1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.jclouds.vcloud.terremark.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.vcloud.terremark.options.AddInternetServiceOptions.Builder.withDescription;
25
26 import java.net.URI;
27 import java.util.Map;
28 import java.util.NoSuchElementException;
29 import java.util.Set;
30 import java.util.Map.Entry;
31
32 import javax.annotation.Nullable;
33 import javax.inject.Inject;
34 import javax.inject.Named;
35 import javax.inject.Provider;
36 import javax.inject.Singleton;
37
38 import org.jclouds.compute.domain.NodeState;
39 import org.jclouds.compute.strategy.PopulateDefaultLoginCredentialsForImageStrategy;
40 import org.jclouds.domain.Credentials;
41 import org.jclouds.vcloud.compute.internal.VCloudExpressComputeClientImpl;
42 import org.jclouds.vcloud.domain.Status;
43 import org.jclouds.vcloud.domain.Task;
44 import org.jclouds.vcloud.domain.TaskStatus;
45 import org.jclouds.vcloud.domain.TasksList;
46 import org.jclouds.vcloud.domain.VCloudExpressVApp;
47 import org.jclouds.vcloud.domain.VCloudExpressVAppTemplate;
48 import org.jclouds.vcloud.options.InstantiateVAppTemplateOptions;
49 import org.jclouds.vcloud.terremark.TerremarkVCloudClient;
50 import org.jclouds.vcloud.terremark.domain.InternetService;
51 import org.jclouds.vcloud.terremark.domain.Node;
52 import org.jclouds.vcloud.terremark.domain.Protocol;
53 import org.jclouds.vcloud.terremark.domain.PublicIpAddress;
54 import org.jclouds.vcloud.terremark.options.TerremarkInstantiateVAppTemplateOptions;
55 import org.jclouds.vcloud.terremark.suppliers.InternetServiceAndPublicIpAddressSupplier;
56
57 import com.google.common.base.Predicate;
58 import com.google.common.collect.ImmutableSet;
59 import com.google.common.collect.Sets;
60
61
62
63
64 @Singleton
65 public class TerremarkVCloudComputeClient extends VCloudExpressComputeClientImpl {
66
67 protected final TerremarkVCloudClient client;
68 protected final PopulateDefaultLoginCredentialsForImageStrategy credentialsProvider;
69 protected final Provider<String> passwordGenerator;
70 protected final Map<String, Credentials> credentialStore;
71 protected final InternetServiceAndPublicIpAddressSupplier internetServiceAndPublicIpAddressSupplier;
72
73 @Inject
74 protected TerremarkVCloudComputeClient(TerremarkVCloudClient client,
75 PopulateDefaultLoginCredentialsForImageStrategy credentialsProvider,
76 @Named("PASSWORD") Provider<String> passwordGenerator, Predicate<URI> successTester,
77 Map<Status, NodeState> vAppStatusToNodeState, Map<String, Credentials> credentialStore,
78 InternetServiceAndPublicIpAddressSupplier internetServiceAndPublicIpAddressSupplier) {
79 super(client, successTester, vAppStatusToNodeState);
80 this.client = client;
81 this.credentialsProvider = credentialsProvider;
82 this.passwordGenerator = passwordGenerator;
83 this.credentialStore = credentialStore;
84 this.internetServiceAndPublicIpAddressSupplier = internetServiceAndPublicIpAddressSupplier;
85 }
86
87 @Override
88 public VCloudExpressVApp start(@Nullable URI VDC, URI templateId, String name,
89 InstantiateVAppTemplateOptions options, int... portsToOpen) {
90 if (options.getDiskSizeKilobytes() != null) {
91 logger.warn("trmk does not support resizing the primary disk; unsetting disk size");
92 }
93
94 if (portsToOpen.length > 0 && !options.shouldBlock())
95 throw new IllegalArgumentException("We cannot open ports on terremark unless we can deploy the vapp");
96 String password = null;
97 VCloudExpressVAppTemplate template = client.getVAppTemplate(templateId);
98 if (template.getDescription().indexOf("Windows") != -1
99 && options instanceof TerremarkInstantiateVAppTemplateOptions) {
100 password = passwordGenerator.get();
101 TerremarkInstantiateVAppTemplateOptions.class.cast(options).getProperties().put("password", password);
102 }
103 Credentials defaultCredentials = credentialsProvider.execute(template);
104
105 VCloudExpressVApp vAppResponse = super.start(VDC, templateId, name, options, portsToOpen);
106 if (password != null) {
107 credentialStore.put("node#" + vAppResponse.getHref().toASCIIString(), new Credentials(
108 defaultCredentials.identity, password));
109 }
110 if (portsToOpen.length > 0)
111 createPublicAddressMappedToPorts(vAppResponse.getHref(), portsToOpen);
112 return vAppResponse;
113 }
114
115 public String createPublicAddressMappedToPorts(URI vAppId, int... ports) {
116 VCloudExpressVApp vApp = client.getVApp(vAppId);
117 PublicIpAddress ip = null;
118 String privateAddress = getLast(vApp.getNetworkToAddresses().values());
119 for (int port : ports) {
120 InternetService is = null;
121 Protocol protocol;
122 switch (port) {
123 case 22:
124 protocol = Protocol.TCP;
125 break;
126 case 80:
127 case 8080:
128 protocol = Protocol.HTTP;
129 break;
130 case 443:
131 protocol = Protocol.HTTPS;
132 break;
133 default:
134 protocol = Protocol.HTTP;
135 break;
136 }
137 if (ip == null) {
138
139 Entry<InternetService, PublicIpAddress> entry = internetServiceAndPublicIpAddressSupplier
140 .getNewInternetServiceAndIp(vApp, port, protocol);
141 is = entry.getKey();
142 ip = entry.getValue();
143
144 } else {
145 logger.debug(">> adding InternetService %s:%s:%d", ip.getAddress(), protocol, port);
146 is = client.addInternetServiceToExistingIp(ip.getId(), vApp.getName() + "-" + port, protocol, port,
147 withDescription(String.format("port %d access to serverId: %s name: %s", port, vApp.getName(),
148 vApp.getName())));
149 }
150 logger.debug("<< created InternetService(%s) %s:%s:%d", is.getName(), is.getPublicIpAddress().getAddress(), is
151 .getProtocol(), is.getPort());
152 logger.debug(">> adding Node %s:%d -> %s:%d", is.getPublicIpAddress().getAddress(), is.getPort(),
153 privateAddress, port);
154 Node node = client.addNode(is.getId(), privateAddress, vApp.getName() + "-" + port, port);
155 logger.debug("<< added Node(%s)", node.getName());
156 }
157 return ip != null ? ip.getAddress() : null;
158 }
159
160 private Set<PublicIpAddress> deleteInternetServicesAndNodesAssociatedWithVApp(VCloudExpressVApp vApp) {
161 checkNotNull(vApp.getVDC(), "VDC reference missing for vApp(%s)", vApp.getName());
162 Set<PublicIpAddress> ipAddresses = Sets.newHashSet();
163 SERVICE: for (InternetService service : client.getAllInternetServicesInVDC(vApp.getVDC().getHref())) {
164 for (Node node : client.getNodes(service.getId())) {
165 if (vApp.getNetworkToAddresses().containsValue(node.getIpAddress())) {
166 ipAddresses.add(service.getPublicIpAddress());
167 logger.debug(">> deleting Node(%s) %s:%d -> %s:%d", node.getName(), service.getPublicIpAddress()
168 .getAddress(), service.getPort(), node.getIpAddress(), node.getPort());
169 client.deleteNode(node.getId());
170 logger.debug("<< deleted Node(%s)", node.getName());
171 Set<Node> nodes = client.getNodes(service.getId());
172 if (nodes.size() == 0) {
173 logger.debug(">> deleting InternetService(%s) %s:%d", service.getName(), service.getPublicIpAddress()
174 .getAddress(), service.getPort());
175 client.deleteInternetService(service.getId());
176 logger.debug("<< deleted InternetService(%s)", service.getName());
177 continue SERVICE;
178 }
179 }
180 }
181 }
182 return ipAddresses;
183 }
184
185 private void deletePublicIpAddressesWithNoServicesAttached(Set<PublicIpAddress> ipAddresses) {
186 IPADDRESS: for (PublicIpAddress address : ipAddresses) {
187 Set<InternetService> services = client.getInternetServicesOnPublicIp(address.getId());
188 if (services.size() == 0) {
189 logger.debug(">> deleting PublicIpAddress(%s) %s", address.getId(), address.getAddress());
190 try {
191 client.deletePublicIp(address.getId());
192 logger.debug("<< deleted PublicIpAddress(%s)", address.getId());
193 } catch (Exception e) {
194 logger.trace("cannot delete PublicIpAddress(%s) as it is unsupported", address.getId());
195 }
196 continue IPADDRESS;
197 }
198 }
199 }
200
201
202
203
204
205
206 @Override
207 public void stop(URI id) {
208 VCloudExpressVApp vApp = client.getVApp(id);
209 Set<PublicIpAddress> ipAddresses = deleteInternetServicesAndNodesAssociatedWithVApp(vApp);
210 deletePublicIpAddressesWithNoServicesAttached(ipAddresses);
211 if (vApp.getStatus() != Status.OFF) {
212 try {
213 powerOffAndWait(vApp);
214 } catch (IllegalStateException e) {
215 logger.warn("<< %s vApp(%s)", e.getMessage(), vApp.getName());
216 blockOnLastTask(vApp);
217 powerOffAndWait(vApp);
218 }
219 vApp = client.getVApp(id);
220 logger.debug("<< %s vApp(%s)", vApp.getStatus(), vApp.getName());
221 }
222 logger.debug(">> deleting vApp(%s)", vApp.getName());
223 client.deleteVApp(id);
224 logger.debug("<< deleted vApp(%s))", vApp.getName());
225 }
226
227 private void powerOffAndWait(VCloudExpressVApp vApp) {
228 logger.debug(">> powering off vApp(%s), current status: %s", vApp.getName(), vApp.getStatus());
229 Task task = client.powerOffVApp(vApp.getHref());
230 if (!taskTester.apply(task.getHref()))
231 throw new RuntimeException(String.format("failed to %s %s: %s", "powerOff", vApp.getName(), task));
232 }
233
234 void blockOnLastTask(VCloudExpressVApp vApp) {
235 TasksList list = client.findTasksListInOrgNamed(null);
236 try {
237 Task lastTask = getLast(filter(list.getTasks(), new Predicate<Task>() {
238
239 @Override
240 public boolean apply(Task input) {
241 return input.getStatus() == TaskStatus.QUEUED || input.getStatus() == TaskStatus.RUNNING;
242 }
243
244 }));
245 if (!taskTester.apply(lastTask.getHref()))
246 throw new RuntimeException(String.format("failed to %s %s: %s", "powerOff", vApp.getName(), lastTask));
247 } catch (NoSuchElementException ex) {
248
249 }
250 }
251
252
253
254
255 @Override
256 public Set<String> getPrivateAddresses(URI id) {
257 VCloudExpressVApp vApp = client.getVApp(id);
258 if (vApp != null)
259 return Sets.newHashSet(vApp.getNetworkToAddresses().values());
260 else
261 return ImmutableSet.<String> of();
262 }
263
264
265
266
267 @Override
268 public Set<String> getPublicAddresses(URI id) {
269 VCloudExpressVApp vApp = client.getVApp(id);
270 if (vApp != null) {
271 Set<String> ipAddresses = Sets.newHashSet();
272 for (InternetService service : client.getAllInternetServicesInVDC(vApp.getVDC().getHref())) {
273 for (Node node : client.getNodes(service.getId())) {
274 if (vApp.getNetworkToAddresses().containsValue(node.getIpAddress())) {
275 ipAddresses.add(service.getPublicIpAddress().getAddress());
276 }
277 }
278 }
279 return ipAddresses;
280 } else {
281 return ImmutableSet.<String> of();
282 }
283 }
284 }