1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.jclouds.trmk.vcloud_0_8.compute;
20
21 import static com.google.common.base.Preconditions.checkNotNull;
22 import static com.google.common.collect.Iterables.filter;
23 import static com.google.common.collect.Iterables.getLast;
24 import static org.jclouds.trmk.vcloud_0_8.options.AddInternetServiceOptions.Builder.withDescription;
25
26 import java.net.URI;
27 import java.util.Map;
28 import java.util.Map.Entry;
29 import java.util.NoSuchElementException;
30 import java.util.Set;
31
32 import org.jclouds.javax.annotation.Nullable;
33 import javax.annotation.Resource;
34 import javax.inject.Inject;
35 import javax.inject.Named;
36 import javax.inject.Provider;
37 import javax.inject.Singleton;
38
39 import org.jclouds.compute.domain.NodeState;
40 import org.jclouds.compute.reference.ComputeServiceConstants;
41 import org.jclouds.compute.strategy.PopulateDefaultLoginCredentialsForImageStrategy;
42 import org.jclouds.domain.Credentials;
43 import org.jclouds.logging.Logger;
44 import org.jclouds.trmk.vcloud_0_8.TerremarkVCloudClient;
45 import org.jclouds.trmk.vcloud_0_8.domain.InternetService;
46 import org.jclouds.trmk.vcloud_0_8.domain.Node;
47 import org.jclouds.trmk.vcloud_0_8.domain.Protocol;
48 import org.jclouds.trmk.vcloud_0_8.domain.PublicIpAddress;
49 import org.jclouds.trmk.vcloud_0_8.domain.Status;
50 import org.jclouds.trmk.vcloud_0_8.domain.Task;
51 import org.jclouds.trmk.vcloud_0_8.domain.TaskStatus;
52 import org.jclouds.trmk.vcloud_0_8.domain.TasksList;
53 import org.jclouds.trmk.vcloud_0_8.domain.VApp;
54 import org.jclouds.trmk.vcloud_0_8.domain.VAppTemplate;
55 import org.jclouds.trmk.vcloud_0_8.options.InstantiateVAppTemplateOptions;
56 import org.jclouds.trmk.vcloud_0_8.suppliers.InternetServiceAndPublicIpAddressSupplier;
57
58 import com.google.common.base.Predicate;
59 import com.google.common.collect.ImmutableSet;
60 import com.google.common.collect.Sets;
61
62
63
64
65 @Singleton
66 public 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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126 public VApp start(@Nullable URI VDC, URI templateId, String name, InstantiateVAppTemplateOptions options,
127 int... portsToOpen) {
128
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
264
265
266
267
268
269
270
271
272
273
274
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
324
325
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
337
338
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
359
360
361
362
363
364
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 }