View Javadoc

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   */
19  package org.jclouds.compute.options;
20  
21  import static com.google.common.base.Preconditions.checkArgument;
22  import static com.google.common.base.Preconditions.checkNotNull;
23  
24  import java.io.IOException;
25  import java.util.Arrays;
26  import java.util.Map;
27  import java.util.Set;
28  
29  import org.jclouds.compute.domain.NodeState;
30  import org.jclouds.domain.Credentials;
31  import org.jclouds.io.Payload;
32  import org.jclouds.scriptbuilder.domain.Statement;
33  import org.jclouds.scriptbuilder.domain.Statements;
34  import org.jclouds.util.Strings2;
35  
36  import com.google.common.base.Throwables;
37  import com.google.common.collect.ImmutableSet;
38  import com.google.common.collect.Maps;
39  
40  /**
41   * Contains options supported in the {@code ComputeService#runNodesWithTag}
42   * operation. <h2>
43   * Usage</h2> The recommended way to instantiate a TemplateOptions object is to
44   * statically import TemplateOptions.* and invoke a static creation method
45   * followed by an instance mutator (if needed):
46   * <p/>
47   * <code>
48   * import static org.jclouds.compute.options.TemplateOptions.Builder.*;
49   * <p/>
50   * ComputeService client = // get connection
51   * templateBuilder.options(inboundPorts(22, 80, 8080, 443));
52   * Set<? extends NodeMetadata> set = client.runNodesWithTag(tag, 2, templateBuilder.build());
53   * <code>
54   * 
55   * @author Adrian Cole
56   */
57  public class TemplateOptions extends RunScriptOptions implements Cloneable {
58  
59     @Override
60     public TemplateOptions clone() {
61        TemplateOptions options = new TemplateOptions();
62        copyTo(options);
63        return options;
64     }
65  
66     public void copyTo(TemplateOptions to) {
67        if (!Arrays.equals(to.getInboundPorts(), this.getInboundPorts()))
68           to.inboundPorts(this.getInboundPorts());
69        if (this.getRunScript() != null)
70           to.runScript(this.getRunScript());
71        if (this.getPrivateKey() != null)
72           to.installPrivateKey(this.getPrivateKey());
73        if (this.getPublicKey() != null)
74           to.authorizePublicKey(this.getPublicKey());
75        if (this.getPort() != -1)
76           to.blockOnPort(this.getPort(), this.getSeconds());
77        if (this.getUserMetadata().size() > 0)
78           to.userMetadata(this.getUserMetadata());
79        if (this.getTags().size() > 0)
80           to.tags(getTags());
81        if (!this.shouldBlockUntilRunning())
82           to.blockUntilRunning(false);
83        if (!this.shouldBlockOnComplete())
84           to.blockOnComplete(false);
85        if (this.getOverridingCredentials() != null)
86           to.overrideCredentialsWith(this.getOverridingCredentials());
87        if (this.getTaskName() != null)
88           to.nameTask(this.getTaskName());
89     }
90  
91     public static final TemplateOptions NONE = new ImmutableTemplateOptions(new TemplateOptions());
92  
93     public static class ImmutableTemplateOptions extends TemplateOptions {
94        private final TemplateOptions delegate;
95  
96        @Override
97        public TemplateOptions clone() {
98           return delegate.clone();
99        }
100 
101       @Override
102       public String getTaskName() {
103          return delegate.getTaskName();
104       }
105 
106       @Override
107       public int getPort() {
108          return delegate.getPort();
109       }
110 
111       @Override
112       public int getSeconds() {
113          return delegate.getSeconds();
114       }
115 
116       @Override
117       public Credentials getOverridingCredentials() {
118          return delegate.getOverridingCredentials();
119       }
120 
121       @Override
122       public boolean shouldRunAsRoot() {
123          return delegate.shouldRunAsRoot();
124       }
125 
126       @Override
127       public boolean shouldBlockOnComplete() {
128          return delegate.shouldBlockOnComplete();
129       }
130 
131       @Override
132       public boolean shouldWrapInInitScript() {
133          return delegate.shouldWrapInInitScript();
134       }
135 
136       @Override
137       public void copyTo(TemplateOptions to) {
138          delegate.copyTo(to);
139       }
140 
141       public ImmutableTemplateOptions(TemplateOptions delegate) {
142          this.delegate = delegate;
143       }
144 
145       @Override
146       public String toString() {
147          return delegate.toString();
148       }
149 
150       @Override
151       public TemplateOptions runScript(Payload script) {
152          throw new IllegalArgumentException("script is immutable");
153       }
154 
155       /**
156        * unsupported as objects of this class are immutable
157        */
158       @Override
159       public TemplateOptions runScript(Statement script) {
160          throw new IllegalArgumentException("script is immutable");
161       }
162 
163       @Override
164       public TemplateOptions installPrivateKey(Payload privateKey) {
165          throw new IllegalArgumentException("privateKey is immutable");
166       }
167 
168       @Override
169       public TemplateOptions dontAuthorizePublicKey() {
170          throw new IllegalArgumentException("public key is immutable");
171       }
172 
173       @Override
174       @Deprecated
175       public TemplateOptions authorizePublicKey(Payload publicKey) {
176          throw new IllegalArgumentException("public key is immutable");
177       }
178 
179       @Override
180       public TemplateOptions blockOnPort(int port, int seconds) {
181          throw new IllegalArgumentException("ports are immutable");
182       }
183 
184       @Override
185       public TemplateOptions nameTask(String name) {
186          throw new IllegalArgumentException("task name is immutable");
187       }
188 
189       @Override
190       public TemplateOptions runAsRoot(boolean runAsRoot) {
191          throw new IllegalArgumentException("runAsRoot is immutable");
192       }
193 
194       @Override
195       public TemplateOptions overrideCredentialsWith(Credentials overridingCredentials) {
196          throw new IllegalArgumentException("credentials are immutable");
197       }
198 
199       @Override
200       public TemplateOptions overrideLoginUserWith(String loginUser) {
201          throw new IllegalArgumentException("credentials are immutable");
202       }
203 
204       @Override
205       public TemplateOptions overrideLoginCredentialWith(String loginCredential) {
206          throw new IllegalArgumentException("credentials are immutable");
207       }
208 
209       @Override
210       public TemplateOptions wrapInInitScript(boolean wrapInInitScript) {
211          throw new IllegalArgumentException("wrapInInitScript is immutable");
212       }
213 
214       @Override
215       public TemplateOptions blockOnComplete(boolean blockOnComplete) {
216          throw new IllegalArgumentException("blockOnComplete is immutable");
217       }
218 
219       @Override
220       public <T extends TemplateOptions> T as(Class<T> clazz) {
221          return delegate.as(clazz);
222       }
223 
224       @Override
225       public TemplateOptions authorizePublicKey(String publicKey) {
226          throw new IllegalArgumentException("publicKey is immutable");
227       }
228 
229       /**
230        * unsupported as objects of this class are immutable
231        */
232       @Override
233       public TemplateOptions blockUntilRunning(boolean blockUntilRunning) {
234          throw new IllegalArgumentException("blockUntilRunning is immutable");
235       }
236 
237       @Override
238       public int[] getInboundPorts() {
239          return delegate.getInboundPorts();
240       }
241 
242       @Override
243       public String getPrivateKey() {
244          return delegate.getPrivateKey();
245       }
246 
247       @Override
248       public String getPublicKey() {
249          return delegate.getPublicKey();
250       }
251 
252       @Override
253       public Statement getRunScript() {
254          return delegate.getRunScript();
255       }
256 
257       @Override
258       public boolean shouldBlockUntilRunning() {
259          return delegate.shouldBlockUntilRunning();
260       }
261 
262       @Override
263       public TemplateOptions inboundPorts(int... ports) {
264          throw new IllegalArgumentException("ports are immutable");
265       }
266 
267       @Override
268       public TemplateOptions installPrivateKey(String privateKey) {
269          throw new IllegalArgumentException("privateKey is immutable");
270       }
271 
272       @Override
273       public TemplateOptions runScript(byte[] script) {
274          throw new IllegalArgumentException("script is immutable");
275       }
276 
277       @Override
278       public Set<String> getTags() {
279          return delegate.getTags();
280       }
281 
282       @Override
283       public TemplateOptions tags(Iterable<String> tags) {
284          throw new IllegalArgumentException("tags are immutable");
285       }
286 
287       @Override
288       public TemplateOptions userMetadata(Map<String, String> userMetadata) {
289          throw new IllegalArgumentException("userMetadata is immutable");
290       }
291 
292       @Override
293       public TemplateOptions userMetadata(String key, String value) {
294          throw new IllegalArgumentException("userMetadata is immutable");
295       }
296 
297       @Override
298       public Map<String, String> getUserMetadata() {
299          return delegate.getUserMetadata();
300       }
301 
302    }
303 
304    protected int[] inboundPorts = new int[] { 22 };
305 
306    protected Statement script;
307 
308    protected Set<String> tags = ImmutableSet.of();
309 
310    protected String privateKey;
311 
312    protected String publicKey;
313 
314    protected boolean blockUntilRunning = true;
315 
316    protected Map<String, String> userMetadata = Maps.newLinkedHashMap();
317 
318    public int[] getInboundPorts() {
319       return inboundPorts;
320    }
321 
322    public Statement getRunScript() {
323       return script;
324    }
325 
326    public Set<String> getTags() {
327       return tags;
328    }
329 
330    public String getPrivateKey() {
331       return privateKey;
332    }
333 
334    public String getPublicKey() {
335       return publicKey;
336    }
337 
338    /**
339     * @see TemplateOptions#blockUntilRunning(boolean)
340     */
341    public boolean shouldBlockUntilRunning() {
342       return blockUntilRunning;
343    }
344 
345    public <T extends TemplateOptions> T as(Class<T> clazz) {
346       return clazz.cast(this);
347    }
348 
349    /**
350     * <p/>
351     * please use alternative that uses the
352     * {@link org.jclouds.scriptbuilder.domain.Statement} object
353     * 
354     * @see TemplateOptions#runScript(Statement)
355     * @see org.jclouds.io.Payloads
356     */
357    @Deprecated
358    public TemplateOptions runScript(byte[] script) {
359       return runScript(Statements.exec(new String(checkNotNull(script, "script"))));
360    }
361 
362    /**
363     * @see TemplateOptions#runScript(Statement)
364     * @see org.jclouds.io.Payloads
365     */
366    public TemplateOptions runScript(Payload script) {
367       try {
368          return runScript(Statements.exec(Strings2.toStringAndClose(checkNotNull(script, "script").getInput())));
369       } catch (IOException e) {
370          Throwables.propagate(e);
371          return this;
372       }
373    }
374 
375    /**
376     * This script will be executed as the root user upon system startup. This
377     * script gets a prologue, so no #!/bin/bash required, path set up, etc
378     * 
379     */
380    public TemplateOptions runScript(Statement script) {
381       this.script = checkNotNull(script, "script");
382       return this;
383    }
384 
385    /**
386     * replaces the rsa ssh key used at login.
387     */
388    public TemplateOptions installPrivateKey(String privateKey) {
389       checkArgument(checkNotNull(privateKey, "privateKey").startsWith("-----BEGIN RSA PRIVATE KEY-----"),
390             "key should start with -----BEGIN RSA PRIVATE KEY-----");
391       this.privateKey = privateKey;
392       return this;
393    }
394 
395    /**
396     * replaces the rsa ssh key used at login.
397     * <p/>
398     * please use alternative that uses {@link java.lang.String}
399     * 
400     * @see org.jclouds.io.Payloads
401     */
402    @Deprecated
403    public TemplateOptions installPrivateKey(Payload privateKey) {
404       try {
405          return installPrivateKey(Strings2.toStringAndClose(checkNotNull(privateKey, "privateKey").getInput()));
406       } catch (IOException e) {
407          Throwables.propagate(e);
408          return this;
409       }
410    }
411 
412    public TemplateOptions dontAuthorizePublicKey() {
413       this.publicKey = null;
414       return this;
415    }
416 
417    /**
418     * authorize an rsa ssh key.
419     */
420    public TemplateOptions authorizePublicKey(String publicKey) {
421       checkArgument(checkNotNull(publicKey, "publicKey").startsWith("ssh-rsa"), "key should start with ssh-rsa");
422       this.publicKey = publicKey;
423       return this;
424    }
425 
426    /**
427     * authorize an rsa ssh key.
428     * <p/>
429     * please use alternative that uses {@link java.lang.String}
430     * 
431     * @see org.jclouds.io.Payloads
432     */
433    @Deprecated
434    public TemplateOptions authorizePublicKey(Payload publicKey) {
435       try {
436          return authorizePublicKey(Strings2.toStringAndClose(checkNotNull(publicKey, "publicKey").getInput()));
437       } catch (IOException e) {
438          Throwables.propagate(e);
439          return this;
440       }
441    }
442 
443    /**
444     * assigns tags to the created nodes
445     */
446    public TemplateOptions tags(Iterable<String> tags) {
447       this.tags = ImmutableSet.copyOf(checkNotNull(tags, "tags"));
448       return this;
449    }
450 
451    /**
452     * Opens the set of ports to public access.
453     */
454    public TemplateOptions inboundPorts(int... ports) {
455       for (int port : ports)
456          checkArgument(port > 0 && port < 65536, "port must be a positive integer < 65535");
457       this.inboundPorts = ports;
458       return this;
459    }
460 
461    public static class Builder extends org.jclouds.compute.options.RunScriptOptions.Builder {
462 
463       public static TemplateOptions nameTask(String name) {
464          TemplateOptions options = new TemplateOptions();
465          return options.nameTask(name);
466       }
467 
468       public static TemplateOptions overrideLoginUserWith(String user) {
469          TemplateOptions options = new TemplateOptions();
470          return options.overrideLoginUserWith(user);
471       }
472 
473       public static TemplateOptions overrideLoginCredentialWith(String credential) {
474          TemplateOptions options = new TemplateOptions();
475          return options.overrideLoginCredentialWith(credential);
476       }
477 
478       public static TemplateOptions overrideCredentialsWith(Credentials credentials) {
479          TemplateOptions options = new TemplateOptions();
480          return options.overrideCredentialsWith(credentials);
481       }
482 
483       public static TemplateOptions runAsRoot(boolean value) {
484          TemplateOptions options = new TemplateOptions();
485          return options.runAsRoot(value);
486       }
487 
488       /**
489        * @see TemplateOptions#blockOnPort
490        */
491       public static TemplateOptions blockOnPort(int port, int seconds) {
492          TemplateOptions options = new TemplateOptions();
493          return options.blockOnPort(port, seconds);
494       }
495 
496       /**
497        * @see TemplateOptions#inboundPorts
498        */
499       public static TemplateOptions inboundPorts(int... ports) {
500          TemplateOptions options = new TemplateOptions();
501          return options.inboundPorts(ports);
502       }
503 
504       /**
505        * @see TemplateOptions#tags
506        */
507       public static TemplateOptions tags(Iterable<String> tags) {
508          TemplateOptions options = new TemplateOptions();
509          return options.tags(tags);
510       }
511 
512       /**
513        * @see TemplateOptions#blockUntilRunning(boolean)
514        */
515       public static TemplateOptions blockUntilRunning(boolean blockUntilRunning) {
516          TemplateOptions options = new TemplateOptions();
517          return options.blockUntilRunning(blockUntilRunning);
518       }
519 
520 /**
521        * please use alternative that uses the {@link Statement) object
522        * 
523        * @see TemplateOptions#runScript(Statement)
524        */
525       @Deprecated
526       public static TemplateOptions runScript(byte[] script) {
527          TemplateOptions options = new TemplateOptions();
528          return options.runScript(script);
529       }
530 
531       /**
532        * @see TemplateOptions#runScript(Statement)
533        * @see org.jclouds.io.Payloads
534        */
535       public static TemplateOptions runScript(Payload script) {
536          TemplateOptions options = new TemplateOptions();
537          return options.runScript(script);
538       }
539 
540       /**
541        * @see TemplateOptions#runScript(Statement)
542        */
543       public static TemplateOptions runScript(Statement script) {
544          TemplateOptions options = new TemplateOptions();
545          return options.runScript(script);
546       }
547 
548       /**
549        * please use alternative that uses the {@link org.jclouds.io.Payload}
550        * object
551        * 
552        * @see org.jclouds.io.Payloads
553        * @see #installPrivateKey(Payload)
554        */
555       @Deprecated
556       public static TemplateOptions installPrivateKey(String rsaKey) {
557          TemplateOptions options = new TemplateOptions();
558          return options.installPrivateKey(rsaKey);
559       }
560 
561       /**
562        * @see TemplateOptions#installPrivateKey
563        * @see org.jclouds.io.Payloads
564        */
565       public static TemplateOptions installPrivateKey(Payload rsaKey) {
566          TemplateOptions options = new TemplateOptions();
567          return options.installPrivateKey(rsaKey);
568       }
569 
570       /**
571        * please use alternative that uses the {@link org.jclouds.io.Payload}
572        * object
573        * 
574        * @see org.jclouds.io.Payloads
575        * @see #authorizePublicKey(Payload)
576        */
577       @Deprecated
578       public static TemplateOptions authorizePublicKey(String rsaKey) {
579          TemplateOptions options = new TemplateOptions();
580          return options.authorizePublicKey(rsaKey);
581       }
582 
583       /**
584        * @see TemplateOptions#authorizePublicKey(Payload)
585        * @see org.jclouds.io.Payloads
586        */
587       public static TemplateOptions authorizePublicKey(Payload rsaKey) {
588          TemplateOptions options = new TemplateOptions();
589          return options.authorizePublicKey(rsaKey);
590       }
591 
592       /**
593        * @see TemplateOptions#userMetadata(Map)
594        */
595       public static TemplateOptions userMetadata(Map<String, String> userMetadata) {
596          TemplateOptions options = new TemplateOptions();
597          return options.userMetadata(userMetadata);
598       }
599 
600       /**
601        * @see TemplateOptions#userMetadata(String, String)
602        */
603       public static TemplateOptions userMetadata(String key, String value) {
604          TemplateOptions options = new TemplateOptions();
605          return options.userMetadata(key, value);
606       }
607 
608       public static TemplateOptions blockOnComplete(boolean value) {
609          TemplateOptions options = new TemplateOptions();
610          return options.blockOnComplete(value);
611       }
612 
613    }
614 
615    @Override
616    public String toString() {
617       return "[inboundPorts=" + Arrays.toString(inboundPorts) + ", privateKey=" + (privateKey != null) + ", publicKey="
618             + (publicKey != null) + ", runScript=" + (script != null) + ", blockUntilRunning=" + blockUntilRunning
619             + ", blockOnComplete=" + blockOnComplete + ", port:seconds=" + port + ":" + seconds + ", userMetadata: "
620             + userMetadata + "]";
621    }
622 
623    /**
624     * <h4>Note</h4> As of version 1.1.0, this option is incompatible with
625     * {@link TemplateOptions#runScript(Statement)} and
626     * {@link RunScriptOptions#blockOnComplete(boolean)}, as all current
627     * implementations utilize ssh in order to execute scripts.
628     * 
629     * @param blockUntilRunning
630     *           (default true) whether to block until the nodes in this template
631     *           are in {@link NodeState#RUNNING} state
632     */
633    public TemplateOptions blockUntilRunning(boolean blockUntilRunning) {
634       this.blockUntilRunning = blockUntilRunning;
635       if (!blockUntilRunning)
636          port = seconds = -1;
637       return this;
638    }
639 
640    /**
641     * 
642     * @param userMetadata
643     *           user-defined metadata to assign to this server
644     */
645    public TemplateOptions userMetadata(Map<String, String> userMetadata) {
646       this.userMetadata.putAll(checkNotNull(userMetadata, "userMetadata"));
647       return this;
648    }
649 
650    /**
651     * 
652     * @param key
653     *           key to place into the metadata map
654     * @param value
655     *           value to associate with that key
656     */
657    public TemplateOptions userMetadata(String key, String value) {
658       this.userMetadata.put(checkNotNull(key, "key"), checkNotNull(value, "value"));
659       return this;
660    }
661 
662    /**
663     * @see #userMetadata(Map)
664     */
665    public Map<String, String> getUserMetadata() {
666       return userMetadata;
667    }
668 
669    @Override
670    public int hashCode() {
671       final int prime = 31;
672       int result = 1;
673       result = prime * result + (blockUntilRunning ? 1231 : 1237);
674       result = prime * result + Arrays.hashCode(inboundPorts);
675       result = prime * result + port;
676       result = prime * result + ((userMetadata == null) ? 0 : userMetadata.hashCode());
677       result = prime * result + ((privateKey == null) ? 0 : privateKey.hashCode());
678       result = prime * result + ((publicKey == null) ? 0 : publicKey.hashCode());
679       result = prime * result + ((script == null) ? 0 : script.hashCode());
680       result = prime * result + seconds;
681       return result;
682    }
683 
684    @Override
685    public boolean equals(Object obj) {
686       if (this == obj)
687          return true;
688       if (obj == null)
689          return false;
690       if (getClass() != obj.getClass())
691          return false;
692       TemplateOptions other = (TemplateOptions) obj;
693       if (blockUntilRunning != other.blockUntilRunning)
694          return false;
695       if (!Arrays.equals(inboundPorts, other.inboundPorts))
696          return false;
697       if (userMetadata == null) {
698          if (other.userMetadata != null)
699             return false;
700       } else if (!userMetadata.equals(other.userMetadata))
701          return false;
702       if (port != other.port)
703          return false;
704       if (privateKey == null) {
705          if (other.privateKey != null)
706             return false;
707       } else if (!privateKey.equals(other.privateKey))
708          return false;
709       if (publicKey == null) {
710          if (other.publicKey != null)
711             return false;
712       } else if (!publicKey.equals(other.publicKey))
713          return false;
714       if (script == null) {
715          if (other.script != null)
716             return false;
717       } else if (!script.equals(other.script))
718          return false;
719       if (seconds != other.seconds)
720          return false;
721       return true;
722    }
723 
724    @Override
725    public TemplateOptions blockOnPort(int port, int seconds) {
726       return TemplateOptions.class.cast(super.blockOnPort(port, seconds));
727    }
728 
729    @Override
730    public TemplateOptions nameTask(String name) {
731       return TemplateOptions.class.cast(super.nameTask(name));
732    }
733 
734    @Override
735    public TemplateOptions runAsRoot(boolean runAsRoot) {
736       return TemplateOptions.class.cast(super.runAsRoot(runAsRoot));
737    }
738 
739    @Override
740    public TemplateOptions overrideCredentialsWith(Credentials overridingCredentials) {
741       return TemplateOptions.class.cast(super.overrideCredentialsWith(overridingCredentials));
742    }
743 
744    @Override
745    public TemplateOptions overrideLoginUserWith(String loginUser) {
746       return TemplateOptions.class.cast(super.overrideLoginUserWith(loginUser));
747    }
748 
749    @Override
750    public TemplateOptions overrideLoginCredentialWith(String loginCredential) {
751       return TemplateOptions.class.cast(super.overrideLoginCredentialWith(loginCredential));
752    }
753 
754    @Override
755    public TemplateOptions wrapInInitScript(boolean wrapInInitScript) {
756       return TemplateOptions.class.cast(super.wrapInInitScript(wrapInInitScript));
757    }
758 
759    @Override
760    public TemplateOptions blockOnComplete(boolean blockOnComplete) {
761       return TemplateOptions.class.cast(super.blockOnComplete(blockOnComplete));
762    }
763 }