1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.jclouds.compute.internal;
20
21 import static com.google.common.base.Preconditions.checkNotNull;
22 import static com.google.common.base.Predicates.and;
23 import static com.google.common.base.Predicates.not;
24 import static com.google.common.base.Predicates.notNull;
25 import static com.google.common.collect.Iterables.filter;
26 import static com.google.common.collect.Maps.newLinkedHashMap;
27 import static com.google.common.collect.Sets.filter;
28 import static com.google.common.collect.Sets.newLinkedHashSet;
29 import static com.google.common.util.concurrent.Futures.immediateFuture;
30 import static org.jclouds.compute.predicates.NodePredicates.TERMINATED;
31 import static org.jclouds.compute.predicates.NodePredicates.all;
32 import static org.jclouds.concurrent.FutureIterables.awaitCompletion;
33 import static org.jclouds.concurrent.FutureIterables.transformParallel;
34
35 import java.io.IOException;
36 import java.util.Map;
37 import java.util.NoSuchElementException;
38 import java.util.Set;
39 import java.util.concurrent.Callable;
40 import java.util.concurrent.ExecutorService;
41 import java.util.concurrent.Future;
42 import java.util.concurrent.TimeUnit;
43 import java.util.concurrent.atomic.AtomicReference;
44
45 import javax.annotation.Resource;
46 import javax.inject.Inject;
47 import javax.inject.Named;
48 import javax.inject.Provider;
49 import javax.inject.Singleton;
50
51 import org.jclouds.Constants;
52 import org.jclouds.collect.Memoized;
53 import org.jclouds.compute.ComputeService;
54 import org.jclouds.compute.ComputeServiceContext;
55 import org.jclouds.compute.RunNodesException;
56 import org.jclouds.compute.RunScriptOnNodesException;
57 import org.jclouds.compute.callables.RunScriptOnNode;
58 import org.jclouds.compute.config.CustomizationResponse;
59 import org.jclouds.compute.domain.ComputeMetadata;
60 import org.jclouds.compute.domain.ExecResponse;
61 import org.jclouds.compute.domain.Hardware;
62 import org.jclouds.compute.domain.Image;
63 import org.jclouds.compute.domain.NodeMetadata;
64 import org.jclouds.compute.domain.NodeMetadataBuilder;
65 import org.jclouds.compute.domain.NodeState;
66 import org.jclouds.compute.domain.Template;
67 import org.jclouds.compute.domain.TemplateBuilder;
68 import org.jclouds.compute.options.RunScriptOptions;
69 import org.jclouds.compute.options.TemplateOptions;
70 import org.jclouds.compute.reference.ComputeServiceConstants;
71 import org.jclouds.compute.reference.ComputeServiceConstants.Timeouts;
72 import org.jclouds.compute.strategy.CreateNodesInGroupThenAddToSet;
73 import org.jclouds.compute.strategy.DestroyNodeStrategy;
74 import org.jclouds.compute.strategy.GetNodeMetadataStrategy;
75 import org.jclouds.compute.strategy.InitializeRunScriptOnNodeOrPlaceInBadMap;
76 import org.jclouds.compute.strategy.ListNodesStrategy;
77 import org.jclouds.compute.strategy.RebootNodeStrategy;
78 import org.jclouds.compute.strategy.ResumeNodeStrategy;
79 import org.jclouds.compute.strategy.RunScriptOnNodeAndAddToGoodMapOrPutExceptionIntoBadMap;
80 import org.jclouds.compute.strategy.SuspendNodeStrategy;
81 import org.jclouds.domain.Credentials;
82 import org.jclouds.domain.Location;
83 import org.jclouds.domain.Credentials.Builder;
84 import org.jclouds.io.Payload;
85 import org.jclouds.logging.Logger;
86 import org.jclouds.predicates.RetryablePredicate;
87 import org.jclouds.scriptbuilder.domain.Statement;
88 import org.jclouds.scriptbuilder.domain.Statements;
89 import org.jclouds.scriptbuilder.functions.InitAdminAccess;
90 import org.jclouds.util.Maps2;
91 import org.jclouds.util.Strings2;
92
93 import com.google.common.base.Function;
94 import com.google.common.base.Predicate;
95 import com.google.common.base.Supplier;
96 import com.google.common.base.Throwables;
97 import com.google.common.collect.ImmutableMap;
98 import com.google.common.collect.ImmutableSet;
99 import com.google.common.collect.Iterables;
100 import com.google.common.collect.LinkedHashMultimap;
101 import com.google.common.collect.Multimap;
102 import com.google.common.util.concurrent.ListenableFuture;
103
104
105
106
107
108 @Singleton
109 public class BaseComputeService implements ComputeService {
110
111 @Resource
112 @Named(ComputeServiceConstants.COMPUTE_LOGGER)
113 protected Logger logger = Logger.NULL;
114
115 protected final ComputeServiceContext context;
116 protected final Map<String, Credentials> credentialStore;
117
118 private final Supplier<Set<? extends Image>> images;
119 private final Supplier<Set<? extends Hardware>> hardwareProfiles;
120 private final Supplier<Set<? extends Location>> locations;
121 private final ListNodesStrategy listNodesStrategy;
122 private final GetNodeMetadataStrategy getNodeMetadataStrategy;
123 private final CreateNodesInGroupThenAddToSet runNodesAndAddToSetStrategy;
124 private final RebootNodeStrategy rebootNodeStrategy;
125 private final DestroyNodeStrategy destroyNodeStrategy;
126 private final ResumeNodeStrategy resumeNodeStrategy;
127 private final SuspendNodeStrategy suspendNodeStrategy;
128 private final Provider<TemplateBuilder> templateBuilderProvider;
129 private final Provider<TemplateOptions> templateOptionsProvider;
130 private final Predicate<NodeMetadata> nodeRunning;
131 private final Predicate<NodeMetadata> nodeTerminated;
132 private final Predicate<NodeMetadata> nodeSuspended;
133 private final InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory;
134 private final Timeouts timeouts;
135 private final InitAdminAccess initAdminAccess;
136 private final PersistNodeCredentials persistNodeCredentials;
137 private final RunScriptOnNode.Factory runScriptOnNodeFactory;
138 private final ExecutorService executor;
139
140 @Inject
141 protected BaseComputeService(ComputeServiceContext context, Map<String, Credentials> credentialStore,
142 @Memoized Supplier<Set<? extends Image>> images,
143 @Memoized Supplier<Set<? extends Hardware>> hardwareProfiles,
144 @Memoized Supplier<Set<? extends Location>> locations, ListNodesStrategy listNodesStrategy,
145 GetNodeMetadataStrategy getNodeMetadataStrategy,
146 CreateNodesInGroupThenAddToSet runNodesAndAddToSetStrategy, RebootNodeStrategy rebootNodeStrategy,
147 DestroyNodeStrategy destroyNodeStrategy, ResumeNodeStrategy resumeNodeStrategy,
148 SuspendNodeStrategy suspendNodeStrategy, Provider<TemplateBuilder> templateBuilderProvider,
149 Provider<TemplateOptions> templateOptionsProvider,
150 @Named("NODE_RUNNING") Predicate<NodeMetadata> nodeRunning,
151 @Named("NODE_TERMINATED") Predicate<NodeMetadata> nodeTerminated,
152 @Named("NODE_SUSPENDED") Predicate<NodeMetadata> nodeSuspended,
153 InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory, InitAdminAccess initAdminAccess,
154 RunScriptOnNode.Factory runScriptOnNodeFactory, PersistNodeCredentials persistNodeCredentials,
155 Timeouts timeouts, @Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor) {
156 this.context = checkNotNull(context, "context");
157 this.credentialStore = checkNotNull(credentialStore, "credentialStore");
158 this.images = checkNotNull(images, "images");
159 this.hardwareProfiles = checkNotNull(hardwareProfiles, "hardwareProfiles");
160 this.locations = checkNotNull(locations, "locations");
161 this.listNodesStrategy = checkNotNull(listNodesStrategy, "listNodesStrategy");
162 this.getNodeMetadataStrategy = checkNotNull(getNodeMetadataStrategy, "getNodeMetadataStrategy");
163 this.runNodesAndAddToSetStrategy = checkNotNull(runNodesAndAddToSetStrategy, "runNodesAndAddToSetStrategy");
164 this.rebootNodeStrategy = checkNotNull(rebootNodeStrategy, "rebootNodeStrategy");
165 this.resumeNodeStrategy = checkNotNull(resumeNodeStrategy, "resumeNodeStrategy");
166 this.suspendNodeStrategy = checkNotNull(suspendNodeStrategy, "suspendNodeStrategy");
167 this.destroyNodeStrategy = checkNotNull(destroyNodeStrategy, "destroyNodeStrategy");
168 this.templateBuilderProvider = checkNotNull(templateBuilderProvider, "templateBuilderProvider");
169 this.templateOptionsProvider = checkNotNull(templateOptionsProvider, "templateOptionsProvider");
170 this.nodeRunning = checkNotNull(nodeRunning, "nodeRunning");
171 this.nodeTerminated = checkNotNull(nodeTerminated, "nodeTerminated");
172 this.nodeSuspended = checkNotNull(nodeSuspended, "nodeSuspended");
173 this.initScriptRunnerFactory = checkNotNull(initScriptRunnerFactory, "initScriptRunnerFactory");
174 this.timeouts = checkNotNull(timeouts, "timeouts");
175 this.initAdminAccess = checkNotNull(initAdminAccess, "initAdminAccess");
176 this.runScriptOnNodeFactory = checkNotNull(runScriptOnNodeFactory, "runScriptOnNodeFactory");
177 this.persistNodeCredentials = checkNotNull(persistNodeCredentials, "persistNodeCredentials");
178 this.executor = checkNotNull(executor, "executor");
179 }
180
181
182
183
184 @Override
185 public ComputeServiceContext getContext() {
186 return context;
187 }
188
189
190
191
192 @Override
193 public Set<? extends NodeMetadata> runNodesWithTag(String group, int count, Template template)
194 throws RunNodesException {
195 return createNodesInGroup(group, count, template);
196 }
197
198
199
200
201 @Override
202 public Set<? extends NodeMetadata> runNodesWithTag(String group, int count, TemplateOptions templateOptions)
203 throws RunNodesException {
204 return createNodesInGroup(group, count, templateBuilder().any().options(templateOptions).build());
205 }
206
207
208
209
210 @Override
211 public Set<? extends NodeMetadata> runNodesWithTag(String group, int count) throws RunNodesException {
212 return createNodesInGroup(group, count, templateOptions());
213 }
214
215 @Override
216 public Set<? extends NodeMetadata> createNodesInGroup(String group, int count, Template template)
217 throws RunNodesException {
218 checkNotNull(group, "group cannot be null");
219 checkNotNull(template.getLocation(), "location");
220 logger.debug(">> running %d node%s group(%s) location(%s) image(%s) hardwareProfile(%s) options(%s)", count,
221 count > 1 ? "s" : "", group, template.getLocation().getId(), template.getImage().getId(), template
222 .getHardware().getId(), template.getOptions());
223 Set<NodeMetadata> goodNodes = newLinkedHashSet();
224 Map<NodeMetadata, Exception> badNodes = newLinkedHashMap();
225 Multimap<NodeMetadata, CustomizationResponse> customizationResponses = LinkedHashMultimap.create();
226
227 if (template.getOptions().getRunScript() != null)
228 initAdminAccess.visit(template.getOptions().getRunScript());
229
230 Map<?, Future<Void>> responses = runNodesAndAddToSetStrategy.execute(group, count, template, goodNodes, badNodes,
231 customizationResponses);
232 Map<?, Exception> executionExceptions = awaitCompletion(responses, executor, null, logger, "runNodesWithTag("
233 + group + ")");
234 Function<NodeMetadata, NodeMetadata> fn = persistNodeCredentials.always(template.getOptions().getRunScript());
235 badNodes = Maps2.transformKeys(badNodes, fn);
236 goodNodes = ImmutableSet.copyOf(Iterables.transform(goodNodes, fn));
237 if (executionExceptions.size() > 0 || badNodes.size() > 0) {
238 throw new RunNodesException(group, count, template, goodNodes, executionExceptions, badNodes);
239 }
240 return goodNodes;
241 }
242
243 @Override
244 public Set<? extends NodeMetadata> createNodesInGroup(String group, int count, TemplateOptions templateOptions)
245 throws RunNodesException {
246 return createNodesInGroup(group, count, templateBuilder().any().options(templateOptions).build());
247 }
248
249 @Override
250 public Set<? extends NodeMetadata> createNodesInGroup(String group, int count) throws RunNodesException {
251 return createNodesInGroup(group, count, templateOptions());
252 }
253
254
255
256
257 @Override
258 public void destroyNode(final String id) {
259 checkNotNull(id, "id");
260 logger.debug(">> destroying node(%s)", id);
261 final AtomicReference<NodeMetadata> node = new AtomicReference<NodeMetadata>();
262 RetryablePredicate<String> tester = new RetryablePredicate<String>(new Predicate<String>() {
263
264 @Override
265 public boolean apply(String input) {
266 try {
267 NodeMetadata md = destroyNodeStrategy.destroyNode(id);
268 if (md != null)
269 node.set(md);
270 return true;
271 } catch (IllegalStateException e) {
272 logger.warn("<< illegal state destroying node(%s)", id);
273 return false;
274 }
275 }
276
277 }, timeouts.nodeRunning, 1000, TimeUnit.MILLISECONDS);
278 boolean successful = tester.apply(id) && (node.get() == null || nodeTerminated.apply(node.get()));
279 if (successful)
280 credentialStore.remove("node#" + id);
281 logger.debug("<< destroyed node(%s) success(%s)", id, successful);
282 }
283
284
285
286
287 @Override
288 public Set<? extends NodeMetadata> destroyNodesMatching(Predicate<NodeMetadata> filter) {
289 logger.debug(">> destroying nodes matching(%s)", filter);
290 Set<NodeMetadata> set = newLinkedHashSet(transformParallel(nodesMatchingFilterAndNotTerminated(filter),
291 new Function<NodeMetadata, Future<NodeMetadata>>() {
292
293
294 @Override
295 public Future<NodeMetadata> apply(final NodeMetadata from) {
296 return executor.submit(new Callable<NodeMetadata>() {
297
298 @Override
299 public NodeMetadata call() throws Exception {
300 destroyNode(from.getId());
301 return from;
302 }
303
304 @Override
305 public String toString() {
306 return "destroyNode(" + from.getId() + ")";
307 }
308 });
309 }
310
311 }, executor, null, logger, "destroyNodesMatching(" + filter + ")"));
312 logger.debug("<< destroyed(%d)", set.size());
313 return set;
314 }
315
316 Iterable<? extends NodeMetadata> nodesMatchingFilterAndNotTerminated(Predicate<NodeMetadata> filter) {
317 return filter(detailsOnAllNodes(), and(checkNotNull(filter, "filter"), not(TERMINATED)));
318 }
319
320
321
322
323
324 Iterable<? extends NodeMetadata> nodesMatchingFilterAndNotTerminatedExceptionIfNotFound(
325 Predicate<NodeMetadata> filter) {
326 Iterable<? extends NodeMetadata> nodes = nodesMatchingFilterAndNotTerminated(filter);
327 if (Iterables.size(nodes) == 0)
328 throw new NoSuchElementException("no nodes matched filter: " + filter);
329 return nodes;
330 }
331
332
333
334
335 @Override
336 public Set<ComputeMetadata> listNodes() {
337 logger.debug(">> listing nodes");
338 Set<ComputeMetadata> set = newLinkedHashSet(listNodesStrategy.listNodes());
339 logger.debug("<< list(%d)", set.size());
340 return set;
341 }
342
343
344
345
346 @Override
347 public Set<? extends NodeMetadata> listNodesDetailsMatching(Predicate<ComputeMetadata> filter) {
348 checkNotNull(filter, "filter");
349 logger.debug(">> listing node details matching(%s)", filter);
350 Set<NodeMetadata> set = newLinkedHashSet(listNodesStrategy.listDetailsOnNodesMatching(filter));
351 logger.debug("<< list(%d)", set.size());
352 return set;
353 }
354
355
356
357
358 @Override
359 public Set<? extends Hardware> listHardwareProfiles() {
360 return hardwareProfiles.get();
361 }
362
363
364
365
366 @Override
367 public Set<? extends Image> listImages() {
368 return images.get();
369 }
370
371
372
373
374 @Override
375 public Set<? extends Location> listAssignableLocations() {
376 return locations.get();
377 }
378
379
380
381
382 @Override
383 public TemplateBuilder templateBuilder() {
384 return templateBuilderProvider.get();
385 }
386
387
388
389
390 @Override
391 public NodeMetadata getNodeMetadata(String id) {
392 checkNotNull(id, "id");
393 return getNodeMetadataStrategy.getNode(id);
394 }
395
396
397
398
399 @Override
400 public void rebootNode(String id) {
401 checkNotNull(id, "id");
402 logger.debug(">> rebooting node(%s)", id);
403 NodeMetadata node = rebootNodeStrategy.rebootNode(id);
404 boolean successful = nodeRunning.apply(node);
405 logger.debug("<< rebooted node(%s) success(%s)", id, successful);
406 }
407
408
409
410
411 @Override
412 public void rebootNodesMatching(Predicate<NodeMetadata> filter) {
413 logger.debug(">> rebooting nodes matching(%s)", filter);
414 transformParallel(nodesMatchingFilterAndNotTerminatedExceptionIfNotFound(filter),
415 new Function<NodeMetadata, Future<Void>>() {
416
417 @Override
418 public Future<Void> apply(NodeMetadata from) {
419 rebootNode(from.getId());
420 return immediateFuture(null);
421 }
422
423 }, executor, null, logger, "rebootNodesMatching(" + filter + ")");
424 logger.debug("<< rebooted");
425 }
426
427
428
429
430 @Override
431 public void resumeNode(String id) {
432 checkNotNull(id, "id");
433 logger.debug(">> resuming node(%s)", id);
434 NodeMetadata node = resumeNodeStrategy.resumeNode(id);
435 boolean successful = nodeRunning.apply(node);
436 logger.debug("<< resumed node(%s) success(%s)", id, successful);
437 }
438
439
440
441
442 @Override
443 public void resumeNodesMatching(Predicate<NodeMetadata> filter) {
444 logger.debug(">> resuming nodes matching(%s)", filter);
445 transformParallel(nodesMatchingFilterAndNotTerminatedExceptionIfNotFound(filter),
446 new Function<NodeMetadata, Future<Void>>() {
447
448 @Override
449 public Future<Void> apply(NodeMetadata from) {
450 resumeNode(from.getId());
451 return immediateFuture(null);
452 }
453
454 }, executor, null, logger, "resumeNodesMatching(" + filter + ")");
455 logger.debug("<< resumed");
456 }
457
458
459
460
461 @Override
462 public void suspendNode(String id) {
463 checkNotNull(id, "id");
464 logger.debug(">> suspending node(%s)", id);
465 NodeMetadata node = suspendNodeStrategy.suspendNode(id);
466 boolean successful = nodeSuspended.apply(node);
467 logger.debug("<< suspended node(%s) success(%s)", id, successful);
468 }
469
470
471
472
473 @Override
474 public void suspendNodesMatching(Predicate<NodeMetadata> filter) {
475 logger.debug(">> suspending nodes matching(%s)", filter);
476 transformParallel(nodesMatchingFilterAndNotTerminatedExceptionIfNotFound(filter),
477 new Function<NodeMetadata, Future<Void>>() {
478
479 @Override
480 public Future<Void> apply(NodeMetadata from) {
481 suspendNode(from.getId());
482 return immediateFuture(null);
483 }
484
485 }, executor, null, logger, "suspendNodesMatching(" + filter + ")");
486 logger.debug("<< suspended");
487 }
488
489
490
491
492 @Override
493 public Map<NodeMetadata, ExecResponse> runScriptOnNodesMatching(Predicate<NodeMetadata> filter, Payload runScript)
494 throws RunScriptOnNodesException {
495 return runScriptOnNodesMatching(filter, runScript, RunScriptOptions.NONE);
496 }
497
498
499
500
501 @Override
502 public Map<NodeMetadata, ExecResponse> runScriptOnNodesMatching(Predicate<NodeMetadata> filter, Payload runScript,
503 RunScriptOptions options) throws RunScriptOnNodesException {
504 try {
505 return runScriptOnNodesMatching(filter, Statements.exec(Strings2.toStringAndClose(checkNotNull(runScript,
506 "runScript").getInput())), options);
507 } catch (IOException e) {
508 Throwables.propagate(e);
509 return null;
510 }
511 }
512
513
514
515
516 @Override
517 public Map<NodeMetadata, ExecResponse> runScriptOnNodesMatching(Predicate<NodeMetadata> filter, String runScript)
518 throws RunScriptOnNodesException {
519 return runScriptOnNodesMatching(filter, Statements.exec(checkNotNull(runScript, "runScript")));
520 }
521
522
523
524
525 @Override
526 public Map<NodeMetadata, ExecResponse> runScriptOnNodesMatching(Predicate<NodeMetadata> filter, Statement runScript)
527 throws RunScriptOnNodesException {
528 return runScriptOnNodesMatching(filter, runScript, RunScriptOptions.NONE);
529 }
530
531 @Override
532 public Map<? extends NodeMetadata, ExecResponse> runScriptOnNodesMatching(Predicate<NodeMetadata> filter,
533 String runScript, RunScriptOptions options) throws RunScriptOnNodesException {
534 return runScriptOnNodesMatching(filter, Statements.exec(checkNotNull(runScript, "runScript")), options);
535 }
536
537
538
539
540 @Override
541 public Map<NodeMetadata, ExecResponse> runScriptOnNodesMatching(Predicate<NodeMetadata> filter, Statement runScript,
542 RunScriptOptions options) throws RunScriptOnNodesException {
543
544 checkNotNull(filter, "filter");
545 checkNotNull(runScript, "runScript");
546 checkNotNull(options, "options");
547
548 Map<NodeMetadata, ExecResponse> goodNodes = newLinkedHashMap();
549 Map<NodeMetadata, Exception> badNodes = newLinkedHashMap();
550 Map<NodeMetadata, Future<ExecResponse>> responses = newLinkedHashMap();
551 Map<?, Exception> exceptions = ImmutableMap.<Object, Exception> of();
552
553 initAdminAccess.visit(runScript);
554
555 Iterable<? extends RunScriptOnNode> scriptRunners = transformNodesIntoInitializedScriptRunners(
556 nodesMatchingFilterAndNotTerminatedExceptionIfNotFound(filter), runScript, options, badNodes);
557 if (Iterables.size(scriptRunners) > 0) {
558 for (RunScriptOnNode runner : scriptRunners) {
559 responses.put(runner.getNode(), executor.submit(new RunScriptOnNodeAndAddToGoodMapOrPutExceptionIntoBadMap(
560 runner, goodNodes, badNodes)));
561 }
562 exceptions = awaitCompletion(responses, executor, null, logger, "runScriptOnNodesMatching(" + filter + ")");
563 }
564
565 Function<NodeMetadata, NodeMetadata> fn = persistNodeCredentials.ifAdminAccess(runScript);
566 badNodes = Maps2.transformKeys(badNodes, fn);
567 goodNodes = Maps2.transformKeys(goodNodes, fn);
568
569 if (exceptions.size() > 0 || badNodes.size() > 0) {
570 throw new RunScriptOnNodesException(runScript, options, goodNodes, exceptions, badNodes);
571 }
572 return goodNodes;
573 }
574
575
576
577
578 @Override
579 public ExecResponse runScriptOnNode(String id, String runScript) {
580 return runScriptOnNode(id, runScript, RunScriptOptions.NONE);
581 }
582
583
584
585
586 @Override
587 public ExecResponse runScriptOnNode(String id, String runScript, RunScriptOptions options) {
588 return runScriptOnNode(id, Statements.exec(checkNotNull(runScript, "runScript")), options);
589 }
590
591
592
593
594 @Override
595 public ExecResponse runScriptOnNode(String id, Statement runScript) {
596 return runScriptOnNode(id, runScript, RunScriptOptions.NONE);
597 }
598
599
600
601
602 @Override
603 public ExecResponse runScriptOnNode(String id, Statement runScript, RunScriptOptions options) {
604 NodeMetadata node = this.getNodeMetadata(id);
605 if (node == null)
606 throw new NoSuchElementException(id);
607 if (node.getState() != NodeState.RUNNING)
608 throw new IllegalStateException("node " + id
609 + " needs to be running before executing a script on it. current state: " + node.getState());
610 initAdminAccess.visit(runScript);
611 node = updateNodeWithCredentialsIfPresent(node, options);
612 ExecResponse response = runScriptOnNodeFactory.create(node, runScript, options).init().call();
613 persistNodeCredentials.ifAdminAccess(runScript).apply(node);
614 return response;
615 }
616
617
618
619
620 @Override
621 public ListenableFuture<ExecResponse> submitScriptOnNode(String id, final Statement runScript,
622 RunScriptOptions options) {
623 NodeMetadata node = this.getNodeMetadata(id);
624 if (node == null)
625 throw new NoSuchElementException(id);
626 if (node.getState() != NodeState.RUNNING)
627 throw new IllegalStateException("node " + id
628 + " needs to be running before executing a script on it. current state: " + node.getState());
629 initAdminAccess.visit(runScript);
630 final NodeMetadata node1 = updateNodeWithCredentialsIfPresent(node, options);
631 ListenableFuture<ExecResponse> response = runScriptOnNodeFactory.submit(node1, runScript, options);
632 response.addListener(new Runnable() {
633
634 @Override
635 public void run() {
636 persistNodeCredentials.ifAdminAccess(runScript).apply(node1);
637 }
638
639 }, executor);
640 return response;
641 }
642
643 private Iterable<? extends RunScriptOnNode> transformNodesIntoInitializedScriptRunners(
644 Iterable<? extends NodeMetadata> nodes, Statement script, RunScriptOptions options,
645 Map<NodeMetadata, Exception> badNodes) {
646 return filter(transformParallel(nodes, new TransformNodesIntoInitializedScriptRunners(script, options, badNodes),
647 executor, null, logger, "initialize script runners"), notNull());
648 }
649
650 private Set<? extends NodeMetadata> detailsOnAllNodes() {
651 return newLinkedHashSet(listNodesStrategy.listDetailsOnNodesMatching(all()));
652 }
653
654 @Override
655 public TemplateOptions templateOptions() {
656 return templateOptionsProvider.get();
657 }
658
659 protected NodeMetadata updateNodeWithCredentialsIfPresent(NodeMetadata node, RunScriptOptions options) {
660 checkNotNull(node, "node");
661 if (options.getOverridingCredentials() != null) {
662 Builder<? extends Credentials> builder = node.getCredentials() != null ? node.getCredentials().toBuilder()
663 : new Credentials.Builder<Credentials>();
664 if (options.getOverridingCredentials().identity != null)
665 builder.identity(options.getOverridingCredentials().identity);
666 if (options.getOverridingCredentials().credential != null) {
667
668 builder = options.getOverridingCredentials().toBuilder();
669 Credentials cred = builder.build();
670 builder.identity(cred.identity);
671 builder.credential(options.getOverridingCredentials().credential);
672 }
673 node = NodeMetadataBuilder.fromNodeMetadata(node).credentials(builder.build()).build();
674 }
675 return node;
676 }
677
678 private final class TransformNodesIntoInitializedScriptRunners implements
679 Function<NodeMetadata, Future<RunScriptOnNode>> {
680 private final Map<NodeMetadata, Exception> badNodes;
681 private final Statement script;
682 private final RunScriptOptions options;
683
684 private TransformNodesIntoInitializedScriptRunners(Statement script, RunScriptOptions options,
685 Map<NodeMetadata, Exception> badNodes) {
686 this.badNodes = checkNotNull(badNodes, "badNodes");
687 this.script = checkNotNull(script, "script");
688 this.options = checkNotNull(options, "options");
689 }
690
691 @Override
692 public Future<RunScriptOnNode> apply(NodeMetadata node) {
693 node = updateNodeWithCredentialsIfPresent(node, options);
694 return executor.submit(initScriptRunnerFactory.create(node, script, options, badNodes));
695 }
696
697 }
698
699 }