EMMA Coverage Report (generated Mon Oct 17 05:41:20 EDT 2011)
[all classes][org.jclouds.trmk.vcloud_0_8.compute]

COVERAGE SUMMARY FOR SOURCE FILE [TerremarkVCloudComputeClient.java]

nameclass, %method, %block, %line, %
TerremarkVCloudComputeClient.java50%  (1/2)11%  (2/19)19%  (213/1123)23%  (35.5/156)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class TerremarkVCloudComputeClient$10%   (0/1)0%   (0/2)0%   (0/18)0%   (0/2)
TerremarkVCloudComputeClient$1 (TerremarkVCloudComputeClient): void 0%   (0/1)0%   (0/6)0%   (0/1)
apply (Task): boolean 0%   (0/1)0%   (0/12)0%   (0/1)
     
class TerremarkVCloudComputeClient100% (1/1)12%  (2/17)19%  (213/1105)23%  (35.5/155)
blockOnLastTask (VApp): void 0%   (0/1)0%   (0/46)0%   (0/7)
createPublicAddressMappedToPorts (URI, int []): String 0%   (0/1)0%   (0/220)0%   (0/25)
deleteInternetServicesAndNodesAssociatedWithVApp (VApp): Set 0%   (0/1)0%   (0/157)0%   (0/17)
deletePublicIpAddressesWithNoServicesAttached (Set): void 0%   (0/1)0%   (0/67)0%   (0/12)
deleteVApp (VApp): void 0%   (0/1)0%   (0/47)0%   (0/6)
getPrivateAddresses (URI): Set 0%   (0/1)0%   (0/14)0%   (0/4)
getPublicAddresses (URI): Set 0%   (0/1)0%   (0/56)0%   (0/9)
getStatus (VApp): Status 0%   (0/1)0%   (0/3)0%   (0/1)
powerOff (VApp): Task 0%   (0/1)0%   (0/6)0%   (0/1)
powerOffAndWait (VApp): void 0%   (0/1)0%   (0/50)0%   (0/5)
refreshVApp (URI): VApp 0%   (0/1)0%   (0/5)0%   (0/1)
reset (URI): void 0%   (0/1)0%   (0/58)0%   (0/7)
reset (VApp): Task 0%   (0/1)0%   (0/6)0%   (0/1)
stop (URI): void 0%   (0/1)0%   (0/95)0%   (0/18)
undeploy (VApp): Task 0%   (0/1)0%   (0/6)0%   (0/1)
start (URI, URI, String, InstantiateVAppTemplateOptions, int []): VApp 100% (1/1)77%  (186/242)85%  (25.5/30)
TerremarkVCloudComputeClient (TerremarkVCloudClient, PopulateDefaultLoginCred... 100% (1/1)100% (27/27)100% (10/10)

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.trmk.vcloud_0_8.compute;
20 
21import static com.google.common.base.Preconditions.checkNotNull;
22import static com.google.common.collect.Iterables.filter;
23import static com.google.common.collect.Iterables.getLast;
24import static org.jclouds.trmk.vcloud_0_8.options.AddInternetServiceOptions.Builder.withDescription;
25 
26import java.net.URI;
27import java.util.Map;
28import java.util.Map.Entry;
29import java.util.NoSuchElementException;
30import java.util.Set;
31 
32import org.jclouds.javax.annotation.Nullable;
33import javax.annotation.Resource;
34import javax.inject.Inject;
35import javax.inject.Named;
36import javax.inject.Provider;
37import javax.inject.Singleton;
38 
39import org.jclouds.compute.domain.NodeState;
40import org.jclouds.compute.reference.ComputeServiceConstants;
41import org.jclouds.compute.strategy.PopulateDefaultLoginCredentialsForImageStrategy;
42import org.jclouds.domain.Credentials;
43import org.jclouds.logging.Logger;
44import org.jclouds.trmk.vcloud_0_8.TerremarkVCloudClient;
45import org.jclouds.trmk.vcloud_0_8.domain.InternetService;
46import org.jclouds.trmk.vcloud_0_8.domain.Node;
47import org.jclouds.trmk.vcloud_0_8.domain.Protocol;
48import org.jclouds.trmk.vcloud_0_8.domain.PublicIpAddress;
49import org.jclouds.trmk.vcloud_0_8.domain.Status;
50import org.jclouds.trmk.vcloud_0_8.domain.Task;
51import org.jclouds.trmk.vcloud_0_8.domain.TaskStatus;
52import org.jclouds.trmk.vcloud_0_8.domain.TasksList;
53import org.jclouds.trmk.vcloud_0_8.domain.VApp;
54import org.jclouds.trmk.vcloud_0_8.domain.VAppTemplate;
55import org.jclouds.trmk.vcloud_0_8.options.InstantiateVAppTemplateOptions;
56import org.jclouds.trmk.vcloud_0_8.suppliers.InternetServiceAndPublicIpAddressSupplier;
57 
58import com.google.common.base.Predicate;
59import com.google.common.collect.ImmutableSet;
60import com.google.common.collect.Sets;
61 
62/**
63 * @author Adrian Cole
64 */
65@Singleton
66public class TerremarkVCloudComputeClient {
67   @Resource
68   @Named(ComputeServiceConstants.COMPUTE_LOGGER)
69   protected Logger logger = Logger.NULL;
70 
71   protected final TerremarkVCloudClient client;
72   protected final PopulateDefaultLoginCredentialsForImageStrategy credentialsProvider;
73   protected final Provider<String> passwordGenerator;
74   protected final Map<String, Credentials> credentialStore;
75   protected final InternetServiceAndPublicIpAddressSupplier internetServiceAndPublicIpAddressSupplier;
76   protected final Map<Status, NodeState> vAppStatusToNodeState;
77   protected final Predicate<URI> taskTester;
78 
79   @Inject
80   protected TerremarkVCloudComputeClient(TerremarkVCloudClient client,
81         PopulateDefaultLoginCredentialsForImageStrategy credentialsProvider,
82         @Named("PASSWORD") Provider<String> passwordGenerator, Predicate<URI> successTester,
83         Map<Status, NodeState> vAppStatusToNodeState, Map<String, Credentials> credentialStore,
84         InternetServiceAndPublicIpAddressSupplier internetServiceAndPublicIpAddressSupplier) {
85      this.client = client;
86      this.credentialsProvider = credentialsProvider;
87      this.passwordGenerator = passwordGenerator;
88      this.credentialStore = credentialStore;
89      this.internetServiceAndPublicIpAddressSupplier = internetServiceAndPublicIpAddressSupplier;
90      this.vAppStatusToNodeState = vAppStatusToNodeState;
91      this.taskTester = successTester;
92   }
93 
94   protected Status getStatus(VApp vApp) {
95      return vApp.getStatus();
96   }
97 
98   /**
99    * Runs through all commands necessary to startup a vApp, opening at least
100    * one ip address to the public network. These are the steps:
101    * <p/>
102    * instantiate -> deploy -> powerOn
103    * <p/>
104    * This command blocks until the vApp is in state {@code VAppStatus#ON}
105    * 
106    * @param VDC
107    *           id of the virtual datacenter {@code VCloudClient#getDefaultVDC}
108    * @param templateId
109    *           id of the vAppTemplate you wish to instantiate
110    * @param name
111    *           name of the vApp
112    * @param cores
113    *           amount of virtual cpu cores
114    * @param megs
115    *           amount of ram in megabytes
116    * @param options
117    *           options for instantiating the vApp; null is ok
118    * @param portsToOpen
119    *           opens the following ports on the public ip address
120    * @return map contains at least the following properties
121    *         <ol>
122    *         <li>id - vApp id</li> <li>username - console login user</li> <li>
123    *         password - console login password</li>
124    *         </ol>
125    */
126   public VApp start(@Nullable URI VDC, URI templateId, String name, InstantiateVAppTemplateOptions options,
127         int... portsToOpen) {
128      // we only get IP addresses after "deploy"
129      if (portsToOpen.length > 0 && !options.shouldBlock())
130         throw new IllegalArgumentException("We cannot open ports on terremark unless we can deploy the vapp");
131      String password = null;
132      VAppTemplate template = client.getVAppTemplate(templateId);
133      if (template.getDescription().indexOf("Windows") != -1) {
134         password = passwordGenerator.get();
135         options.getProperties().put("password", password);
136      }
137      Credentials defaultCredentials = credentialsProvider.execute(template);
138      checkNotNull(options, "options");
139      logger.debug(">> instantiating vApp vDC(%s) template(%s) name(%s) options(%s) ", VDC, templateId, name, options);
140 
141      VApp vAppResponse = client.instantiateVAppTemplateInVDC(VDC, templateId, name, options);
142      logger.debug("<< instantiated VApp(%s)", vAppResponse.getName());
143      if (options.shouldDeploy()) {
144         logger.debug(">> deploying vApp(%s)", vAppResponse.getName());
145 
146         Task task = client.deployVApp(vAppResponse.getHref());
147         if (options.shouldBlock()) {
148            if (!taskTester.apply(task.getHref())) {
149               throw new RuntimeException(String.format("failed to %s %s: %s", "deploy", vAppResponse.getName(), task));
150            }
151            logger.debug("<< deployed vApp(%s)", vAppResponse.getName());
152            if (options.shouldPowerOn()) {
153               logger.debug(">> powering vApp(%s)", vAppResponse.getName());
154               task = client.powerOnVApp(vAppResponse.getHref());
155               if (!taskTester.apply(task.getHref())) {
156                  throw new RuntimeException(String.format("failed to %s %s: %s", "powerOn", vAppResponse.getName(),
157                        task));
158               }
159               logger.debug("<< on vApp(%s)", vAppResponse.getName());
160            }
161         }
162      }
163      if (password != null) {
164         credentialStore.put("node#" + vAppResponse.getHref().toASCIIString(), new Credentials(
165               defaultCredentials.identity, password));
166      }
167      if (portsToOpen.length > 0)
168         createPublicAddressMappedToPorts(vAppResponse.getHref(), portsToOpen);
169      return vAppResponse;
170   }
171 
172   public String createPublicAddressMappedToPorts(URI vAppId, int... ports) {
173      VApp vApp = client.getVApp(vAppId);
174      PublicIpAddress ip = null;
175      String privateAddress = getLast(vApp.getNetworkToAddresses().values());
176      for (int port : ports) {
177         InternetService is = null;
178         Protocol protocol;
179         switch (port) {
180         case 22:
181            protocol = Protocol.TCP;
182            break;
183         case 80:
184         case 8080:
185            protocol = Protocol.HTTP;
186            break;
187         case 443:
188            protocol = Protocol.HTTPS;
189            break;
190         default:
191            protocol = Protocol.HTTP;
192            break;
193         }
194         if (ip == null) {
195 
196            Entry<InternetService, PublicIpAddress> entry = internetServiceAndPublicIpAddressSupplier
197                  .getNewInternetServiceAndIp(vApp, port, protocol);
198            is = entry.getKey();
199            ip = entry.getValue();
200 
201         } else {
202            logger.debug(">> adding InternetService %s:%s:%d", ip.getAddress(), protocol, port);
203            is = client.addInternetServiceToExistingIp(
204                  ip.getId(),
205                  vApp.getName() + "-" + port,
206                  protocol,
207                  port,
208                  withDescription(String.format("port %d access to serverId: %s name: %s", port, vApp.getName(),
209                        vApp.getName())));
210         }
211         logger.debug("<< created InternetService(%s) %s:%s:%d", is.getName(), is.getPublicIpAddress().getAddress(),
212               is.getProtocol(), is.getPort());
213         logger.debug(">> adding Node %s:%d -> %s:%d", is.getPublicIpAddress().getAddress(), is.getPort(),
214               privateAddress, port);
215         Node node = client.addNode(is.getId(), privateAddress, vApp.getName() + "-" + port, port);
216         logger.debug("<< added Node(%s)", node.getName());
217      }
218      return ip != null ? ip.getAddress() : null;
219   }
220 
221   private Set<PublicIpAddress> deleteInternetServicesAndNodesAssociatedWithVApp(VApp vApp) {
222      checkNotNull(vApp.getVDC(), "VDC reference missing for vApp(%s)", vApp.getName());
223      Set<PublicIpAddress> ipAddresses = Sets.newHashSet();
224      SERVICE: for (InternetService service : client.getAllInternetServicesInVDC(vApp.getVDC().getHref())) {
225         for (Node node : client.getNodes(service.getId())) {
226            if (vApp.getNetworkToAddresses().containsValue(node.getIpAddress())) {
227               ipAddresses.add(service.getPublicIpAddress());
228               logger.debug(">> deleting Node(%s) %s:%d -> %s:%d", node.getName(), service.getPublicIpAddress()
229                     .getAddress(), service.getPort(), node.getIpAddress(), node.getPort());
230               client.deleteNode(node.getId());
231               logger.debug("<< deleted Node(%s)", node.getName());
232               Set<Node> nodes = client.getNodes(service.getId());
233               if (nodes.size() == 0) {
234                  logger.debug(">> deleting InternetService(%s) %s:%d", service.getName(), service.getPublicIpAddress()
235                        .getAddress(), service.getPort());
236                  client.deleteInternetService(service.getId());
237                  logger.debug("<< deleted InternetService(%s)", service.getName());
238                  continue SERVICE;
239               }
240            }
241         }
242      }
243      return ipAddresses;
244   }
245 
246   private void deletePublicIpAddressesWithNoServicesAttached(Set<PublicIpAddress> ipAddresses) {
247      IPADDRESS: for (PublicIpAddress address : ipAddresses) {
248         Set<InternetService> services = client.getInternetServicesOnPublicIp(address.getId());
249         if (services.size() == 0) {
250            logger.debug(">> deleting PublicIpAddress(%s) %s", address.getId(), address.getAddress());
251            try {
252               client.deletePublicIp(address.getId());
253               logger.debug("<< deleted PublicIpAddress(%s)", address.getId());
254            } catch (Exception e) {
255               logger.trace("cannot delete PublicIpAddress(%s) as it is unsupported", address.getId());
256            }
257            continue IPADDRESS;
258         }
259      }
260   }
261 
262   /**
263    * Destroys dependent resources, powers off and deletes the vApp, blocking
264    * until the following state transition is complete:
265    * <p/>
266    * current -> {@code VAppStatus#OFF} -> deleted
267    * <p/>
268    * * deletes the internet service and nodes associated with the vapp. Deletes
269    * the IP address, if there are no others using it. Finally, it powers off
270    * and deletes the vapp. Note that we do not call undeploy, as terremark does
271    * not support the command.
272    * 
273    * @param vAppId
274    *           vApp to stop
275    */
276   public void stop(URI id) {
277      VApp vApp = client.getVApp(id);
278      if (vApp == null)
279         return;
280      Set<PublicIpAddress> ipAddresses = deleteInternetServicesAndNodesAssociatedWithVApp(vApp);
281      deletePublicIpAddressesWithNoServicesAttached(ipAddresses);
282      if (vApp.getStatus() != Status.OFF) {
283         try {
284            powerOffAndWait(vApp);
285         } catch (IllegalStateException e) {
286            logger.warn("<< %s vApp(%s)", e.getMessage(), vApp.getName());
287            blockOnLastTask(vApp);
288            powerOffAndWait(vApp);
289         }
290         vApp = client.getVApp(id);
291         logger.debug("<< %s vApp(%s)", vApp.getStatus(), vApp.getName());
292      }
293      logger.debug(">> deleting vApp(%s)", vApp.getName());
294      client.deleteVApp(id);
295      logger.debug("<< deleted vApp(%s))", vApp.getName());
296   }
297 
298   private void powerOffAndWait(VApp vApp) {
299      logger.debug(">> powering off vApp(%s), current status: %s", vApp.getName(), vApp.getStatus());
300      Task task = client.powerOffVApp(vApp.getHref());
301      if (!taskTester.apply(task.getHref()))
302         throw new RuntimeException(String.format("failed to %s %s: %s", "powerOff", vApp.getName(), task));
303   }
304 
305   void blockOnLastTask(VApp vApp) {
306      TasksList list = client.findTasksListInOrgNamed(null, null);
307      try {
308         Task lastTask = getLast(filter(list.getTasks(), new Predicate<Task>() {
309 
310            public boolean apply(Task input) {
311               return input.getStatus() == TaskStatus.QUEUED || input.getStatus() == TaskStatus.RUNNING;
312            }
313 
314         }));
315         if (!taskTester.apply(lastTask.getHref()))
316            throw new RuntimeException(String.format("failed to %s %s: %s", "powerOff", vApp.getName(), lastTask));
317      } catch (NoSuchElementException ex) {
318 
319      }
320   }
321 
322   /**
323    * returns a set of addresses that are only visible to the private network.
324    * 
325    * @returns empty set if the node is not found
326    */
327   public Set<String> getPrivateAddresses(URI id) {
328      VApp vApp = client.getVApp(id);
329      if (vApp != null)
330         return Sets.newHashSet(vApp.getNetworkToAddresses().values());
331      else
332         return ImmutableSet.<String> of();
333   }
334 
335   /**
336    * returns a set of addresses that are publically visible
337    * 
338    * @returns empty set if the node is not found
339    */
340   public Set<String> getPublicAddresses(URI id) {
341      VApp vApp = client.getVApp(id);
342      if (vApp != null) {
343         Set<String> ipAddresses = Sets.newHashSet();
344         for (InternetService service : client.getAllInternetServicesInVDC(vApp.getVDC().getHref())) {
345            for (Node node : client.getNodes(service.getId())) {
346               if (vApp.getNetworkToAddresses().containsValue(node.getIpAddress())) {
347                  ipAddresses.add(service.getPublicIpAddress().getAddress());
348               }
349            }
350         }
351         return ipAddresses;
352      } else {
353         return ImmutableSet.<String> of();
354      }
355   }
356 
357   /**
358    * reboots the vApp, blocking until the following state transition is
359    * complete:
360    * <p/>
361    * current -> {@code VAppStatus#OFF} -> {@code VAppStatus#ON}
362    * 
363    * @param vAppId
364    *           vApp to reboot
365    */
366   public void reset(URI id) {
367      VApp vApp = refreshVApp(id);
368      logger.debug(">> resetting vApp(%s)", vApp.getName());
369      Task task = reset(vApp);
370      if (!taskTester.apply(task.getHref())) {
371         throw new RuntimeException(String.format("failed to %s %s: %s", "resetVApp", vApp.getName(), task));
372      }
373      logger.debug("<< on vApp(%s)", vApp.getName());
374   }
375 
376   protected void deleteVApp(VApp vApp) {
377      logger.debug(">> deleting vApp(%s)", vApp.getName());
378      Task task = client.deleteVApp(vApp.getHref());
379      if (task != null)
380         if (!taskTester.apply(task.getHref()))
381            throw new RuntimeException(String.format("failed to %s %s: %s", "delete", vApp.getName(), task));
382   }
383 
384   protected VApp refreshVApp(URI id) {
385      return client.getVApp(id);
386   }
387 
388   protected Task powerOff(VApp vApp) {
389      return client.powerOffVApp(vApp.getHref());
390   }
391 
392   protected Task reset(VApp vApp) {
393      return client.resetVApp(vApp.getHref());
394   }
395 
396   protected Task undeploy(VApp vApp) {
397      return client.undeployVApp(vApp.getHref());
398   }
399}

[all classes][org.jclouds.trmk.vcloud_0_8.compute]
EMMA 2.0.5312 (C) Vladimir Roubtsov