Merge branch 'master' of git://github.com/jclouds/jclouds into jclouds-vbox

This commit is contained in:
David Ribeiro Alves 2012-02-21 15:13:57 +00:00
commit 77122c4bc8
492 changed files with 14360 additions and 4874 deletions

View File

@ -47,7 +47,7 @@ import org.apache.tools.ant.types.Environment;
import org.apache.tools.ant.types.FileSet; import org.apache.tools.ant.types.FileSet;
import org.apache.tools.ant.types.Path; import org.apache.tools.ant.types.Path;
import org.apache.tools.ant.types.Environment.Variable; import org.apache.tools.ant.types.Environment.Variable;
import org.jclouds.scriptbuilder.InitBuilder; import org.jclouds.scriptbuilder.InitScript;
import org.jclouds.scriptbuilder.domain.OsFamily; import org.jclouds.scriptbuilder.domain.OsFamily;
import org.jclouds.scriptbuilder.domain.ShellToken; import org.jclouds.scriptbuilder.domain.ShellToken;
import org.jclouds.scriptbuilder.domain.Statement; import org.jclouds.scriptbuilder.domain.Statement;
@ -237,13 +237,13 @@ public class SSHJava extends Java {
private int sshexecRedirectStreams(Statement statement) throws IOException { private int sshexecRedirectStreams(Statement statement) throws IOException {
exec.setStreamHandler(redirector.createHandler()); exec.setStreamHandler(redirector.createHandler());
log("starting java as:\n" + statement.render(osFamily), Project.MSG_VERBOSE); log("starting java as:\n" + statement.render(osFamily), Project.MSG_VERBOSE);
int rc; int exitStatus;
try { try {
rc = sshexec(statement.render(osFamily)); exitStatus = sshexec(statement.render(osFamily));
} finally { } finally {
redirector.complete(); redirector.complete();
} }
return rc; return exitStatus;
} }
private void mkdirAndCopyTo(String destination, Iterable<FileSet> sets) { private void mkdirAndCopyTo(String destination, Iterable<FileSet> sets) {
@ -373,8 +373,8 @@ public class SSHJava extends Java {
Joiner.on(' ').join(commandLine.getJavaCommand().getArguments())); Joiner.on(' ').join(commandLine.getJavaCommand().getArguments()));
} }
InitBuilder testInitBuilder = new InitBuilder(id, basedir, basedir, envVariables, InitScript testInitBuilder = InitScript.builder().name(id).home(basedir).exportVariables(envVariables)
ImmutableList.<Statement> of(Statements.interpret( commandBuilder.toString()))); .run(Statements.interpret( commandBuilder.toString())).build();
return testInitBuilder.render(osFamily); return testInitBuilder.render(osFamily);
} }

View File

@ -118,8 +118,8 @@
<configuration> <configuration>
<instructions> <instructions>
<Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName> <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
<Export-Package>org.jclouds.atmos.*;version="${project.version}"</Export-Package> <Export-Package>org.jclouds.atmos*;version="${project.version}"</Export-Package>
<Import-Package>org.jclouds.*;version="${project.version}",*</Import-Package> <Import-Package>org.jclouds*;version="${project.version}",*</Import-Package>
</instructions> </instructions>
</configuration> </configuration>
</plugin> </plugin>

View File

@ -113,11 +113,11 @@
<configuration> <configuration>
<instructions> <instructions>
<Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName> <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
<Export-Package>org.jclouds.byon.*;version="${project.version}"</Export-Package> <Export-Package>org.jclouds.byon*;version="${project.version}"</Export-Package>
<Import-Package> <Import-Package>
org.jclouds.compute.internal;version="${project.version}", org.jclouds.compute.internal;version="${project.version}",
org.jclouds.rest.internal;version="${project.version}", org.jclouds.rest.internal;version="${project.version}",
org.jclouds.*;version="${project.version}", org.jclouds*;version="${project.version}",
* *
</Import-Package> </Import-Package>
</instructions> </instructions>

View File

@ -133,8 +133,12 @@
<configuration> <configuration>
<instructions> <instructions>
<Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName> <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
<Export-Package>org.jclouds.cloudfiles.*;version="${project.version}"</Export-Package> <Export-Package>org.jclouds.cloudfiles*;version="${project.version}"</Export-Package>
<Import-Package>org.jclouds.*;version="${project.version}",*</Import-Package> <Import-Package>
org.jclouds*;version="${project.version}",
org.jclouds.openstack.swift.options;version="${project.version}",
*
</Import-Package>
</instructions> </instructions>
</configuration> </configuration>
</plugin> </plugin>

View File

@ -119,8 +119,8 @@
<configuration> <configuration>
<instructions> <instructions>
<Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName> <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
<Export-Package>org.jclouds.cloudloadbalancers.*;version="${project.version}"</Export-Package> <Export-Package>org.jclouds.cloudloadbalancers*;version="${project.version}"</Export-Package>
<Import-Package>org.jclouds.*;version="${project.version}",*</Import-Package> <Import-Package>org.jclouds*;version="${project.version}",*</Import-Package>
</instructions> </instructions>
</configuration> </configuration>
</plugin> </plugin>

View File

@ -134,11 +134,11 @@
<configuration> <configuration>
<instructions> <instructions>
<Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName> <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
<Export-Package>org.jclouds.cloudservers.*;version="${project.version}"</Export-Package> <Export-Package>org.jclouds.cloudservers*;version="${project.version}"</Export-Package>
<Import-Package> <Import-Package>
org.jclouds.compute.internal;version="${project.version}", org.jclouds.compute.internal;version="${project.version}",
org.jclouds.rest.internal;version="${project.version}", org.jclouds.rest.internal;version="${project.version}",
org.jclouds.*;version="${project.version}", org.jclouds*;version="${project.version}",
* *
</Import-Package> </Import-Package>
</instructions> </instructions>

View File

@ -132,7 +132,7 @@ public class ServerToNodeMetadata implements Function<Server, NodeMetadata> {
try { try {
return Iterables.find(images.get(), new FindImageForServer(from)).getOperatingSystem(); return Iterables.find(images.get(), new FindImageForServer(from)).getOperatingSystem();
} catch (NoSuchElementException e) { } catch (NoSuchElementException e) {
logger.warn("could not find a matching image for server %s in location %s", from, location); logger.warn("could not find a matching image for server %s in location %s", from, location.get());
} }
return null; return null;
} }

View File

@ -120,11 +120,11 @@
<configuration> <configuration>
<instructions> <instructions>
<Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName> <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
<Export-Package>org.jclouds.cloudsigma.*;version="${project.version}"</Export-Package> <Export-Package>org.jclouds.cloudsigma*;version="${project.version}"</Export-Package>
<Import-Package> <Import-Package>
org.jclouds.compute.internal;version="${project.version}", org.jclouds.compute.internal;version="${project.version}",
org.jclouds.rest.internal;version="${project.version}", org.jclouds.rest.internal;version="${project.version}",
org.jclouds.*;version="${project.version}", org.jclouds*;version="${project.version}",
* *
</Import-Package> </Import-Package>
</instructions> </instructions>

View File

@ -144,11 +144,11 @@
<configuration> <configuration>
<instructions> <instructions>
<Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName> <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
<Export-Package>org.jclouds.cloudstack.*;version="${project.version}"</Export-Package> <Export-Package>org.jclouds.cloudstack*;version="${project.version}"</Export-Package>
<Import-Package> <Import-Package>
org.jclouds.compute.internal;version="${project.version}", org.jclouds.compute.internal;version="${project.version}",
org.jclouds.rest.internal;version="${project.version}", org.jclouds.rest.internal;version="${project.version}",
org.jclouds.*;version="${project.version}", org.jclouds*;version="${project.version}",
* *
</Import-Package> </Import-Package>
</instructions> </instructions>

View File

@ -109,8 +109,8 @@
<configuration> <configuration>
<instructions> <instructions>
<Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName> <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
<Export-Package>org.jclouds.cloudwatch.*;version="${project.version}"</Export-Package> <Export-Package>org.jclouds.cloudwatch*;version="${project.version}"</Export-Package>
<Import-Package>org.jclouds.*;version="${project.version}",*</Import-Package> <Import-Package>org.jclouds*;version="${project.version}",*</Import-Package>
</instructions> </instructions>
</configuration> </configuration>
</plugin> </plugin>

View File

@ -133,11 +133,11 @@
<configuration> <configuration>
<instructions> <instructions>
<Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName> <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
<Export-Package>org.jclouds.deltacloud.*;version="${project.version}"</Export-Package> <Export-Package>org.jclouds.deltacloud*;version="${project.version}"</Export-Package>
<Import-Package> <Import-Package>
org.jclouds.compute.internal;version="${project.version}", org.jclouds.compute.internal;version="${project.version}",
org.jclouds.rest.internal;version="${project.version}", org.jclouds.rest.internal;version="${project.version}",
org.jclouds.*;version="${project.version}", org.jclouds*;version="${project.version}",
* *
</Import-Package> </Import-Package>
</instructions> </instructions>

View File

@ -134,11 +134,11 @@
<configuration> <configuration>
<instructions> <instructions>
<Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName> <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
<Export-Package>org.jclouds.ec2.*;version="${project.version}"</Export-Package> <Export-Package>org.jclouds.ec2*;version="${project.version}"</Export-Package>
<Import-Package> <Import-Package>
org.jclouds.compute.internal;version="${project.version}", org.jclouds.compute.internal;version="${project.version}",
org.jclouds.rest.internal;version="${project.version}", org.jclouds.rest.internal;version="${project.version}",
org.jclouds.*;version="${project.version}", org.jclouds*;version="${project.version}",
* *
</Import-Package> </Import-Package>
</instructions> </instructions>

View File

@ -1,319 +0,0 @@
;
; Licensed to jclouds, Inc. (jclouds) under one or more
; contributor license agreements. See the NOTICE file
; distributed with this work for additional information
; regarding copyright ownership. jclouds licenses this file
; to you under the Apache License, Version 2.0 (the
; "License"); you may not use this file except in compliance
; with the License. You may obtain a copy of the License at
;
; http://www.apache.org/licenses/LICENSE-2.0
;
; Unless required by applicable law or agreed to in writing,
; software distributed under the License is distributed on an
; "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
; KIND, either express or implied. See the License for the
; specific language governing permissions and limitations
; under the License.
;
(ns
#^{:author "Chas Emerick, cemerick@snowtide.com"
:doc "A clojure binding to the jclouds EBS service interface."}
org.jclouds.ec2.ebs
(:use [clojure.core.incubator :only (-?>)])
(:require (org.jclouds [compute :as compute]))
(:import org.jclouds.aws.domain.Region
org.jclouds.compute.domain.NodeMetadata
(org.jclouds.ec2.domain Volume Volume$Status Snapshot Snapshot$Status AvailabilityZoneInfo)
(org.jclouds.ec2.options DescribeSnapshotsOptions DetachVolumeOptions CreateSnapshotOptions)))
(defn snapshot?
"Returns true iff the argument is a org.jclouds.ec2.domain.Snapshot."
[s]
(instance? Snapshot s))
(defn volume?
"Returns true iff the argument is a org.jclouds.ec2.domain.Volume."
[v]
(instance? Volume v))
(defn #^org.jclouds.ec2.services.ElasticBlockStoreClient
ebs-service
"Returns the synchronous ElasticBlockStoreClient associated with
the specified compute service, or compute/*compute* as bound by with-compute-service."
[& [compute]]
(-> (or compute compute/*compute*)
.getContext .getProviderSpecificContext .getApi .getElasticBlockStoreServices))
(defn get-region
"Coerces the first parameter into a Region string; strings, keywords, and
NodeMetadata instances are acceptable arguments. An optional second argument
is returned if the first cannot be coerced into a region string.
Returns nil otherwise."
([v] (get-region v nil))
([v default-region]
(cond
(string? v) v
(keyword? v) (name v)
(instance? NodeMetadata v) (let [zone (compute/location v)]
; no easier way to go from zone -> region?
(if (> (.indexOf zone "-") -1)
(subs zone 0 (-> zone count dec))
zone))
:else default-region)))
(defn get-volume-id
"Returns a string volume ID taken from the given string, keyword, or Volume argument."
[v]
(cond
(instance? Volume v) (.getId #^Volume v)
(keyword? v) (name v)
(string? v) v
:else (throw (IllegalArgumentException.
(str "Can't obtain volume id from argument of type " (class v))))))
(defn volumes
"Returns a set of org.jclouds.ec2.domain.Volume instances corresponding to the
volumes in the specified region (defaulting to your account's default region).
e.g. (with-compute-service [compute] (volumes))
(with-compute-service [compute] (volumes :us-east-1 \"vol-6b218805\" ...))"
[& [region & volume-ids]]
(set
(.describeVolumesInRegion (ebs-service)
(get-region region)
(into-array String (map get-volume-id
(if (get-region region)
volume-ids
(when region (cons region volume-ids))))))))
(defn- as-string
[v]
(cond
(string? v) v
(keyword? v) (name v)
:else v))
(defn- get-string
[map key]
(as-string (get map key)))
(defn- as-int
[v]
(cond
(number? v) (int v)
(string? v) (Integer/parseInt v)
:else (throw (IllegalArgumentException.
(str "Don't know how to convert object of type " (class v) " to a string")))))
(defn- snapshot-options
[optmap]
(let [string-array #(let [v (% optmap)]
(into-array String (cond
(keyword? v) [(name v)]
(string? v) [v]
:else (map as-string v))))]
(-> (DescribeSnapshotsOptions.)
(.ownedBy (string-array :owner))
(.snapshotIds (string-array :ids))
(.restorableBy (string-array :restorable-by)))))
(defn snapshots
"Returns a set of org.jclouds.aws.ec2.domain.Snapshot instances that match
the criteria provided. Options include:
:region - region string, keyword, or NodeMetadata
:owner - AWS account id (or \"amazon\" or \"self\")
:restorable-by - AWS account id
Multiple values for each type of criteria can be provided by passing a seq
of the appropriate types as values.
(with-compute-service [compute]
(snapshots :owner \"self\")
(snapshots :region :us-west-1 :ids [\"snap-44b3ab2d\" \"snap-9e8821f7\"]))"
[& options]
(let [options (apply hash-map options)
region (:region options)
options (snapshot-options (dissoc options :region))]
(set
(.describeSnapshotsInRegion (ebs-service)
(get-region region)
(into-array DescribeSnapshotsOptions [options])))))
(defn create-snapshot
"Creates a snapshot of a volume in the specified region with an optional description.
If provided, the description must be < 255 characters in length. Returns the
org.jclouds.aws.ec2.domain.Snapshot object representing the created snapshot.
e.g. (with-compute-service [compute]
(create-snapshot some-volume-instance)
(create-snapshot :us-east-1 \"vol-1dbe6785\" nil)
(create-snapshot :us-east-1 \"vol-1dbe6785\" \"super-important data\"))"
([#^Volume volume] (create-snapshot volume nil))
([#^Volume volume description] (create-snapshot (.getRegion volume) (.getId volume) description))
([region volume-id description]
(.createSnapshotInRegion (ebs-service)
(get-region region)
(as-string volume-id)
(into-array CreateSnapshotOptions (when description
[(.withDescription (CreateSnapshotOptions.) description)])))))
(defn delete-snapshot
"Deletes a snapshot in the specified region.
e.g. (with-compute-service [compute]
(delete-snapshot :us-east-1 :snap-252310af)
(delete-snapshot :us-east-1 \"snap-242adf03\"))"
([#^Snapshot snapshot] (delete-snapshot (.getRegion snapshot) (.getId snapshot)))
([region snapshot-id]
(.deleteSnapshotInRegion (ebs-service)
(get-region region)
(as-string snapshot-id))))
(defn get-zone
[v]
(cond
(instance? AvailabilityZoneInfo v) (.getZone v)
(instance? NodeMetadata v) (compute/location #^NodeMetadata v)
(string? v) v
(keyword? v) (name v)
:else (throw (IllegalArgumentException.
(str "Can't obtain zone from argument of type " (class v))))))
(defn attach-volume
"Attaches a volume to an instance, returning the resulting org.jclouds.aws.ec2.domain.Attachment.
e.g. (with-compute-service [compute]
(attach-volume :us-east-1 \"i-a92358c1\" :vol-45228a6d \"/dev/sdh\")
(attach-volume some-node-instance :vol-45228a6d \"/dev/sdh\")
(attach-volume some-node-instance some-volume-instance \"/dev/sdh\"))"
([#^NodeMetadata node volume device]
(attach-volume node (.getProviderId node) (get-volume-id volume) device))
([region instance-id volume-id device]
(apply #(.attachVolumeInRegion (ebs-service)
(get-region region) % %2 %3)
(map as-string [volume-id instance-id device]))))
(defn detach-volume
"Detatches a volume from the instance to which it is currently attached.
The volume may be specified with a Volume instance, a string, or a keyword.
Providing a logical true value for the :force option will cause the volume
to be forcibly detached, regardless of whether it is in-use (mounted) or not.
If the volume is specified as a string or keyword, one of the following options
is additionally required:
:region - the region where the volume is allocated
:node - a node in the region where the volume is allocated
FYI: It appears that issuing a detatch-volume command while the volume in question is mounted
will cause the volume to be detatched immediately upon the volume beign unmounted."
[volume & options]
(let [options (apply hash-map options)
volume-id (get-volume-id volume)
region (get-region (if (instance? Volume volume)
(.getRegion volume)
(or (:region options) (:node options))))]
(when (not region)
(throw (IllegalArgumentException.
"Must specify volume's region via :region or :node options, or by providing a Volume instance.")))
(.detachVolumeInRegion (ebs-service)
region
volume-id
(boolean (:force options))
(into-array DetachVolumeOptions []))))
(defn create-volume
"Creates a new volume given a set of options:
- one of :zone (keyword, string, or AvailabilityZoneInfo) or :node (NodeMetadata)
- one or both of :snapshot (keyword, string, or Snapshot instance) or :size
(string, keyword, or number)
- :device (string or keyword) provided *only* when you want to attach the new volume to
the :node you specified!
Returns a vector of [created org.jclouds.ec2.domain.Volume,
optional org.jclouds.ec2.domain.Attachment]
Note that specifying :node instead of :zone will only attach the created volume
:device is also provided. Otherwise, the node is only used to obtain the desired
availability zone.
Note also that if :device and :node are specified, and the attach operation fails,
you will have \"leaked\" the newly-created volume
(volume creation and attachment cannot be done atomically).
e.g. (with-compute-service [compute]
(create-volume :zone :us-east-1a :size 250)
(create-volume :node node-instance :size 250)
(create-volume :node node-instance :size 250 :device \"/dev/sdj\")
(create-volume :zone :eu-west-1b :snapshot \"snap-252310af\")
(create-volume :zone :eu-west-1b :snapshot snapshot-instance)
(create-volume :zone :eu-west-1b :snapshot \"snap-252310af\" :size :1024))"
[& options]
(when (-> options count odd?)
(throw (IllegalArgumentException. "Must provide key-value pairs, e.g. :zone :us-east-1d :size 200")))
(let [options (apply hash-map options)
snapshot (get-string options :snapshot)
snapshot (if (snapshot? snapshot) (.getId snapshot) snapshot)
size (-?> (get-string options :size) as-int)
#^NodeMetadata node (:node options)
zone (or node (get-string options :zone))
zone (if zone
(get-zone zone)
(throw (IllegalArgumentException. "Must supply a :zone or :node option.")))
ebs (ebs-service)]
(when (and (:device options) (not node))
(throw (IllegalArgumentException. "Cannot create and attach new volume; no :node specified")))
(let [new-volume (cond
(and snapshot size) (.createVolumeFromSnapshotInAvailabilityZone ebs zone size snapshot)
snapshot (.createVolumeFromSnapshotInAvailabilityZone ebs zone snapshot)
size (.createVolumeInAvailabilityZone ebs zone size)
:else (throw (IllegalArgumentException. "Must supply :size and/or :snapshot options.")))]
[new-volume (when (:device options)
(attach-volume node new-volume (as-string (:device options))))])))
(defn delete-volume
"Deletes a volume in the specified region.
e.g. (with-compute-service [compute]
(delete-volume :us-east-1 :vol-45228a6d)
(delete-volume :us-east-1 \"vol-052b846c\"))"
([#^Volume volume]
(delete-volume (.getRegion volume) (.getId volume)))
([region volume-id]
(.deleteVolumeInRegion (ebs-service)
(get-region region)
(as-string volume-id))))
(defn status
"Returns the status of the given entity; works for Volumes and Snapshots."
[k]
(.getStatus k))
(defn status-available?
[#^Volume v]
(= Volume$Status/AVAILABLE (status v)))
(defn status-creating?
[#^Volume v]
(= Volume$Status/CREATING (status v)))
(defn status-deleting?
[#^Volume v]
(= Volume$Status/DELETING (status v)))
(defn status-in-use?
[#^Volume v]
(= Volume$Status/IN_USE (status v)))
(defn status-completed?
[#^Snapshot s]
(= Snapshot$Status/COMPLETED (status s)))
(defn status-error?
[#^Snapshot s]
(= Snapshot$Status/ERROR (status s)))
(defn status-pending?
[#^Snapshot s]
(= Snapshot$Status/PENDING (status s)))

View File

@ -1,83 +0,0 @@
;
; Licensed to jclouds, Inc. (jclouds) under one or more
; contributor license agreements. See the NOTICE file
; distributed with this work for additional information
; regarding copyright ownership. jclouds licenses this file
; to you under the Apache License, Version 2.0 (the
; "License"); you may not use this file except in compliance
; with the License. You may obtain a copy of the License at
;
; http://www.apache.org/licenses/LICENSE-2.0
;
; Unless required by applicable law or agreed to in writing,
; software distributed under the License is distributed on an
; "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
; KIND, either express or implied. See the License for the
; specific language governing permissions and limitations
; under the License.
;
(ns
#^{:author "Chas Emerick, cemerick@snowtide.com"
:doc "A clojure binding for the jclouds AWS elastic IP address interface."}
org.jclouds.ec2.elastic-ip
(:require (org.jclouds [compute :as compute])
[org.jclouds.ec2.ebs :as ebs])
(:import org.jclouds.compute.domain.NodeMetadata
(org.jclouds.ec2.domain PublicIpInstanceIdPair)))
(defn #^org.jclouds.ec2.services.ElasticIPAddressClient
eip-service
"Returns the synchronous ElasticIPAddressClient associated with
the specified compute service, or compute/*compute* as bound by with-compute-service."
[& [compute]]
(-> (or compute compute/*compute*)
.getContext .getProviderSpecificContext .getApi .getElasticIPAddressServices))
(defn allocate
"Claims a new elastic IP address within the (optionally) specified region for your account.
Region may be a string, keyword, or a node from which the region
is inferred. Returns the IP address as a string."
([] (allocate nil))
([region]
(.allocateAddressInRegion (eip-service) (ebs/get-region region))))
(defn associate
"Associates an elastic IP address with a node."
([#^NodeMetadata node public-ip]
(associate node public-ip (.getProviderId node)))
([region public-ip instance-id]
(.associateAddressInRegion (eip-service)
(ebs/get-region region)
public-ip
instance-id)))
(defn addresses
"Returns a map of elastic IP addresses to maps with slots:
:region - the region (string/keyword/NodeMetadata) the IP address is allocated within
:node-id - the ID of the instance with which the IP address is associated (optional)
You may optionally specify which IP addresses you would like to query."
([] (addresses nil))
([region & public-ips]
(into {} (for [#^PublicIpInstanceIdPair pair (.describeAddressesInRegion (eip-service)
(ebs/get-region region)
(into-array String public-ips))]
[(.getPublicIp pair) (merge {:region (.getRegion pair)}
(when (.getInstanceId pair) {:node-id (.getInstanceId pair)}))]))))
(defn dissociate
"Dissociates an elastic IP address from the node with which it is currently associated."
[region public-ip]
(.disassociateAddressInRegion (eip-service)
(ebs/get-region region)
public-ip))
(defn release
"Disclaims an elastic IP address from your account."
([public-ip] (release nil public-ip))
([region public-ip]
(.releaseAddressInRegion (eip-service)
(ebs/get-region region)
public-ip)))

View File

@ -24,10 +24,11 @@ import static com.google.common.collect.Iterables.transform;
import static org.jclouds.util.Preconditions2.checkNotEmpty; import static org.jclouds.util.Preconditions2.checkNotEmpty;
import java.util.Map; import java.util.Map;
import java.util.Set;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.atomic.AtomicReference;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Named; import javax.inject.Named;
@ -71,8 +72,8 @@ import com.google.common.base.Predicate;
import com.google.common.base.Supplier; import com.google.common.base.Supplier;
import com.google.common.cache.LoadingCache; import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableMultimap; import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableMultimap.Builder; import com.google.common.collect.ImmutableMultimap.Builder;
import com.google.common.collect.ImmutableSet;
/** /**
* @author Adrian Cole * @author Adrian Cole
@ -91,9 +92,9 @@ public class EC2ComputeService extends BaseComputeService {
RebootNodeStrategy rebootNodeStrategy, DestroyNodeStrategy destroyNodeStrategy, RebootNodeStrategy rebootNodeStrategy, DestroyNodeStrategy destroyNodeStrategy,
ResumeNodeStrategy startNodeStrategy, SuspendNodeStrategy stopNodeStrategy, ResumeNodeStrategy startNodeStrategy, SuspendNodeStrategy stopNodeStrategy,
Provider<TemplateBuilder> templateBuilderProvider, Provider<TemplateOptions> templateOptionsProvider, Provider<TemplateBuilder> templateBuilderProvider, Provider<TemplateOptions> templateOptionsProvider,
@Named("NODE_RUNNING") Predicate<NodeMetadata> nodeRunning, @Named("NODE_RUNNING") Predicate<AtomicReference<NodeMetadata>> nodeRunning,
@Named("NODE_TERMINATED") Predicate<NodeMetadata> nodeTerminated, @Named("NODE_TERMINATED") Predicate<AtomicReference<NodeMetadata>> nodeTerminated,
@Named("NODE_SUSPENDED") Predicate<NodeMetadata> nodeSuspended, @Named("NODE_SUSPENDED") Predicate<AtomicReference<NodeMetadata>> nodeSuspended,
InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory, InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory,
RunScriptOnNode.Factory runScriptOnNodeFactory, InitAdminAccess initAdminAccess, RunScriptOnNode.Factory runScriptOnNodeFactory, InitAdminAccess initAdminAccess,
PersistNodeCredentials persistNodeCredentials, Timeouts timeouts, PersistNodeCredentials persistNodeCredentials, Timeouts timeouts,

View File

@ -26,6 +26,7 @@ import static org.jclouds.ec2.compute.util.EC2ComputeUtils.getZoneFromLocationOr
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.Future; import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicReference;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.inject.Inject; import javax.inject.Inject;
@ -80,7 +81,7 @@ public class EC2CreateNodesInGroupThenAddToSet implements CreateNodesInGroupThen
@VisibleForTesting @VisibleForTesting
final EC2Client client; final EC2Client client;
@VisibleForTesting @VisibleForTesting
final Predicate<NodeMetadata> nodeRunning; final Predicate<AtomicReference<NodeMetadata>> nodeRunning;
@VisibleForTesting @VisibleForTesting
final LoadingCache<RegionAndName, String> elasticIpCache; final LoadingCache<RegionAndName, String> elasticIpCache;
@VisibleForTesting @VisibleForTesting
@ -101,7 +102,7 @@ public class EC2CreateNodesInGroupThenAddToSet implements CreateNodesInGroupThen
EC2Client client, EC2Client client,
@Named("ELASTICIP") @Named("ELASTICIP")
LoadingCache<RegionAndName, String> elasticIpCache, LoadingCache<RegionAndName, String> elasticIpCache,
@Named("NODE_RUNNING") Predicate<NodeMetadata> nodeRunning, @Named("NODE_RUNNING") Predicate<AtomicReference<NodeMetadata>> nodeRunning,
Provider<TemplateBuilder> templateBuilderProvider, Provider<TemplateBuilder> templateBuilderProvider,
CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions createKeyPairAndSecurityGroupsAsNeededAndReturncustomize, CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions createKeyPairAndSecurityGroupsAsNeededAndReturncustomize,
InstancePresent instancePresent, Function<RunningInstance, NodeMetadata> runningInstanceToNodeMetadata, InstancePresent instancePresent, Function<RunningInstance, NodeMetadata> runningInstanceToNodeMetadata,
@ -197,7 +198,8 @@ public class EC2CreateNodesInGroupThenAddToSet implements CreateNodesInGroupThen
// block until instance is running // block until instance is running
logger.debug(">> awaiting status running instance(%s)", coordinates); logger.debug(">> awaiting status running instance(%s)", coordinates);
nodeRunning.apply(runningInstanceToNodeMetadata.apply(startedInstance)); AtomicReference<NodeMetadata> node = new AtomicReference<NodeMetadata>(runningInstanceToNodeMetadata.apply(startedInstance));
nodeRunning.apply(node);
logger.trace("<< running instance(%s)", coordinates); logger.trace("<< running instance(%s)", coordinates);
logger.debug(">> associating elastic IP %s to instance %s", ip, coordinates); logger.debug(">> associating elastic IP %s to instance %s", ip, coordinates);
client.getElasticIPAddressServices().associateAddressInRegion(region, ip, id); client.getElasticIPAddressServices().associateAddressInRegion(region, ip, id);

View File

@ -40,6 +40,8 @@ import org.jclouds.domain.LoginCredentials;
import org.jclouds.ec2.domain.Attachment; import org.jclouds.ec2.domain.Attachment;
import org.jclouds.ec2.domain.BlockDevice; import org.jclouds.ec2.domain.BlockDevice;
import org.jclouds.ec2.domain.Image; import org.jclouds.ec2.domain.Image;
import org.jclouds.ec2.domain.Image.Architecture;
import org.jclouds.ec2.domain.Image.ImageType;
import org.jclouds.ec2.domain.InstanceState; import org.jclouds.ec2.domain.InstanceState;
import org.jclouds.ec2.domain.InstanceType; import org.jclouds.ec2.domain.InstanceType;
import org.jclouds.ec2.domain.IpProtocol; import org.jclouds.ec2.domain.IpProtocol;
@ -49,8 +51,6 @@ import org.jclouds.ec2.domain.RootDeviceType;
import org.jclouds.ec2.domain.RunningInstance; import org.jclouds.ec2.domain.RunningInstance;
import org.jclouds.ec2.domain.Snapshot; import org.jclouds.ec2.domain.Snapshot;
import org.jclouds.ec2.domain.Volume; import org.jclouds.ec2.domain.Volume;
import org.jclouds.ec2.domain.Image.Architecture;
import org.jclouds.ec2.domain.Image.ImageType;
import org.jclouds.ec2.domain.Volume.InstanceInitiatedShutdownBehavior; import org.jclouds.ec2.domain.Volume.InstanceInitiatedShutdownBehavior;
import org.jclouds.ec2.predicates.InstanceStateRunning; import org.jclouds.ec2.predicates.InstanceStateRunning;
import org.jclouds.ec2.predicates.InstanceStateStopped; import org.jclouds.ec2.predicates.InstanceStateStopped;
@ -65,9 +65,8 @@ import org.jclouds.net.IPSocket;
import org.jclouds.predicates.RetryablePredicate; import org.jclouds.predicates.RetryablePredicate;
import org.jclouds.predicates.SocketOpen; import org.jclouds.predicates.SocketOpen;
import org.jclouds.rest.RestContextFactory; import org.jclouds.rest.RestContextFactory;
import org.jclouds.scriptbuilder.InitBuilder; import org.jclouds.scriptbuilder.InitScript;
import org.jclouds.scriptbuilder.domain.OsFamily; import org.jclouds.scriptbuilder.domain.OsFamily;
import org.jclouds.scriptbuilder.domain.Statement;
import org.jclouds.scriptbuilder.domain.Statements; import org.jclouds.scriptbuilder.domain.Statements;
import org.jclouds.ssh.SshClient; import org.jclouds.ssh.SshClient;
import org.jclouds.ssh.SshException; import org.jclouds.ssh.SshException;
@ -77,7 +76,6 @@ import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
@ -256,12 +254,12 @@ public class EBSBootEC2ClientLiveTest extends BaseVersionedServiceLiveTest {
@BeforeTest @BeforeTest
void makeScript() { void makeScript() {
mkEbsBoot = new InitBuilder( mkEbsBoot = InitScript.builder()
"mkebsboot",// name of the script .name("mkebsboot")
"/tmp",// working directory .home("/tmp")
"/tmp/logs",// location of stdout.log and stderr.log .logDir("/tmp/logs")
ImmutableMap.of("imageDir", "/mnt/tmp", "ebsDevice", "/dev/sdh", "ebsMountPoint", "/mnt/ebs"), .exportVariables(ImmutableMap.of("imageDir", "/mnt/tmp", "ebsDevice", "/dev/sdh", "ebsMountPoint", "/mnt/ebs"))
ImmutableList.<Statement> of(Statements .run(Statements
.interpret( .interpret(
"echo creating a filesystem and mounting the ebs volume", "echo creating a filesystem and mounting the ebs volume",
"{md} {varl}IMAGE_DIR{varr} {varl}EBS_MOUNT_POINT{varr}", "{md} {varl}IMAGE_DIR{varr} {varl}EBS_MOUNT_POINT{varr}",
@ -275,7 +273,7 @@ public class EBSBootEC2ClientLiveTest extends BaseVersionedServiceLiveTest {
"echo copying the local working copy to the ebs mount", "{cd} {varl}IMAGE_DIR{varr}", "echo copying the local working copy to the ebs mount", "{cd} {varl}IMAGE_DIR{varr}",
"tar -cSf - * | tar xf - -C {varl}EBS_MOUNT_POINT{varr}", "echo size of ebs", "tar -cSf - * | tar xf - -C {varl}EBS_MOUNT_POINT{varr}", "echo size of ebs",
"du -sk {varl}EBS_MOUNT_POINT{varr}", "echo size of source", "du -sk {varl}IMAGE_DIR{varr}", "du -sk {varl}EBS_MOUNT_POINT{varr}", "echo size of source", "du -sk {varl}IMAGE_DIR{varr}",
"rm -rf {varl}IMAGE_DIR{varr}/*", "umount {varl}EBS_MOUNT_POINT{varr}", "echo " + SCRIPT_END))) "rm -rf {varl}IMAGE_DIR{varr}/*", "umount {varl}EBS_MOUNT_POINT{varr}", "echo " + SCRIPT_END)).build()
.render(OsFamily.UNIX); .render(OsFamily.UNIX);
} }

View File

@ -18,12 +18,12 @@
*/ */
package org.jclouds.ec2.compute.strategy; package org.jclouds.ec2.compute.strategy;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.eq; import static org.easymock.EasyMock.eq;
import static org.easymock.EasyMock.expect; import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import static org.easymock.EasyMock.reportMatcher; import static org.easymock.EasyMock.reportMatcher;
import static org.easymock.classextension.EasyMock.createMock; import static org.easymock.EasyMock.verify;
import static org.easymock.classextension.EasyMock.replay;
import static org.easymock.classextension.EasyMock.verify;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
@ -33,8 +33,12 @@ import org.jclouds.compute.config.CustomizationResponse;
import org.jclouds.compute.domain.Hardware; import org.jclouds.compute.domain.Hardware;
import org.jclouds.compute.domain.Image; import org.jclouds.compute.domain.Image;
import org.jclouds.compute.domain.NodeMetadata; import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.domain.NodeMetadataBuilder;
import org.jclouds.compute.domain.NodeState;
import org.jclouds.compute.domain.Template; import org.jclouds.compute.domain.Template;
import org.jclouds.compute.domain.TemplateBuilder; import org.jclouds.compute.domain.TemplateBuilder;
import org.jclouds.compute.predicates.AtomicNodeRunning;
import org.jclouds.compute.strategy.GetNodeMetadataStrategy;
import org.jclouds.compute.util.ComputeUtils; import org.jclouds.compute.util.ComputeUtils;
import org.jclouds.domain.Credentials; import org.jclouds.domain.Credentials;
import org.jclouds.domain.Location; import org.jclouds.domain.Location;
@ -50,9 +54,9 @@ import org.jclouds.ec2.domain.RunningInstance;
import org.jclouds.ec2.options.RunInstancesOptions; import org.jclouds.ec2.options.RunInstancesOptions;
import org.jclouds.ec2.services.ElasticIPAddressClient; import org.jclouds.ec2.services.ElasticIPAddressClient;
import org.jclouds.ec2.services.InstanceClient; import org.jclouds.ec2.services.InstanceClient;
import org.testng.Assert;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.base.Predicate;
import com.google.common.cache.LoadingCache; import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
@ -73,17 +77,19 @@ public class EC2CreateNodesInGroupThenAddToSetTest {
String imageId = "ami1"; String imageId = "ami1";
String instanceCreatedId = "instance1"; String instanceCreatedId = "instance1";
NodeMetadata nodeMetadata = new NodeMetadataBuilder().id(region + "/" + instanceCreatedId)
.providerId(instanceCreatedId).state(NodeState.RUNNING).build();
// setup mocks // setup mocks
TemplateBuilder templateBuilder = createMock(TemplateBuilder.class); TemplateBuilder templateBuilder = createMock(TemplateBuilder.class);
EC2CreateNodesInGroupThenAddToSet strategy = setupStrategy(templateBuilder); EC2CreateNodesInGroupThenAddToSet strategy = setupStrategy(templateBuilder, nodeMetadata);
InputParams input = new InputParams(location); InputParams input = new InputParams(location);
InstanceClient instanceClient = createMock(InstanceClient.class); InstanceClient instanceClient = createMock(InstanceClient.class);
ElasticIPAddressClient ipClient = createMock(ElasticIPAddressClient.class); ElasticIPAddressClient ipClient = createMock(ElasticIPAddressClient.class);
RunInstancesOptions ec2Options = createMock(RunInstancesOptions.class); RunInstancesOptions ec2Options = createMock(RunInstancesOptions.class);
RunningInstance instance = createMock(RunningInstance.class); RunningInstance instance = createMock(RunningInstance.class);
Reservation<? extends RunningInstance> reservation = new Reservation<RunningInstance>(region, ImmutableSet Reservation<? extends RunningInstance> reservation = new Reservation<RunningInstance>(region,
.<String> of(), ImmutableSet.<RunningInstance> of(instance), "ownerId", "requesterId", "reservationId"); ImmutableSet.<String> of(), ImmutableSet.<RunningInstance> of(instance), "ownerId", "requesterId",
NodeMetadata nodeMetadata = createMock(NodeMetadata.class); "reservationId");
// enable auto-allocation // enable auto-allocation
strategy.autoAllocateElasticIps = true; strategy.autoAllocateElasticIps = true;
@ -93,8 +99,8 @@ public class EC2CreateNodesInGroupThenAddToSetTest {
expect(templateBuilder.build()).andReturn(input.template); expect(templateBuilder.build()).andReturn(input.template);
expect(strategy.client.getInstanceServices()).andReturn(instanceClient).atLeastOnce(); expect(strategy.client.getInstanceServices()).andReturn(instanceClient).atLeastOnce();
expect( expect(
strategy.createKeyPairAndSecurityGroupsAsNeededAndReturncustomize.execute(region, input.tag, strategy.createKeyPairAndSecurityGroupsAsNeededAndReturncustomize
input.template)).andReturn(ec2Options); .execute(region, input.tag, input.template)).andReturn(ec2Options);
expect(strategy.client.getElasticIPAddressServices()).andReturn(ipClient).atLeastOnce(); expect(strategy.client.getElasticIPAddressServices()).andReturn(ipClient).atLeastOnce();
expect(input.template.getLocation()).andReturn(input.location).atLeastOnce(); expect(input.template.getLocation()).andReturn(input.location).atLeastOnce();
@ -104,7 +110,6 @@ public class EC2CreateNodesInGroupThenAddToSetTest {
// differences when ip allocation // differences when ip allocation
expect(ipClient.allocateAddressInRegion(region)).andReturn("1.1.1.1"); expect(ipClient.allocateAddressInRegion(region)).andReturn("1.1.1.1");
expect(strategy.runningInstanceToNodeMetadata.apply(instance)).andReturn(nodeMetadata).atLeastOnce(); expect(strategy.runningInstanceToNodeMetadata.apply(instance)).andReturn(nodeMetadata).atLeastOnce();
expect(strategy.nodeRunning.apply(nodeMetadata)).andReturn(true);
ipClient.associateAddressInRegion(region, "1.1.1.1", instanceCreatedId); ipClient.associateAddressInRegion(region, "1.1.1.1", instanceCreatedId);
strategy.elasticIpCache.put(new RegionAndName(region, instanceCreatedId), "1.1.1.1"); strategy.elasticIpCache.put(new RegionAndName(region, instanceCreatedId), "1.1.1.1");
@ -122,8 +127,8 @@ public class EC2CreateNodesInGroupThenAddToSetTest {
expect( expect(
strategy.utils.customizeNodesAndAddToGoodMapOrPutExceptionIntoBadMap(eq(input.options), strategy.utils.customizeNodesAndAddToGoodMapOrPutExceptionIntoBadMap(eq(input.options),
containsNodeMetadata(nodeMetadata), eq(input.nodes), eq(input.badNodes), containsNodeMetadata(nodeMetadata), eq(input.nodes), eq(input.badNodes), eq(input.customization)))
eq(input.customization))).andReturn(null); .andReturn(null);
// replay mocks // replay mocks
replay(templateBuilder); replay(templateBuilder);
@ -131,7 +136,6 @@ public class EC2CreateNodesInGroupThenAddToSetTest {
replay(ipClient); replay(ipClient);
replay(ec2Options); replay(ec2Options);
replay(instance); replay(instance);
replay(nodeMetadata);
input.replayMe(); input.replayMe();
replayStrategy(strategy); replayStrategy(strategy);
@ -144,7 +148,6 @@ public class EC2CreateNodesInGroupThenAddToSetTest {
verify(ipClient); verify(ipClient);
verify(ec2Options); verify(ec2Options);
verify(instance); verify(instance);
verify(nodeMetadata);
input.verifyMe(); input.verifyMe();
verifyStrategy(strategy); verifyStrategy(strategy);
} }
@ -184,24 +187,27 @@ public class EC2CreateNodesInGroupThenAddToSetTest {
private void assertRegionAndZoneForLocation(Location location, String region, String zone) { private void assertRegionAndZoneForLocation(Location location, String region, String zone) {
String imageId = "ami1"; String imageId = "ami1";
String instanceCreatedId = "instance1"; String instanceCreatedId = "instance1";
NodeMetadata nodeMetadata = new NodeMetadataBuilder().id(region + "/" + instanceCreatedId)
.providerId(instanceCreatedId).state(NodeState.RUNNING).build();
// setup mocks // setup mocks
TemplateBuilder templateBuilder = createMock(TemplateBuilder.class); TemplateBuilder templateBuilder = createMock(TemplateBuilder.class);
EC2CreateNodesInGroupThenAddToSet strategy = setupStrategy(templateBuilder); EC2CreateNodesInGroupThenAddToSet strategy = setupStrategy(templateBuilder, nodeMetadata);
InputParams input = new InputParams(location); InputParams input = new InputParams(location);
InstanceClient instanceClient = createMock(InstanceClient.class); InstanceClient instanceClient = createMock(InstanceClient.class);
RunInstancesOptions ec2Options = createMock(RunInstancesOptions.class); RunInstancesOptions ec2Options = createMock(RunInstancesOptions.class);
RunningInstance instance = createMock(RunningInstance.class); RunningInstance instance = createMock(RunningInstance.class);
Reservation<? extends RunningInstance> reservation = new Reservation<RunningInstance>(region, ImmutableSet Reservation<? extends RunningInstance> reservation = new Reservation<RunningInstance>(region,
.<String> of(), ImmutableSet.<RunningInstance> of(instance), "ownerId", "requesterId", "reservationId"); ImmutableSet.<String> of(), ImmutableSet.<RunningInstance> of(instance), "ownerId", "requesterId",
NodeMetadata nodeMetadata = createMock(NodeMetadata.class); "reservationId");
// setup expectations // setup expectations
expect(templateBuilder.fromTemplate(input.template)).andReturn(templateBuilder); expect(templateBuilder.fromTemplate(input.template)).andReturn(templateBuilder);
expect(templateBuilder.build()).andReturn(input.template); expect(templateBuilder.build()).andReturn(input.template);
expect(strategy.client.getInstanceServices()).andReturn(instanceClient).atLeastOnce(); expect(strategy.client.getInstanceServices()).andReturn(instanceClient).atLeastOnce();
expect( expect(
strategy.createKeyPairAndSecurityGroupsAsNeededAndReturncustomize.execute(region, input.tag, strategy.createKeyPairAndSecurityGroupsAsNeededAndReturncustomize
input.template)).andReturn(ec2Options); .execute(region, input.tag, input.template)).andReturn(ec2Options);
expect(input.template.getLocation()).andReturn(input.location).atLeastOnce(); expect(input.template.getLocation()).andReturn(input.location).atLeastOnce();
expect(input.template.getImage()).andReturn(input.image).atLeastOnce(); expect(input.template.getImage()).andReturn(input.image).atLeastOnce();
expect(input.image.getProviderId()).andReturn(imageId).atLeastOnce(); expect(input.image.getProviderId()).andReturn(imageId).atLeastOnce();
@ -220,15 +226,14 @@ public class EC2CreateNodesInGroupThenAddToSetTest {
expect(strategy.runningInstanceToNodeMetadata.apply(instance)).andReturn(nodeMetadata); expect(strategy.runningInstanceToNodeMetadata.apply(instance)).andReturn(nodeMetadata);
expect( expect(
strategy.utils.customizeNodesAndAddToGoodMapOrPutExceptionIntoBadMap(eq(input.options), strategy.utils.customizeNodesAndAddToGoodMapOrPutExceptionIntoBadMap(eq(input.options),
containsNodeMetadata(nodeMetadata), eq(input.nodes), eq(input.badNodes), containsNodeMetadata(nodeMetadata), eq(input.nodes), eq(input.badNodes), eq(input.customization)))
eq(input.customization))).andReturn(null); .andReturn(null);
// replay mocks // replay mocks
replay(templateBuilder); replay(templateBuilder);
replay(instanceClient); replay(instanceClient);
replay(ec2Options); replay(ec2Options);
replay(instance); replay(instance);
replay(nodeMetadata);
input.replayMe(); input.replayMe();
replayStrategy(strategy); replayStrategy(strategy);
@ -240,16 +245,16 @@ public class EC2CreateNodesInGroupThenAddToSetTest {
verify(instanceClient); verify(instanceClient);
verify(ec2Options); verify(ec2Options);
verify(instance); verify(instance);
verify(nodeMetadata);
input.verifyMe(); input.verifyMe();
verifyStrategy(strategy); verifyStrategy(strategy);
} }
private static final Location REGION_AP_SOUTHEAST_1 = new LocationBuilder().scope(LocationScope.REGION).id( private static final Location REGION_AP_SOUTHEAST_1 = new LocationBuilder().scope(LocationScope.REGION)
"ap-southeast-1").description("ap-southeast-1").parent( .id("ap-southeast-1").description("ap-southeast-1")
new LocationBuilder().scope(LocationScope.PROVIDER).id("aws-ec2").description("aws-ec2").build()).build(); .parent(new LocationBuilder().scope(LocationScope.PROVIDER).id("aws-ec2").description("aws-ec2").build())
private static final Location ZONE_AP_SOUTHEAST_1A = new LocationBuilder().scope(LocationScope.ZONE).id( .build();
"ap-southeast-1a").description("ap-southeast-1a").parent(REGION_AP_SOUTHEAST_1).build(); private static final Location ZONE_AP_SOUTHEAST_1A = new LocationBuilder().scope(LocationScope.ZONE)
.id("ap-southeast-1a").description("ap-southeast-1a").parent(REGION_AP_SOUTHEAST_1).build();
// ///////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@ -293,7 +298,6 @@ public class EC2CreateNodesInGroupThenAddToSetTest {
private void verifyStrategy(EC2CreateNodesInGroupThenAddToSet strategy) { private void verifyStrategy(EC2CreateNodesInGroupThenAddToSet strategy) {
verify(strategy.createKeyPairAndSecurityGroupsAsNeededAndReturncustomize); verify(strategy.createKeyPairAndSecurityGroupsAsNeededAndReturncustomize);
verify(strategy.client); verify(strategy.client);
verify(strategy.nodeRunning);
verify(strategy.elasticIpCache); verify(strategy.elasticIpCache);
verify(strategy.instancePresent); verify(strategy.instancePresent);
verify(strategy.runningInstanceToNodeMetadata); verify(strategy.runningInstanceToNodeMetadata);
@ -303,18 +307,26 @@ public class EC2CreateNodesInGroupThenAddToSetTest {
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private EC2CreateNodesInGroupThenAddToSet setupStrategy(TemplateBuilder template) { private EC2CreateNodesInGroupThenAddToSet setupStrategy(TemplateBuilder template, final NodeMetadata node) {
EC2Client client = createMock(EC2Client.class); EC2Client client = createMock(EC2Client.class);
CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions createKeyPairAndSecurityGroupsAsNeededAndReturncustomize = createMock(CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions.class); CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions createKeyPairAndSecurityGroupsAsNeededAndReturncustomize = createMock(CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions.class);
InstancePresent instancePresent = createMock(InstancePresent.class); InstancePresent instancePresent = createMock(InstancePresent.class);
RunningInstanceToNodeMetadata runningInstanceToNodeMetadata = createMock(RunningInstanceToNodeMetadata.class); RunningInstanceToNodeMetadata runningInstanceToNodeMetadata = createMock(RunningInstanceToNodeMetadata.class);
LoadingCache<RunningInstance, Credentials> instanceToCredentials = createMock(LoadingCache.class); LoadingCache<RunningInstance, Credentials> instanceToCredentials = createMock(LoadingCache.class);
LoadingCache<RegionAndName, String> elasticIpCache = createMock(LoadingCache.class); LoadingCache<RegionAndName, String> elasticIpCache = createMock(LoadingCache.class);
Predicate<NodeMetadata> nodeRunning = createMock(Predicate.class); GetNodeMetadataStrategy nodeRunning = new GetNodeMetadataStrategy(){
@Override
public NodeMetadata getNode(String input) {
Assert.assertEquals(input, node.getId());
return node;
}
};
Map<String, Credentials> credentialStore = createMock(Map.class); Map<String, Credentials> credentialStore = createMock(Map.class);
ComputeUtils utils = createMock(ComputeUtils.class); ComputeUtils utils = createMock(ComputeUtils.class);
return new EC2CreateNodesInGroupThenAddToSet(client, elasticIpCache, nodeRunning, Providers return new EC2CreateNodesInGroupThenAddToSet(client, elasticIpCache, new AtomicNodeRunning(nodeRunning),
.<TemplateBuilder> of(template), createKeyPairAndSecurityGroupsAsNeededAndReturncustomize, Providers.<TemplateBuilder> of(template), createKeyPairAndSecurityGroupsAsNeededAndReturncustomize,
instancePresent, runningInstanceToNodeMetadata, instanceToCredentials, credentialStore, utils); instancePresent, runningInstanceToNodeMetadata, instanceToCredentials, credentialStore, utils);
} }
@ -322,7 +334,6 @@ public class EC2CreateNodesInGroupThenAddToSetTest {
replay(strategy.createKeyPairAndSecurityGroupsAsNeededAndReturncustomize); replay(strategy.createKeyPairAndSecurityGroupsAsNeededAndReturncustomize);
replay(strategy.client); replay(strategy.client);
replay(strategy.elasticIpCache); replay(strategy.elasticIpCache);
replay(strategy.nodeRunning);
replay(strategy.instancePresent); replay(strategy.instancePresent);
replay(strategy.runningInstanceToNodeMetadata); replay(strategy.runningInstanceToNodeMetadata);
replay(strategy.instanceToCredentials); replay(strategy.instanceToCredentials);

View File

@ -133,11 +133,11 @@
<configuration> <configuration>
<instructions> <instructions>
<Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName> <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
<Export-Package>org.jclouds.elasticstack.*;version="${project.version}"</Export-Package> <Export-Package>org.jclouds.elasticstack*;version="${project.version}"</Export-Package>
<Import-Package> <Import-Package>
org.jclouds.compute.internal;version="${project.version}", org.jclouds.compute.internal;version="${project.version}",
org.jclouds.rest.internal;version="${project.version}", org.jclouds.rest.internal;version="${project.version}",
org.jclouds.*;version="${project.version}", org.jclouds*;version="${project.version}",
* *
</Import-Package> </Import-Package>
</instructions> </instructions>

View File

@ -128,11 +128,11 @@
<configuration> <configuration>
<instructions> <instructions>
<Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName> <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
<Export-Package>org.jclouds.eucalyptus.*;version="${project.version}"</Export-Package> <Export-Package>org.jclouds.eucalyptus*;version="${project.version}"</Export-Package>
<Import-Package> <Import-Package>
org.jclouds.compute.internal;version="${project.version}", org.jclouds.compute.internal;version="${project.version}",
org.jclouds.rest.internal;version="${project.version}", org.jclouds.rest.internal;version="${project.version}",
org.jclouds.*;version="${project.version}", org.jclouds*;version="${project.version}",
* *
</Import-Package> </Import-Package>
</instructions> </instructions>

View File

@ -106,8 +106,8 @@
<configuration> <configuration>
<instructions> <instructions>
<Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName> <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
<Export-Package>org.jclouds.filesystem.*;version="${project.version}"</Export-Package> <Export-Package>org.jclouds.filesystem*;version="${project.version}"</Export-Package>
<Import-Package>org.jclouds.*;version="${project.version}",*</Import-Package> <Import-Package>org.jclouds*;version="${project.version}",*</Import-Package>
</instructions> </instructions>
</configuration> </configuration>
</plugin> </plugin>

View File

@ -137,11 +137,11 @@
<configuration> <configuration>
<instructions> <instructions>
<Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName> <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
<Export-Package>org.jclouds.openstack.nova.*;version="${project.version}"</Export-Package> <Export-Package>org.jclouds.openstack.nova*;version="${project.version}"</Export-Package>
<Import-Package> <Import-Package>
org.jclouds.compute.internal;version="${project.version}", org.jclouds.compute.internal;version="${project.version}",
org.jclouds.rest.internal;version="${project.version}", org.jclouds.rest.internal;version="${project.version}",
org.jclouds.*;version="${project.version}", org.jclouds*;version="${project.version}",
* *
</Import-Package> </Import-Package>
</instructions> </instructions>

View File

@ -135,7 +135,7 @@ public class ServerToNodeMetadata implements Function<Server, NodeMetadata> {
try { try {
return Iterables.find(images.get(), new FindImageForServer(from)); return Iterables.find(images.get(), new FindImageForServer(from));
} catch (NoSuchElementException e) { } catch (NoSuchElementException e) {
logger.warn("could not find a matching image for server %s in location %s", from, location); logger.warn("could not find a matching image for server %s in location %s", from, location.get());
} }
return null; return null;
} }

View File

@ -131,8 +131,8 @@
<configuration> <configuration>
<instructions> <instructions>
<Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName> <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
<Export-Package>org.jclouds.s3.*;version="${project.version}"</Export-Package> <Export-Package>org.jclouds.s3*;version="${project.version}"</Export-Package>
<Import-Package>org.jclouds.*;version="${project.version}",*</Import-Package> <Import-Package>org.jclouds*;version="${project.version}",*</Import-Package>
</instructions> </instructions>
</configuration> </configuration>
</plugin> </plugin>

View File

@ -131,8 +131,8 @@
<configuration> <configuration>
<instructions> <instructions>
<Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName> <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
<Export-Package>org.jclouds.openstack.swift.*;version="${project.version}"</Export-Package> <Export-Package>org.jclouds.openstack.swift*;version="${project.version}"</Export-Package>
<Import-Package>org.jclouds.*;version="${project.version}",*</Import-Package> <Import-Package>org.jclouds*;version="${project.version}",*</Import-Package>
</instructions> </instructions>
</configuration> </configuration>
</plugin> </plugin>

View File

@ -131,11 +131,11 @@
<configuration> <configuration>
<instructions> <instructions>
<Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName> <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
<Export-Package>org.jclouds.vcloud.*;version="${project.version}"</Export-Package> <Export-Package>org.jclouds.vcloud*;version="${project.version}"</Export-Package>
<Import-Package> <Import-Package>
org.jclouds.compute.internal;version="${project.version}", org.jclouds.compute.internal;version="${project.version}",
org.jclouds.rest.internal;version="${project.version}", org.jclouds.rest.internal;version="${project.version}",
org.jclouds.*;version="${project.version}", org.jclouds*;version="${project.version}",
* *
</Import-Package> </Import-Package>
</instructions> </instructions>

View File

@ -127,8 +127,8 @@
<configuration> <configuration>
<instructions> <instructions>
<Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName> <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
<Export-Package>org.jclouds.walrus.*;version="${project.version}"</Export-Package> <Export-Package>org.jclouds.walrus*;version="${project.version}"</Export-Package>
<Import-Package>org.jclouds.*;version="${project.version}",*</Import-Package> <Import-Package>org.jclouds*;version="${project.version}",*</Import-Package>
</instructions> </instructions>
</configuration> </configuration>
</plugin> </plugin>

View File

@ -97,8 +97,8 @@
<configuration> <configuration>
<instructions> <instructions>
<Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName> <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
<Export-Package>org.jclouds.blobstore.*;version="${project.version}"</Export-Package> <Export-Package>org.jclouds.blobstore*;version="${project.version}"</Export-Package>
<Import-Package>org.jclouds.*;version="${project.version}",*</Import-Package> <Import-Package>org.jclouds*;version="${project.version}",*</Import-Package>
<Fragment-Host>jclouds-core;bundle-version="[1.3,2)"</Fragment-Host> <Fragment-Host>jclouds-core;bundle-version="[1.3,2)"</Fragment-Host>
</instructions> </instructions>
</configuration> </configuration>

View File

@ -1,460 +0,0 @@
;
; Licensed to jclouds, Inc. (jclouds) under one or more
; contributor license agreements. See the NOTICE file
; distributed with this work for additional information
; regarding copyright ownership. jclouds licenses this file
; to you under the Apache License, Version 2.0 (the
; "License"); you may not use this file except in compliance
; with the License. You may obtain a copy of the License at
;
; http://www.apache.org/licenses/LICENSE-2.0
;
; Unless required by applicable law or agreed to in writing,
; software distributed under the License is distributed on an
; "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
; KIND, either express or implied. See the License for the
; specific language governing permissions and limitations
; under the License.
;
(ns org.jclouds.blobstore
"A clojure binding for the jclouds BlobStore.
Current supported services are:
[transient, filesystem, azureblob, atmos, walrus, scaleup-storage, ninefold-storage
googlestorage, synaptic, peer1-storage, aws-s3, eucalyptus-partnercloud-s3,
cloudfiles-us, cloudfiles-uk, swift, scality-rs2, hosteurope-storage
tiscali-storage]
Here's a quick example of how to viewresources in rackspace
(use 'org.jclouds.blobstore)
(def user \"rackspace_username\")
(def password \"rackspace_password\")
(def blobstore-name \"cloudfiles\")
(with-blobstore [blobstore-name user password]
(pprint (locations))
(pprint (containers))
(pprint (blobs blobstore your_container_name)))
See http://code.google.com/p/jclouds for details."
(:use [org.jclouds.core])
(:import [java.io File FileOutputStream OutputStream]
java.util.Properties
[org.jclouds.blobstore
AsyncBlobStore domain.BlobBuilder BlobStore BlobStoreContext
BlobStoreContextFactory domain.BlobMetadata domain.StorageMetadata
domain.Blob options.ListContainerOptions]
org.jclouds.io.Payloads
org.jclouds.io.payloads.PhantomPayload
java.util.Arrays
[java.security DigestOutputStream MessageDigest]
com.google.common.collect.ImmutableSet))
(defn blobstore
"Create a logged in context.
Options for communication style
:sync and :async.
Options can also be specified for extension modules
:log4j :enterprise :ning :apachehc :bouncycastle :joda :gae"
([#^String provider #^String provider-identity #^String provider-credential
& options]
(let [module-keys (set (keys module-lookup))
ext-modules (filter #(module-keys %) options)
opts (apply hash-map (filter #(not (module-keys %)) options))]
(let [context (.. (BlobStoreContextFactory.)
(createContext
provider provider-identity provider-credential
(apply modules (concat ext-modules (opts :extensions)))
(reduce #(do (.put %1 (name (first %2)) (second %2)) %1)
(Properties.) (dissoc opts :extensions))))]
(if (some #(= :async %) options)
(.getAsyncBlobStore context)
(.getBlobStore context))))))
(defn blobstore-context
"Returns a blobstore context from a blobstore."
[blobstore]
(.getContext blobstore))
(defn blob?
[object]
(instance? Blob))
(defn blobstore?
[object]
(or (instance? BlobStore object)
(instance? AsyncBlobStore object)))
(defn blobstore-context?
[object]
(instance? BlobStoreContext object))
(defn as-blobstore
"Tries hard to produce a blobstore from its input arguments"
[& args]
(cond
(blobstore? (first args)) (first args)
(blobstore-context? (first args)) (.getBlobStore (first args))
:else (apply blobstore args)))
(def ^{:dynamic :true} *blobstore*)
(def ^{:dynamic :true} *max-retries* 3)
(defmacro with-blobstore [[& blobstore-or-args] & body]
`(binding [*blobstore* (as-blobstore ~@blobstore-or-args)]
~@body))
(defn containers
"List all containers in a blobstore."
([] (containers *blobstore*))
([blobstore] (.list blobstore)))
(def #^{:private true} list-option-map
{:after-marker #(.afterMarker %1 %2)
:in-directory #(.inDirectory %1 %2)
:max-results #(.maxResults %1 %2)
:with-details #(when %2 (.withDetails %1))
:recursive #(when %2 (.recursive %1))})
(defn list-container
"Low-level container listing. Use list-blobs where possible since
it's higher-level and returns a lazy seq. Options are:
:after-marker string
:in-direcory path
:max-results n
:with-details true
:recursive true"
[blobstore & args]
(if (blobstore? blobstore)
(let [[container-name & args] args
options (apply hash-map args)
list-options (reduce
(fn [lco [k v]]
((list-option-map k) lco v)
lco)
(ListContainerOptions.)
options)]
(.list blobstore container-name list-options))
(apply list-container *blobstore* blobstore args)))
(defn- list-blobs-chunk [container prefix #^BlobStore blobstore & [marker]]
(apply list-container blobstore container
(concat (when prefix
[:in-directory prefix])
(when (string? marker)
[:after-marker marker]))))
(defn- list-blobs-chunks [container prefix #^BlobStore blobstore marker]
(when marker
(let [chunk (list-blobs-chunk container prefix blobstore marker)]
(lazy-seq (cons chunk
(list-blobs-chunks container prefix blobstore
(.getNextMarker chunk)))))))
(defn- concat-elements
"Make a lazy concatenation of the lazy sequences contained in coll. Lazily evaluates coll.
Note: (apply concat coll) or (lazy-cat coll) are not lazy wrt coll itself."
[coll]
(if-let [s (seq coll)]
(lazy-seq (concat (first s) (concat-elements (next s))))))
(defn list-blobs
"Returns a lazy seq of all blobs in the given container."
([container]
(list-blobs container *blobstore*))
([container blobstore]
(list-blobs container nil blobstore))
([container prefix blobstore]
(concat-elements (list-blobs-chunks container prefix blobstore :start))))
(defn locations
"Retrieve the available container locations for the blobstore context."
([] (locations *blobstore*))
([#^BlobStore blobstore]
(seq (.listAssignableLocations blobstore))))
(defn create-container
"Create a container."
([container-name]
(create-container container-name nil *blobstore*))
([container-name location]
(create-container container-name location *blobstore*))
([container-name location #^BlobStore blobstore]
(.createContainerInLocation blobstore location container-name)))
(defn clear-container
"Clear a container."
([container-name]
(clear-container container-name *blobstore*))
([container-name #^BlobStore blobstore]
(.clearContainer blobstore container-name)))
(defn delete-container
"Delete a container."
([container-name]
(delete-container container-name *blobstore*))
([container-name #^BlobStore blobstore]
(.deleteContainer blobstore container-name)))
(defn container-exists?
"Predicate to check presence of a container"
([container-name]
(container-exists? container-name *blobstore*))
([container-name #^BlobStore blobstore]
(.containerExists blobstore container-name)))
(defn directory-exists?
"Predicate to check presence of a directory"
([container-name path]
(directory-exists? container-name path *blobstore*))
([container-name path #^BlobStore blobstore]
(.directoryExists blobstore container-name path)))
(defn create-directory
"Create a directory path."
([container-name path]
(create-directory container-name path *blobstore*))
([container-name path #^BlobStore blobstore]
(.createDirectory blobstore container-name path)))
(defn delete-directory
"Delete a directory path."
([container-name path]
(delete-directory container-name path *blobstore*))
([container-name path #^BlobStore blobstore]
(.deleteDirectory blobstore container-name path)))
(defn blob-exists?
"Predicate to check presence of a blob"
([container-name path]
(blob-exists? container-name path *blobstore*))
([container-name path #^BlobStore blobstore]
(.blobExists blobstore container-name path)))
(defn put-blob
"Put a blob. Metadata in the blob determines location."
([container-name blob]
(put-blob container-name blob *blobstore*))
([container-name blob #^BlobStore blobstore]
(.putBlob blobstore container-name blob)))
(defn blob-metadata
"Get metadata from given path"
([container-name path]
(blob-metadata container-name path *blobstore*))
([container-name path #^BlobStore blobstore]
(.blobMetadata blobstore container-name path)))
(defn ^{:dynamic :true} get-blob
"Get blob from given path"
([container-name path]
(get-blob container-name path *blobstore*))
([container-name path #^BlobStore blobstore]
(.getBlob blobstore container-name path)))
(defn sign-blob-request
"Get a signed http request for manipulating a blob in another application.
ex. curl. The default is for a :get request.
The request argument is used to specify charecteristics of the request
to be signed. The :method key must be set to one of :get, :delete, and
:put. For :put requests, :content-length must be specified. Optionally,
:content-type, :content-disposition, :content-language, :content-encoding
and :content-md5 may be given."
{:deprecated "1.0-beta-10"}
([container-name path]
(sign-blob-request container-name path {:method :get} *blobstore*))
([container-name path
{:keys [method content-type content-length content-md5
content-disposition content-encoding content-language] :as request}]
(sign-blob-request container-name path request *blobstore*))
([container-name path
{:keys [method content-type content-length content-md5
content-disposition content-encoding content-language]} blobstore]
{:pre [(#{:delete :get :put} method)
(or content-length (#{:delete :get} method))]}
(case method
:delete (.signRemoveBlob
(.. blobstore getContext getSigner) container-name path)
:get (.signGetBlob
(.. blobstore getContext getSigner) container-name path)
:put (.signPutBlob
(.. blobstore getContext getSigner) container-name
(doto (.build (.blobBuilder blobstore path))
(.setPayload
(let [payload (PhantomPayload.)
metadata (.getContentMetadata payload)]
;; TODO look into use of ContentMetadata constructor
(doto metadata
(.setContentLength (long content-length))
(.setContentType content-type)
(.setContentMD5 content-md5)
(.setContentDisposition content-disposition)
(.setContentEncoding content-encoding)
(.setContentLanguage content-language))
payload)))))))
(defn sign-get
"Get a signed http GET request for manipulating a blob in another
application, Ex. curl."
([container-name name]
(sign-get container-name name *blobstore*))
([container-name name ^BlobStore blobstore]
(.signGetBlob (.. blobstore getContext getSigner) container-name name)))
(defn sign-put
"Get a signed http PUT request for manipulating a blob in another
application, Ex. curl. A Blob with at least the name and content-length
must be given."
([container-name blob]
(sign-put container-name blob *blobstore*))
([container-name ^Blob blob ^BlobStore blobstore]
(.signPutBlob (.. blobstore getContext getSigner)
container-name
blob)))
(defn sign-delete
"Get a signed http DELETE request for manipulating a blob in another
applicaiton, Ex. curl."
([container-name name]
(sign-delete container-name name *blobstore*))
([container-name name ^BlobStore blobstore]
(.signRemoveBlob (.. blobstore getContext getSigner) container-name name)))
(defn get-blob-stream
"Get an inputstream from the blob at a given path"
([container-name path]
(get-blob-stream container-name path *blobstore*))
([container-name path #^BlobStore blobstore]
(.getInput(.getPayload(.getBlob blobstore container-name path)))))
(defn remove-blob
"Remove blob from given path"
([container-name path]
(remove-blob container-name path *blobstore*))
([container-name path #^BlobStore blobstore]
(.removeBlob blobstore container-name path)))
(defn count-blobs
"Count blobs"
([container-name]
(count-blobs container-name *blobstore*))
([container-name blobstore]
(.countBlobs blobstore container-name)))
(defn blobs
"List the blobs in a container:
blobstore container -> blobs
list the blobs in a container under a path:
blobstore container dir -> blobs
example:
(pprint
(blobs
(blobstore-context flightcaster-creds)
\"somecontainer\" \"some-dir\"))"
([blobstore container-name]
(.list (as-blobstore blobstore) container-name))
([blobstore container-name dir]
(.list (as-blobstore blobstore) container-name
(.inDirectory (new ListContainerOptions) dir))))
(defn blob
"create a new blob with the specified payload"
{:deprecated "1.0-beta-10"}
([#^String name payload]
(blob name payload *blobstore*))
([#^String name payload #^BlobStore blobstore]
(.build
(.payload
(.blobBuilder blobstore name) payload))))
(defn blob2
"Create a new blob with the specified payload and options."
([^String name option-map]
(blob2 name option-map *blobstore*))
([^String name
{:keys [payload content-type content-length content-md5 calculate-md5
content-disposition content-encoding content-language metadata]}
^BlobStore blobstore]
{:pre [(not (and content-md5 calculate-md5))
(not (and (nil? payload) calculate-md5))]}
(let [blob-builder (if payload
(.payload (.blobBuilder blobstore name) payload)
(.forSigning (.blobBuilder blobstore name)))
blob-builder (if content-length ;; Special case, arg is prim.
(.contentLength blob-builder content-length)
blob-builder)
blob-builder (if calculate-md5 ;; Only do calculateMD5 OR contentMD5.
(.calculateMD5 blob-builder)
(if content-md5
(.contentMD5 blob-builder content-md5)
blob-builder))]
(doto blob-builder
(.contentType content-type)
(.contentDisposition content-disposition)
(.contentEncoding content-encoding)
(.contentLanguage content-language)
(.userMetadata metadata))
(.build blob-builder))))
(defn md5-blob
"add a content md5 to a blob, or make a new blob that has an md5.
note that this implies rebuffering, if the blob's payload isn't repeatable"
([#^Blob blob]
(Payloads/calculateMD5 blob))
([#^String name payload]
(md5-blob name payload *blobstore*))
([#^String name payload #^BlobStore blobstore]
(md5-blob (blob2 name {:payload payload} blobstore))))
(defn upload-blob
"Create anrepresenting text data:
container, name, string -> etag"
([container-name name data]
(upload-blob container-name name data *blobstore*))
([container-name name data #^BlobStore blobstore]
(put-blob container-name
(md5-blob name data blobstore) blobstore)))
(defmulti #^{:arglists '[[container-name name target]
[container-name name target blobstore]]}
download-blob (fn [& args]
(if (= (count args) 3)
::short-form
(class (last (butlast args))))))
(defmethod download-blob ::short-form
[container-name name target]
(download-blob container-name name target *blobstore*))
(defmethod download-blob OutputStream [container-name name target blobstore
& [retries]]
(let [blob (get-blob container-name name blobstore)
digest-stream (DigestOutputStream.
target (.md5(.crypto (.utils (blobstore-context blobstore)))))]
(.writeTo (.getPayload blob) digest-stream)
(let [digest (.digest (.getMessageDigest digest-stream))
metadata-digest (.getContentMD5 (.getContentMetadata (.getPayload blob)))]
(when-not (Arrays/equals digest metadata-digest)
(if (<= (or retries 0) *max-retries*)
(recur container-name name target blobstore [(inc (or retries 1))])
(throw (Exception. (format "Download failed for %s/%s"
container-name name))))))))
(defmethod download-blob File [container-name name target blobstore]
(download-blob container-name name (FileOutputStream. target) blobstore))
(define-accessors StorageMetadata "blob" type id name
location-id uri last-modified)
(define-accessors BlobMetadata "blob" content-type)
(defn blob-etag [blob]
(.getETag blob))
(defn blob-md5 [blob]
(.getContentMD5 blob))

View File

@ -1,247 +0,0 @@
;
; Licensed to jclouds, Inc. (jclouds) under one or more
; contributor license agreements. See the NOTICE file
; distributed with this work for additional information
; regarding copyright ownership. jclouds licenses this file
; to you under the Apache License, Version 2.0 (the
; "License"); you may not use this file except in compliance
; with the License. You may obtain a copy of the License at
;
; http://www.apache.org/licenses/LICENSE-2.0
;
; Unless required by applicable law or agreed to in writing,
; software distributed under the License is distributed on an
; "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
; KIND, either express or implied. See the License for the
; specific language governing permissions and limitations
; under the License.
;
(ns org.jclouds.blobstore-test
(:use [org.jclouds.blobstore] :reload-all)
(:use [clojure.test])
(:import [org.jclouds.blobstore BlobStoreContextFactory]
[org.jclouds.crypto CryptoStreams]
[java.io ByteArrayOutputStream]
[org.jclouds.util Strings2]))
(defn clean-stub-fixture
"This should allow basic tests to easily be run with another service."
[service account key & options]
(fn [f]
(with-blobstore [(apply blobstore service account key options)]
(doseq [container (containers)]
(delete-container (.getName container)))
(f))))
(use-fixtures :each (clean-stub-fixture "transient" "" ""))
(deftest blobstore?-test
(is (blobstore? *blobstore*)))
(deftest as-blobstore-test
(is (blobstore? (blobstore "transient" "user" "password")))
(is (blobstore? (as-blobstore *blobstore*)))
(is (blobstore? (as-blobstore (blobstore-context *blobstore*)))))
(deftest create-existing-container-test
(is (not (container-exists? "")))
(is (create-container "fred"))
(is (container-exists? "fred")))
(deftest create-container-test
(is (create-container "fred"))
(is (container-exists? "fred")))
(deftest locations-test
(is (not (empty? (locations))))
(is (create-container "fred" (first (locations)))))
(deftest containers-test
(is (empty? (containers)))
(is (create-container "fred"))
(is (= 1 (count (containers)))))
(deftest list-container-test
(is (create-container "container"))
(is (empty? (list-container "container")))
(is (upload-blob "container" "blob1" "blob1"))
(is (upload-blob "container" "blob2" "blob2"))
(is (= 2 (count (list-container "container"))))
(is (= 1 (count (list-container "container" :max-results 1))))
(create-directory "container" "dir")
(is (upload-blob "container" "dir/blob2" "blob2"))
(is (= 3 (count-blobs "container")))
(is (= 3 (count (list-container "container"))))
(is (= 4 (count (list-container "container" :recursive true))))
(is (= 3 (count (list-container "container" :with-details true))))
(is (= 1 (count (list-container "container" :in-directory "dir")))))
(deftest list-blobs-test
(is (create-container "container"))
(is (empty? (list-blobs "container")))
(is (empty? (list-blobs "container" "/a" *blobstore*))))
(deftest large-container-list-test
(let [container-name "test"
total-blobs 5000]
;; create a container full of blobs
(create-container container-name)
(dotimes [i total-blobs] (upload-blob container-name (str i) (str i)))
;; verify
(is (= total-blobs (count-blobs container-name)))))
(deftest get-blob-test
(is (create-container "blob"))
(is (upload-blob "blob" "blob1" "blob1"))
(is (upload-blob "blob" "blob2" "blob2"))
(is (= "blob2" (Strings2/toStringAndClose (get-blob-stream "blob" "blob2")))))
(deftest download-blob-test
(let [name "test"
container-name "test-container"
data "test content"
data-file (java.io.File/createTempFile "jclouds" "data")]
(try (create-container container-name)
(upload-blob container-name name data)
(download-blob container-name name data-file)
(is (= data (slurp (.getAbsolutePath data-file))))
(finally (.delete data-file)))))
(deftest download-checksum-test
(binding [get-blob (fn [blobstore c-name name]
(let [blob (.newBlob blobstore name)
md (.getMetadata blob)]
(.setPayload blob "bogus payload")
(.setContentMD5 md (.getBytes "bogus MD5"))
blob))]
(let [name "test"
container-name "test-container"
data "test content"
data-file (java.io.File/createTempFile "jclouds" "data")]
(try (create-container container-name)
(upload-blob container-name name data)
(is (thrown? Exception
(download-blob container-name name data-file)))
(finally (.delete data-file))))))
(deftest sign-blob-request-test
(testing "delete"
(let [request (sign-blob-request "container" "path" {:method :delete})]
(is (= "http://localhost/container/path" (str (.getEndpoint request))))
(is (= "DELETE" (.getMethod request)))))
(testing "default request"
(let [request (sign-blob-request "container" "path")]
(is (= "http://localhost/container/path" (str (.getEndpoint request))))
(is (= "GET" (.getMethod request)))))
(testing "get"
(let [request (sign-blob-request "container" "path" {:method :get})]
(is (= "http://localhost/container/path" (str (.getEndpoint request))))
(is (= "GET" (.getMethod request)))))
(testing "put"
(let [request (sign-blob-request
"container" "path" {:method :put :content-length 10})]
(is (= "http://localhost/container/path" (str (.getEndpoint request))))
(is (= "PUT" (.getMethod request)))
(is (= "10" (first (.get (.getHeaders request) "Content-Length"))))
(is (nil?
(first (.get (.getHeaders request) "Content-Type"))))))
(testing "put with headers"
(let [request (sign-blob-request
"container" "path"
{:method :put :content-length 10
:content-type "x"
:content-language "en"
:content-disposition "f"
:content-encoding "g"})]
(is (= "PUT" (.getMethod request)))
(is (= "10" (first (.get (.getHeaders request) "Content-Length"))))
(is (= "x" (first (.get (.getHeaders request) "Content-Type"))))
(is (= "en" (first (.get (.getHeaders request) "Content-Language"))))
(is (= "f" (first (.get (.getHeaders request) "Content-Disposition"))))
(is (= "g" (first (.get (.getHeaders request) "Content-Encoding")))))))
(deftest sign-get-test
(let [request (sign-get "container" "path")]
(is (= "http://localhost/container/path" (str (.getEndpoint request))))
(is (= "GET" (.getMethod request)))))
(deftest sign-put-test
(let [request (sign-put "container"
(blob2 "path" {:content-length 10}))]
(is (= "http://localhost/container/path" (str (.getEndpoint request))))
(is (= "PUT" (.getMethod request)))
(is (= "10" (first (.get (.getHeaders request) "Content-Length"))))
(is (nil?
(first (.get (.getHeaders request) "Content-Type"))))))
(deftest sign-put-with-headers-test
(let [request (sign-put
"container"
(blob2 "path" {:content-length 10
:content-type "x"
:content-language "en"
:content-disposition "f"
:content-encoding "g"}))]
(is (= "PUT" (.getMethod request)))
(is (= "10" (first (.get (.getHeaders request) "Content-Length"))))
(is (= "x" (first (.get (.getHeaders request) "Content-Type"))))
(is (= "en" (first (.get (.getHeaders request) "Content-Language"))))
(is (= "f" (first (.get (.getHeaders request) "Content-Disposition"))))
(is (= "g" (first (.get (.getHeaders request) "Content-Encoding"))))))
(deftest sign-delete-test
(let [request (sign-delete "container" "path")]
(is (= "http://localhost/container/path" (str (.getEndpoint request))))
(is (= "DELETE" (.getMethod request)))))
(deftest blob2-test
(let [a-blob (blob2 "test-name" {:payload (.getBytes "test-payload")
:calculate-md5 true})]
(is (= (seq (.. a-blob (getPayload) (getContentMetadata) (getContentMD5)))
(seq (CryptoStreams/md5 (.getBytes "test-payload")))))))
;; TODO: more tests involving blob-specific functions
(deftest corruption-hunt
(let [container-name "test"
name "work-file"
total-downloads 100
threads 10]
;; upload
(create-container container-name)
(when-not (blob-exists? container-name name)
(let [data-stream (java.io.ByteArrayOutputStream.)]
(dotimes [i 5000000] (.write data-stream i))
(upload-blob container-name name (.toByteArray data-stream))))
;; download
(let [total (atom total-downloads)]
(defn new-agent []
(agent name))
(defn dl-and-restart [blob-s file]
(when-not (<= @total 0)
(with-open [baos (java.io.ByteArrayOutputStream.)]
(try
(download-blob container-name file baos blob-s)
(catch Exception e
(with-open [of (java.io.FileOutputStream.
(java.io.File/createTempFile "jclouds" ".dl"))]
(.write of (.toByteArray baos)))
(throw e))))
(swap! total dec)
(send *agent* (partial dl-and-restart blob-s))
file))
(defn start-agents []
(let [agents (map (fn [_] (new-agent))
(range threads))]
(doseq [a agents]
(send-off a (partial dl-and-restart *blobstore*)))
agents))
(let [agents (start-agents)]
(apply await agents)
(is (every? nil? (map agent-errors agents)))))))

View File

@ -56,8 +56,8 @@
<configuration> <configuration>
<instructions> <instructions>
<Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName> <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
<Export-Package>org.jclouds.aws.*;version="${project.version}"</Export-Package> <Export-Package>org.jclouds.aws*;version="${project.version}"</Export-Package>
<Import-Package>org.jclouds.*;version="${project.version}",*</Import-Package> <Import-Package>org.jclouds*;version="${project.version}",*</Import-Package>
</instructions> </instructions>
</configuration> </configuration>
</plugin> </plugin>

View File

@ -56,8 +56,8 @@
<configuration> <configuration>
<instructions> <instructions>
<Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName> <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
<Export-Package>org.jclouds.azure.*;version="${project.version}"</Export-Package> <Export-Package>org.jclouds.azure*;version="${project.version}"</Export-Package>
<Import-Package>org.jclouds.*;version="${project.version}",*</Import-Package> <Import-Package>org.jclouds*;version="${project.version}",*</Import-Package>
</instructions> </instructions>
</configuration> </configuration>
</plugin> </plugin>

View File

@ -57,8 +57,8 @@
<configuration> <configuration>
<instructions> <instructions>
<Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName> <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
<Export-Package>org.jclouds.openstack.*;version="${project.version}"</Export-Package> <Export-Package>org.jclouds.openstack*;version="${project.version}"</Export-Package>
<Import-Package>org.jclouds.*;version="${project.version}",*</Import-Package> <Import-Package>org.jclouds*;version="${project.version}",*</Import-Package>
</instructions> </instructions>
</configuration> </configuration>
</plugin> </plugin>

View File

@ -81,8 +81,8 @@
<configuration> <configuration>
<instructions> <instructions>
<Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName> <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
<Export-Package>org.jclouds.trmk.vcloud_0_8.*;version="${project.version}"</Export-Package> <Export-Package>org.jclouds.trmk.vcloud_0_8*;version="${project.version}"</Export-Package>
<Import-Package>org.jclouds.*;version="${project.version}",*</Import-Package> <Import-Package>org.jclouds*;version="${project.version}",*</Import-Package>
</instructions> </instructions>
</configuration> </configuration>
</plugin> </plugin>

View File

@ -21,6 +21,7 @@ package org.jclouds.trmk.vcloud_0_8.compute;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.atomic.AtomicReference;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Named; import javax.inject.Named;
@ -71,9 +72,9 @@ public class TerremarkVCloudComputeService extends BaseComputeService {
RebootNodeStrategy rebootNodeStrategy, DestroyNodeStrategy destroyNodeStrategy, RebootNodeStrategy rebootNodeStrategy, DestroyNodeStrategy destroyNodeStrategy,
ResumeNodeStrategy resumeNodeStrategy, SuspendNodeStrategy suspendNodeStrategy, ResumeNodeStrategy resumeNodeStrategy, SuspendNodeStrategy suspendNodeStrategy,
Provider<TemplateBuilder> templateBuilderProvider, Provider<TemplateOptions> templateOptionsProvider, Provider<TemplateBuilder> templateBuilderProvider, Provider<TemplateOptions> templateOptionsProvider,
@Named("NODE_RUNNING") Predicate<NodeMetadata> nodeRunning, @Named("NODE_RUNNING") Predicate<AtomicReference<NodeMetadata>> nodeRunning,
@Named("NODE_TERMINATED") Predicate<NodeMetadata> nodeTerminated, @Named("NODE_TERMINATED") Predicate<AtomicReference<NodeMetadata>> nodeTerminated,
@Named("NODE_SUSPENDED") Predicate<NodeMetadata> nodeSuspended, @Named("NODE_SUSPENDED") Predicate<AtomicReference<NodeMetadata>> nodeSuspended,
InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory, InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory,
RunScriptOnNode.Factory runScriptOnNodeFactory, InitAdminAccess initAdminAccess, RunScriptOnNode.Factory runScriptOnNodeFactory, InitAdminAccess initAdminAccess,
PersistNodeCredentials persistNodeCredentials, Timeouts timeouts, PersistNodeCredentials persistNodeCredentials, Timeouts timeouts,

View File

@ -73,8 +73,8 @@
<configuration> <configuration>
<instructions> <instructions>
<Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName> <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
<Export-Package>org.jclouds.compute.*;version="${project.version}",org.jclouds.cim.*;version="${project.version}",org.jclouds.ovf.*;version="${project.version}",org.jclouds.ssh.*;version="${project.version}"</Export-Package> <Export-Package>org.jclouds.compute*;version="${project.version}",org.jclouds.cim*;version="${project.version}",org.jclouds.ovf*;version="${project.version}",org.jclouds.ssh*;version="${project.version}"</Export-Package>
<Import-Package>!org.jclouds.compute.*;org.jclouds.*;version="${project.version}",*</Import-Package> <Import-Package>!org.jclouds.compute.*;org.jclouds*;version="${project.version}",*</Import-Package>
<Fragment-Host>jclouds-core;bundle-version="[1.3,2)"</Fragment-Host> <Fragment-Host>jclouds-core;bundle-version="[1.3,2)"</Fragment-Host>
</instructions> </instructions>
</configuration> </configuration>

View File

@ -1,459 +0,0 @@
;
; Licensed to jclouds, Inc. (jclouds) under one or more
; contributor license agreements. See the NOTICE file
; distributed with this work for additional information
; regarding copyright ownership. jclouds licenses this file
; to you under the Apache License, Version 2.0 (the
; "License"); you may not use this file except in compliance
; with the License. You may obtain a copy of the License at
;
; http://www.apache.org/licenses/LICENSE-2.0
;
; Unless required by applicable law or agreed to in writing,
; software distributed under the License is distributed on an
; "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
; KIND, either express or implied. See the License for the
; specific language governing permissions and limitations
; under the License.
;
(ns org.jclouds.compute
"A clojure binding to the jclouds ComputeService.
Current supported providers are:
[aws-ec2, eucualyptus-partnercloud-ec2, elastichosts-lon-b, nova,
cloudservers-uk, cloudservers-us, byon, cloudsigma-zrh, stub,
trmk-ecloud, trmk-vcloudexpress, vcloud, bluelock, eucalyptus,
slicehost, elastichosts-lon-p, elastichosts-sat-p, elastichosts,
openhosting-east1, serverlove-z1-man, skalicloud-sdg-my, deltacloud]
Here's an example of getting some compute configuration from rackspace:
(use 'org.jclouds.compute)
(def provider \"cloudservers\")
(def provider-identity \"username\")
(def provider-credential \"password\")
;; create a compute service
(def compute
(compute-service provider provider-identity provider-credential))
(with-compute-service [compute]
(pprint (locations))
(pprint (images))
(pprint (nodes))
(pprint (hardware-profiles)))
Here's an example of creating and running a small linux node in the group
webserver:
;; create a compute service using ssh and log4j extensions
(def compute
(compute-service
provider provider-identity provider-credential :sshj :log4j))
(create-node \"webserver\" compute)
See http://code.google.com/p/jclouds for details."
(:use org.jclouds.core
(org.jclouds predicate) [clojure.core.incubator :only (-?>)])
(:import java.io.File
java.util.Properties
[org.jclouds.domain Location]
[org.jclouds.compute
ComputeService ComputeServiceContext ComputeServiceContextFactory]
[org.jclouds.compute.domain
Template TemplateBuilder ComputeMetadata NodeMetadata Hardware
OsFamily Image]
[org.jclouds.compute.options TemplateOptions]
[org.jclouds.compute.predicates
NodePredicates]
[com.google.common.collect ImmutableSet]))
(defmacro deprecate-fwd [old-name new-name] `(defn ~old-name {:deprecated "beta-9"} [& args#] (apply ~new-name args#)))
(defn compute-service
"Create a logged in context."
([#^String provider #^String provider-identity #^String provider-credential
& options]
(let [module-keys (set (keys module-lookup))
ext-modules (filter #(module-keys %) options)
opts (apply hash-map (filter #(not (module-keys %)) options))]
(.. (ComputeServiceContextFactory.)
(createContext
provider provider-identity provider-credential
(apply modules (concat ext-modules (opts :extensions)))
(reduce #(do (.put %1 (name (first %2)) (second %2)) %1)
(Properties.) (dissoc opts :extensions)))
(getComputeService)))))
(defn compute-context
"Returns a compute context from a compute service."
[compute]
(.getContext compute))
(defn compute-service?
[object]
(instance? ComputeService object))
(defn compute-context?
[object]
(instance? ComputeServiceContext object))
(defn as-compute-service
"Tries hard to produce a compute service from its input arguments"
[& args]
(cond
(compute-service? (first args)) (first args)
(compute-context? (first args)) (.getComputeService (first args))
:else (apply compute-service args)))
(def ^{:dynamic :true} *compute*)
(defmacro with-compute-service
"Specify the default compute service"
[[& compute-or-args] & body]
`(binding [*compute* (as-compute-service ~@compute-or-args)]
~@body))
(defn locations
"Retrieve the available compute locations for the compute context."
([] (locations *compute*))
([#^ComputeService compute]
(seq (.listAssignableLocations compute))))
(defn nodes
"Retrieve the existing nodes for the compute context."
([] (nodes *compute*))
([#^ComputeService compute]
(seq (.listNodes compute))))
(defn nodes-with-details
"Retrieve the existing nodes for the compute context."
([] (nodes-with-details *compute*))
([#^ComputeService compute]
(seq (.listNodesDetailsMatching compute (NodePredicates/all)))))
(defn nodes-in-group
"list details of all the nodes in the given group."
([group] (nodes-in-group group *compute*))
([#^String group #^ComputeService compute]
(filter #(= (.getGroup %) group) (nodes-with-details compute))))
(defn images
"Retrieve the available images for the compute context."
([] (images *compute*))
([#^ComputeService compute]
(seq (.listImages compute))))
(defn hardware-profiles
"Retrieve the available node hardware profiles for the compute context."
([] (hardware-profiles *compute*))
([#^ComputeService compute]
(seq (.listHardwareProfiles compute))))
(defn default-template
([] (default-template *compute*))
([#^ComputeService compute]
(.. compute (templateBuilder)
(options
(org.jclouds.compute.options.TemplateOptions$Builder/authorizePublicKey
(slurp (str (. System getProperty "user.home") "/.ssh/id_rsa.pub"))))
build)))
(defn create-nodes
"Create the specified number of nodes using the default or specified
template.
;; Simplest way to add 2 small linux nodes to the group webserver is to run
(create-nodes \"webserver\" 2 compute)
;; which is the same as wrapping the create-nodes command with an implicit
;; compute service.
;; Note that this will actually add another 2 nodes to the set called
;; \"webserver\"
(with-compute-service [compute]
(create-nodes \"webserver\" 2 ))
;; which is the same as specifying the default template
(with-compute-service [compute]
(create-nodes \"webserver\" 2 (default-template)))
;; which, on gogrid, is the same as constructing the smallest centos template
;; that has no layered software
(with-compute-service [compute]
(create-nodes \"webserver\" 2
(build-template
service
{:os-family :centos :smallest true
:image-name-matches \".*w/ None.*\"})))"
([group count]
(create-nodes group count (default-template *compute*) *compute*))
([group count compute-or-template]
(if (compute-service? compute-or-template)
(create-nodes
group count (default-template compute-or-template) compute-or-template)
(create-nodes group count compute-or-template *compute*)))
([group count template #^ComputeService compute]
(seq
(.createNodesInGroup compute group count template))))
(deprecate-fwd run-nodes create-nodes)
(defn create-node
"Create a node using the default or specified template.
;; simplest way to add a small linux node to the group webserver is to run
(create-node \"webserver\" compute)
;; which is the same as wrapping the create-node command with an implicit compute
;; service.
;; Note that this will actually add another node to the set called
;; \"webserver\"
(with-compute-service [compute]
(create-node \"webserver\" ))"
([group]
(first (create-nodes group 1 (default-template *compute*) *compute*)))
([group compute-or-template]
(if (compute-service? compute-or-template)
(first
(create-nodes
group 1 (default-template compute-or-template) compute-or-template))
(first (create-nodes group 1 compute-or-template *compute*))))
([group template compute]
(first (create-nodes group 1 template compute))))
(deprecate-fwd run-node create-node)
(defn #^NodeMetadata node-details
"Retrieve the node metadata, given its id."
([id] (node-details id *compute*))
([id #^ComputeService compute]
(.getNodeMetadata compute id)))
(defn suspend-nodes-in-group
"Reboot all the nodes in the given group."
([group] (suspend-nodes-in-group group *compute*))
([#^String group #^ComputeService compute]
(.suspendNodesMatching compute (NodePredicates/inGroup group))))
(defn suspend-node
"Suspend a node, given its id."
([id] (suspend-node id *compute*))
([id #^ComputeService compute]
(.suspendNode compute id)))
(defn resume-nodes-in-group
"Suspend all the nodes in the given group."
([group] (resume-nodes-in-group group *compute*))
([#^String group #^ComputeService compute]
(.resumeNodesMatching compute (NodePredicates/inGroup group))))
(defn resume-node
"Resume a node, given its id."
([id] (resume-node id *compute*))
([id #^ComputeService compute]
(.resumeNode compute id)))
(defn reboot-nodes-in-group
"Reboot all the nodes in the given group."
([group] (reboot-nodes-in-group group *compute*))
([#^String group #^ComputeService compute]
(.rebootNodesMatching compute (NodePredicates/inGroup group))))
(defn reboot-node
"Reboot a node, given its id."
([id] (reboot-node id *compute*))
([id #^ComputeService compute]
(.rebootNode compute id)))
(defn destroy-nodes-in-group
"Destroy all the nodes in the given group."
([group] (destroy-nodes-in-group group *compute*))
([#^String group #^ComputeService compute]
(.destroyNodesMatching compute (NodePredicates/inGroup group))))
(defn destroy-node
"Destroy a node, given its id."
([id] (destroy-node id *compute*))
([id #^ComputeService compute]
(.destroyNode compute id)))
(defmacro state-predicate [node state]
`(= (.getState ~node)
(. org.jclouds.compute.domain.NodeState ~state)))
(defn pending?
"Predicate for the node being in transition"
[#^NodeMetadata node]
(state-predicate node PENDING))
(defn running?
"Predicate for the node being available for requests."
[#^NodeMetadata node]
(state-predicate node RUNNING))
(defn terminated?
"Predicate for the node being halted."
[#^NodeMetadata node]
(or
(= node nil)
(state-predicate node TERMINATED)))
(defn suspended?
"Predicate for the node being suspended."
[#^NodeMetadata node]
(state-predicate node SUSPENDED))
(defn error-state?
"Predicate for the node being in an error state."
[#^NodeMetadata node]
(state-predicate node ERROR))
(defn unrecognized-state?
"Predicate for the node being in an unrecognized state."
[#^NodeMetadata node]
(state-predicate node UNRECOGNIZED))
(defn public-ips
"Returns the node's public ips"
[#^NodeMetadata node]
(.getPublicAddresses node))
(defn private-ips
"Returns the node's private ips"
[#^NodeMetadata node]
(.getPrivateAddresses node))
(defn group
"Returns a the node's group"
[#^NodeMetadata node]
(.getGroup node))
(defn hostname
"Returns the compute node's name"
[#^ComputeMetadata node]
(.getName node))
(defn location
"Returns the compute node's location id"
[#^ComputeMetadata node]
(-?> node .getLocation .getId))
(defn id
"Returns the compute node's id"
[#^ComputeMetadata node]
(.getId node))
(define-accessors Template image hardware location options)
(define-accessors Image version os-family os-description architecture)
(define-accessors Hardware processors ram volumes)
(define-accessors NodeMetadata "node" credentials hardware state group)
(def
^{:doc "TemplateBuilder functions" :private true}
template-map
(merge
(make-option-map
kw-memfn-0arg [:smallest :fastest :biggest :any])
(make-option-map
kw-memfn-1arg
[:os-family :location-id :architecture :image-id :hardware-id
:os-name-matches :os-version-matches :os-description-matches
:os-64-bit :image-version-matches :image-name-matches
:image-description-matches :min-cores :min-ram])))
(def
^{:doc "TemplateOptions functions" :private true}
options-map
(merge
(make-option-map
kw-memfn-0arg
[:destroy-on-error :enable-monitoring :no-placement-group :no-key-pair
:with-details])
(make-option-map
kw-memfn-1arg
[:run-script :install-private-key :authorize-public-key
:override-credentials-with :override-login-user-with
:override-login-credential-with
;; aws ec2 options
:spot-price :spot-options :placement-group :subnet-id
:block-device-mappings :unmapDeviceNamed :security-groups
:key-pair :user-data])
(make-option-map kw-memfn-varargs [:inbound-ports])
(make-option-map
kw-memfn-2arg
[:block-on-port
;; aws ec2 options
:map-ephemeral-device-to-device-name])
{:map-ebs-snapshot-to-device-name
(memfn-apply mapEBSSnapshotToDeviceName
device-name snapshot-id size-in-gib delete-on-termination)
:map-new-volume-to-device-name
(kw-memfn-apply :map-new-volume-to-device-name
device-name size-in-gib delete-on-termination)}))
(def
^{:doc "All receognised options"}
known-template-options
(set (mapcat keys [options-map template-map])))
(defn os-families []
(. OsFamily values))
(def enum-map {:os-family (os-families)})
(defn translate-enum-value [kword value]
(or (-> (filter #(= (name value) (str %)) (kword enum-map)) first)
value))
(defn apply-option [builder option-map option value]
(when-let [f (option-map option)]
(f builder (translate-enum-value option value))))
;; TODO look at clojure-datalog
(defn build-template
"Creates a template that can be used to run nodes.
The :os-family key expects a keyword version of OsFamily,
eg. :os-family :ubuntu.
The :smallest, :fastest, :biggest, :any, and :destroy-on-error keys expect a
boolean value.
Options correspond to TemplateBuilder methods."
[#^ComputeService compute
{:keys [os-family location-id architecture image-id hardware-id
os-name-matches os-version-matches os-description-matches
os-64-bit image-version-matches image-name-matches
image-description-matches min-cores min-ram
run-script install-private-key authorize-public-key
inbound-ports smallest fastest biggest any destroy-on-error]
:as options}]
(let [builder (.. compute (templateBuilder))]
(doseq [[option value] options]
(when-not (known-template-options option)
(throw (Exception. (format "Invalid template builder option : %s" option))))
;; apply template builder options
(try
(apply-option builder template-map option value)
(catch Exception e
(throw (Exception. (format
"Problem applying template builder %s with value %s: %s"
option (pr-str value) (.getMessage e))
e)))))
(let [template (.build builder)
template-options (.getOptions template)]
(doseq [[option value] options]
;; apply template option options
(try
(apply-option template-options options-map option value)
(catch Exception e
(throw (Exception.
(format
"Problem applying template option %s with value %s: %s"
option (pr-str value) (.getMessage e))
e)))))
template)))

View File

@ -326,7 +326,7 @@ Here's an example of creating and running a small linux node in the group webser
(make-option-map (make-option-map
kw-memfn-1arg kw-memfn-1arg
[:from-hardware :from-image :from-template [:from-hardware :from-image :from-template
:os-family :location-id :image-id :hardware-id :os-family :location-id :image-id :hardware-id :hypervisor-matches
:os-name-matches :os-description-matches :os-version-matches :os-name-matches :os-description-matches :os-version-matches
:os-arch-matches :os-64-bit :image-name-matches :os-arch-matches :os-64-bit :image-name-matches
:image-version-matches :image-description-matches :image-matches :image-version-matches :image-description-matches :image-matches

View File

@ -23,23 +23,21 @@ import static org.jclouds.compute.util.ComputeServiceUtils.extractTargzIntoDirec
import static org.jclouds.scriptbuilder.domain.Statements.appendFile; import static org.jclouds.scriptbuilder.domain.Statements.appendFile;
import static org.jclouds.scriptbuilder.domain.Statements.exec; import static org.jclouds.scriptbuilder.domain.Statements.exec;
import static org.jclouds.scriptbuilder.domain.Statements.interpret; import static org.jclouds.scriptbuilder.domain.Statements.interpret;
import static org.jclouds.scriptbuilder.domain.Statements.newStatementList;
import java.io.IOException; import java.io.IOException;
import java.net.URI; import java.net.URI;
import org.jclouds.compute.domain.OperatingSystem; import org.jclouds.compute.domain.OperatingSystem;
import org.jclouds.compute.predicates.OperatingSystemPredicates; import org.jclouds.scriptbuilder.InitScript;
import org.jclouds.scriptbuilder.InitBuilder;
import org.jclouds.scriptbuilder.domain.Statement; import org.jclouds.scriptbuilder.domain.Statement;
import org.jclouds.scriptbuilder.domain.StatementList; import org.jclouds.scriptbuilder.domain.StatementList;
import org.jclouds.scriptbuilder.statements.java.InstallJDK;
import org.jclouds.scriptbuilder.statements.login.AdminAccess; import org.jclouds.scriptbuilder.statements.login.AdminAccess;
import com.google.common.base.Splitter; import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableList.Builder; import com.google.common.collect.ImmutableList.Builder;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
/** /**
* *
@ -47,24 +45,11 @@ import com.google.common.collect.ImmutableSet;
*/ */
public class RunScriptData { public class RunScriptData {
public static final URI JDK7_URL = URI.create(System.getProperty("test.jdk7-url",
"http://download.oracle.com/otn-pub/java/jdk/7u2-b13/jdk-7u2-linux-x64.tar.gz"));
public static final URI JBOSS7_URL = URI.create(System.getProperty("test.jboss7-url",// public static final URI JBOSS7_URL = URI.create(System.getProperty("test.jboss7-url",//
"http://download.jboss.org/jbossas/7.0/jboss-as-7.0.2.Final/jboss-as-web-7.0.2.Final.tar.gz")); "http://download.jboss.org/jbossas/7.0/jboss-as-7.0.2.Final/jboss-as-web-7.0.2.Final.tar.gz"));
public static String JBOSS_HOME = "/usr/local/jboss"; public static String JBOSS_HOME = "/usr/local/jboss";
public static Statement installJavaAndCurl(OperatingSystem os) {
if (os == null || OperatingSystemPredicates.supportsApt().apply(os))
return APT_RUN_SCRIPT;
else if (OperatingSystemPredicates.supportsYum().apply(os))
return YUM_RUN_SCRIPT;
else if (OperatingSystemPredicates.supportsZypper().apply(os))
return ZYPPER_RUN_SCRIPT;
else
throw new IllegalArgumentException("don't know how to handle" + os.toString());
}
public static Statement authorizePortsInIpTables(int... ports) { public static Statement authorizePortsInIpTables(int... ports) {
Builder<Statement> builder = ImmutableList.<Statement> builder(); Builder<Statement> builder = ImmutableList.<Statement> builder();
for (int port : ports) for (int port : ports)
@ -76,7 +61,7 @@ public class RunScriptData {
public static StatementList installAdminUserJBossAndOpenPorts(OperatingSystem os) throws IOException { public static StatementList installAdminUserJBossAndOpenPorts(OperatingSystem os) throws IOException {
return new StatementList(// return new StatementList(//
AdminAccess.builder().adminUsername("web").build(),// AdminAccess.builder().adminUsername("web").build(),//
installJavaAndCurl(os),// InstallJDK.fromURL(),//
authorizePortsInIpTables(22, 8080),// authorizePortsInIpTables(22, 8080),//
extractTargzIntoDirectory(JBOSS7_URL, "/usr/local"),// extractTargzIntoDirectory(JBOSS7_URL, "/usr/local"),//
exec("{md} " + JBOSS_HOME), exec("mv /usr/local/jboss-*/* " + JBOSS_HOME),// exec("{md} " + JBOSS_HOME), exec("mv /usr/local/jboss-*/* " + JBOSS_HOME),//
@ -86,15 +71,13 @@ public class RunScriptData {
} }
// NOTE do not name this the same as your login user, or the init process may kill you! // NOTE do not name this the same as your login user, or the init process may kill you!
public static InitBuilder startJBoss(String configuration) { public static InitScript startJBoss(String configuration) {
return new InitBuilder( return InitScript.builder()
"jboss", .name("jboss")
JBOSS_HOME, .home(JBOSS_HOME)
JBOSS_HOME, .exportVariables(ImmutableMap.of("jbossHome", JBOSS_HOME))
ImmutableMap.of("jbossHome", JBOSS_HOME), .init(appendFile(JBOSS_HOME + "/standalone/configuration/standalone-custom.xml", Splitter.on('\n').split(configuration)))
ImmutableList.<Statement>of(appendFile(JBOSS_HOME + "/standalone/configuration/standalone-custom.xml", Splitter.on('\n').split(configuration))), .run(interpret(new StringBuilder().append("java ").append(' ')
ImmutableList
.<Statement> of(interpret(new StringBuilder().append("java ").append(' ')
.append("-server -Xms128m -Xmx128m -XX:MaxPermSize=128m -Djava.net.preferIPv4Stack=true -XX:+UseFastAccessorMethods -XX:+TieredCompilation -Xverify:none -Dorg.jboss.resolver.warning=true -Dsun.rmi.dgc.client.gcInterval=3600000 -Dsun.rmi.dgc.server.gcInterval=3600000").append(' ') .append("-server -Xms128m -Xmx128m -XX:MaxPermSize=128m -Djava.net.preferIPv4Stack=true -XX:+UseFastAccessorMethods -XX:+TieredCompilation -Xverify:none -Dorg.jboss.resolver.warning=true -Dsun.rmi.dgc.client.gcInterval=3600000 -Dsun.rmi.dgc.server.gcInterval=3600000").append(' ')
.append("-Djboss.modules.system.pkgs=org.jboss.byteman").append(' ') .append("-Djboss.modules.system.pkgs=org.jboss.byteman").append(' ')
.append("-Dorg.jboss.boot.log.file=$JBOSS_HOME/standalone/log/boot.log").append(' ') .append("-Dorg.jboss.boot.log.file=$JBOSS_HOME/standalone/log/boot.log").append(' ')
@ -106,21 +89,7 @@ public class RunScriptData {
.append("org.jboss.as.standalone").append(' ') .append("org.jboss.as.standalone").append(' ')
.append("-Djboss.home.dir=$JBOSS_HOME").append(' ') .append("-Djboss.home.dir=$JBOSS_HOME").append(' ')
.append("--server-config=standalone-custom.xml") .append("--server-config=standalone-custom.xml")
.toString()))); .toString())).build();
}
public static Statement normalizeHostAndDNSConfig() {
return newStatementList(//
addHostnameToEtcHostsIfMissing(),//
addDnsToResolverIfMissing());
}
public static Statement addHostnameToEtcHostsIfMissing() {
return exec("grep `hostname` /etc/hosts >/dev/null || awk -v hostname=`hostname` 'END { print $1\" \"hostname }' /proc/net/arp >> /etc/hosts");
}
public static Statement addDnsToResolverIfMissing() {
return exec("nslookup yahoo.com >/dev/null || echo nameserver 208.67.222.222 >> /etc/resolv.conf");
} }
// TODO make this a cli option // TODO make this a cli option
@ -129,47 +98,4 @@ public class RunScriptData {
"(cd %s/standalone/configuration && sed 's~inet-address value=.*/~any-address/~g' standalone.xml > standalone.xml.new && mv standalone.xml.new standalone.xml)", "(cd %s/standalone/configuration && sed 's~inet-address value=.*/~any-address/~g' standalone.xml > standalone.xml.new && mv standalone.xml.new standalone.xml)",
JBOSS_HOME)); JBOSS_HOME));
} }
public static final ImmutableSet<String> exportJavaHomeAndAddToPath = ImmutableSet.of(
"export JAVA_HOME=/usr/local/jdk", "export PATH=$JAVA_HOME/bin:$PATH");
public static final Statement JDK7_INSTALL_TGZ = newStatementList(//
exec("{md} /usr/local/jdk"), extractTargzIntoDirectory(JDK7_URL, "/usr/local"),//
exec("mv /usr/local/jdk1.7*/* /usr/local/jdk/"),//
exec("test -n \"$SUDO_USER\" && "), appendFile("/home/$SUDO_USER/.bashrc", exportJavaHomeAndAddToPath),//
appendFile("/etc/bashrc", exportJavaHomeAndAddToPath),//
appendFile("$HOME/.bashrc", exportJavaHomeAndAddToPath),//
appendFile("/etc/skel/.bashrc", exportJavaHomeAndAddToPath),//
// TODO:
// eventhough we are setting the above, sometimes images (ex.
// cloudservers ubuntu) kick out of .bashrc (ex. [ -z "$PS1" ] &&
// return), for this reason, we should also explicitly link.
// A better way would be to update using alternatives or the like
exec("ln -fs /usr/local/jdk/bin/java /usr/bin/java"));
public static String aptInstall = "apt-get install -f -y -qq --force-yes";
public static String aptInstallLazyUpgrade(String packageName) {
return aptInstall + " " + packageName + "|| (" + "apt-get update -qq&&" + "apt-get upgrade -y -qq" + ")&&"
+ aptInstall + " " + packageName;
}
public static final Statement APT_RUN_SCRIPT = newStatementList(//
exec("which nslookup >&- 2>&-|| " + aptInstallLazyUpgrade("dnsutils")),//
normalizeHostAndDNSConfig(),//
exec("which curl >&- 2>&-|| " + aptInstallLazyUpgrade("curl")),//
JDK7_INSTALL_TGZ);
public static String yumInstall = "yum --nogpgcheck -y install";
public static final Statement YUM_RUN_SCRIPT = newStatementList(//
exec("which nslookup >&- 2>&-|| " + yumInstall + " bind-utils"),//
normalizeHostAndDNSConfig(),//
exec("which curl >&- 2>&-|| " + yumInstall + " curl"),//
JDK7_INSTALL_TGZ);
public static final Statement ZYPPER_RUN_SCRIPT = newStatementList(//
normalizeHostAndDNSConfig(),//
exec("which curl >&- 2>&-|| zypper install curl"),//
JDK7_INSTALL_TGZ);
} }

View File

@ -21,6 +21,7 @@ package org.jclouds.compute.callables;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Date; import java.util.Date;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@ -30,22 +31,28 @@ import javax.annotation.Resource;
import org.jclouds.Constants; import org.jclouds.Constants;
import org.jclouds.compute.domain.ExecResponse; import org.jclouds.compute.domain.ExecResponse;
import org.jclouds.compute.events.StatementOnNodeCompletion;
import org.jclouds.compute.events.StatementOnNodeFailure;
import org.jclouds.compute.predicates.ScriptStatusReturnsZero; import org.jclouds.compute.predicates.ScriptStatusReturnsZero;
import org.jclouds.compute.reference.ComputeServiceConstants; import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.logging.Logger; import org.jclouds.logging.Logger;
import org.jclouds.predicates.RetryablePredicate; import org.jclouds.predicates.RetryablePredicate;
import org.jclouds.scriptbuilder.InitBuilder; import org.jclouds.scriptbuilder.InitScript;
import org.jclouds.ssh.SshClient; import org.jclouds.ssh.SshClient;
import com.google.common.base.Objects;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
import com.google.common.base.Throwables; import com.google.common.base.Throwables;
import com.google.common.eventbus.EventBus;
import com.google.common.primitives.Ints;
import com.google.common.util.concurrent.AbstractFuture; import com.google.common.util.concurrent.AbstractFuture;
import com.google.inject.Inject; import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted; import com.google.inject.assistedinject.Assisted;
import com.google.inject.name.Named; import com.google.inject.name.Named;
/** /**
* A future that works in tandem with a task that was invoked by {@link InitBuilder} * A future that works in tandem with a task that was invoked by
* {@link InitScript}
* *
* @author Adrian Cole * @author Adrian Cole
*/ */
@ -60,23 +67,31 @@ public class BlockUntilInitScriptStatusIsZeroThenReturnOutput extends AbstractFu
protected Logger logger = Logger.NULL; protected Logger logger = Logger.NULL;
private final ExecutorService userThreads; private final ExecutorService userThreads;
private final EventBus eventBus;
private final SudoAwareInitManager commandRunner; private final SudoAwareInitManager commandRunner;
private final RetryablePredicate<String> notRunningAnymore;
private boolean shouldCancel; public SudoAwareInitManager getCommandRunner() {
return commandRunner;
}
private final RetryablePredicate<String> notRunningAnymore;
@Inject @Inject
public BlockUntilInitScriptStatusIsZeroThenReturnOutput( public BlockUntilInitScriptStatusIsZeroThenReturnOutput(
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService userThreads, @Named(Constants.PROPERTY_USER_THREADS) ExecutorService userThreads, EventBus eventBus,
ComputeServiceConstants.InitStatusProperties properties, ComputeServiceConstants.InitStatusProperties properties, final ScriptStatusReturnsZero stateRunning,
final ScriptStatusReturnsZero stateRunning, @Assisted final SudoAwareInitManager commandRunner) { @Assisted final SudoAwareInitManager commandRunner) {
long retryMaxWait = TimeUnit.DAYS.toMillis(365); // arbitrarily high value, but Long.MAX_VALUE doesn't work! long retryMaxWait = TimeUnit.DAYS.toMillis(365); // arbitrarily high
// value, but
// Long.MAX_VALUE doesn't
// work!
long retryInitialPeriod = properties.initStatusInitialPeriod; long retryInitialPeriod = properties.initStatusInitialPeriod;
long retryMaxPeriod = properties.initStatusMaxPeriod; long retryMaxPeriod = properties.initStatusMaxPeriod;
this.commandRunner = checkNotNull(commandRunner, "commandRunner"); this.commandRunner = checkNotNull(commandRunner, "commandRunner");
this.userThreads = checkNotNull(userThreads, "userThreads"); this.userThreads = checkNotNull(userThreads, "userThreads");
this.eventBus = checkNotNull(eventBus, "eventBus");
this.notRunningAnymore = new RetryablePredicate<String>(new Predicate<String>() { this.notRunningAnymore = new RetryablePredicate<String>(new Predicate<String>() {
@Override @Override
@ -85,13 +100,13 @@ public class BlockUntilInitScriptStatusIsZeroThenReturnOutput extends AbstractFu
} }
}, retryMaxWait, retryInitialPeriod, retryMaxPeriod, TimeUnit.MILLISECONDS) { }, retryMaxWait, retryInitialPeriod, retryMaxPeriod, TimeUnit.MILLISECONDS) {
/** /**
* make sure we stop the retry loop if someone cancelled the future, this keeps threads * make sure we stop the retry loop if someone cancelled the future,
* from being consumed on dead tasks * this keeps threads from being consumed on dead tasks
*/ */
@Override @Override
protected boolean atOrAfter(Date end) { protected boolean atOrAfter(Date end) {
if (shouldCancel) if (isCancelled())
Throwables.propagate(new TimeoutException("cancelled")); Throwables.propagate(new CancellationException("cancelled"));
return super.atOrAfter(end); return super.atOrAfter(end);
} }
}; };
@ -105,20 +120,28 @@ public class BlockUntilInitScriptStatusIsZeroThenReturnOutput extends AbstractFu
} }
/** /**
* Submits a thread that will either set the result of the future or the exception that took * Submits a thread that will either set the result of the future or the
* place * exception that took place
*/ */
public BlockUntilInitScriptStatusIsZeroThenReturnOutput init() { public BlockUntilInitScriptStatusIsZeroThenReturnOutput init() {
userThreads.submit(new Runnable() { userThreads.submit(new Runnable() {
@Override @Override
public void run() { public void run() {
try { try {
boolean complete = notRunningAnymore.apply("status"); notRunningAnymore.apply("status");
String stdout = commandRunner.runAction("tail").getOutput(); String stdout = commandRunner.runAction("stdout").getOutput();
String stderr = commandRunner.runAction("tailerr").getOutput(); String stderr = commandRunner.runAction("stderr").getOutput();
// TODO make ScriptBuilder save exit status on nuhup Integer exitStatus = Ints.tryParse(commandRunner.runAction("exitstatus").getOutput().trim());
logger.debug("<< complete(%s) status(%s)", commandRunner.getStatement().getInstanceName(), complete); ExecResponse exec = new ExecResponse(stdout, stderr, exitStatus == null ? -1 : exitStatus);
set(new ExecResponse(stdout, stderr, complete && !shouldCancel ? 0 : -1)); if (exitStatus == null) {
Integer pid = Ints.tryParse(commandRunner.runAction("status").getOutput().trim());
throw new ScriptStillRunningException(String.format("%s still running: pid(%s), last status: %s",
BlockUntilInitScriptStatusIsZeroThenReturnOutput.this, pid, exec),
BlockUntilInitScriptStatusIsZeroThenReturnOutput.this);
}
logger.debug("<< complete(%s) status(%s)", commandRunner.getStatement().getInstanceName(), exitStatus);
set(exec);
} catch (CancellationException e) {
} catch (Exception e) { } catch (Exception e) {
setException(e); setException(e);
} }
@ -127,63 +150,43 @@ public class BlockUntilInitScriptStatusIsZeroThenReturnOutput extends AbstractFu
return this; return this;
} }
@Override
protected boolean set(ExecResponse value) {
eventBus.post(new StatementOnNodeCompletion(getCommandRunner().getStatement(), getCommandRunner().getNode(),
value));
return super.set(value);
}
@Override @Override
protected void interruptTask() { protected void interruptTask() {
logger.debug("<< cancelled(%s)", commandRunner.getStatement().getInstanceName()); logger.debug("<< cancelled(%s)", commandRunner.getStatement().getInstanceName());
commandRunner.refreshAndRunAction("stop"); ExecResponse returnVal = commandRunner.refreshAndRunAction("stop");
shouldCancel = true; CancellationException e = new CancellationException(String.format(
"cancelled %s on node: %s; stop command had exit status: %s", getCommandRunner().getStatement()
.getInstanceName(), getCommandRunner().getNode().getId(), returnVal));
eventBus.post(new StatementOnNodeFailure(getCommandRunner().getStatement(), getCommandRunner().getNode(), e));
super.interruptTask(); super.interruptTask();
} }
@Override @Override
public String toString() { public String toString() {
return String.format("running task[%s]", commandRunner); return Objects.toStringHelper(this).add("commandRunner", commandRunner).toString();
} }
@Override @Override
public int hashCode() { public int hashCode() {
final int prime = 31; return Objects.hashCode(commandRunner);
int result = 1;
result = prime * result + ((commandRunner == null) ? 0 : commandRunner.hashCode());
result = prime * result + ((logger == null) ? 0 : logger.hashCode());
result = prime * result + ((notRunningAnymore == null) ? 0 : notRunningAnymore.hashCode());
result = prime * result + (shouldCancel ? 1231 : 1237);
result = prime * result + ((userThreads == null) ? 0 : userThreads.hashCode());
return result;
} }
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object o) {
if (this == obj) if (o == null)
return true;
if (obj == null)
return false; return false;
if (getClass() != obj.getClass()) if (!o.getClass().equals(getClass()))
return false; return false;
BlockUntilInitScriptStatusIsZeroThenReturnOutput other = (BlockUntilInitScriptStatusIsZeroThenReturnOutput) obj; BlockUntilInitScriptStatusIsZeroThenReturnOutput that = BlockUntilInitScriptStatusIsZeroThenReturnOutput.class
if (commandRunner == null) { .cast(o);
if (other.commandRunner != null) return Objects.equal(this.commandRunner, that.commandRunner);
return false;
} else if (!commandRunner.equals(other.commandRunner))
return false;
if (logger == null) {
if (other.logger != null)
return false;
} else if (!logger.equals(other.logger))
return false;
if (notRunningAnymore == null) {
if (other.notRunningAnymore != null)
return false;
} else if (!notRunningAnymore.equals(other.notRunningAnymore))
return false;
if (shouldCancel != other.shouldCancel)
return false;
if (userThreads == null) {
if (other.userThreads != null)
return false;
} else if (!userThreads.equals(other.userThreads))
return false;
return true;
} }
@Override @Override
@ -192,7 +195,9 @@ public class BlockUntilInitScriptStatusIsZeroThenReturnOutput extends AbstractFu
try { try {
return super.get(timeout, unit); return super.get(timeout, unit);
} catch (TimeoutException e) { } catch (TimeoutException e) {
throw new ScriptStillRunningException(timeout, unit, this); ScriptStillRunningException exception = new ScriptStillRunningException(timeout, unit, this);
exception.initCause(e);
throw exception;
} }
} }

View File

@ -26,7 +26,7 @@ import java.util.concurrent.atomic.AtomicInteger;
import javax.inject.Named; import javax.inject.Named;
import javax.inject.Singleton; import javax.inject.Singleton;
import org.jclouds.scriptbuilder.InitBuilder; import org.jclouds.scriptbuilder.InitScript;
import com.google.common.base.Supplier; import com.google.common.base.Supplier;
import com.google.inject.Inject; import com.google.inject.Inject;
@ -104,8 +104,8 @@ public class InitScriptConfigurationForTasks {
* *
* @return the naming convention of init scripts. ex. {@code /tmp/init-%s}, noting logs are under * @return the naming convention of init scripts. ex. {@code /tmp/init-%s}, noting logs are under
* the basedir/%s where %s is the taskName * the basedir/%s where %s is the taskName
* @see InitBuilder#getHomeDir * @see InitScript#getHomeDir
* @see InitBuilder#getLogDir * @see InitScript#getLogDir
*/ */
public String getInitScriptPattern() { public String getInitScriptPattern() {
return initScriptPattern; return initScriptPattern;

View File

@ -21,19 +21,15 @@ package org.jclouds.compute.callables;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState; import static com.google.common.base.Preconditions.checkState;
import java.util.Collections;
import javax.annotation.Resource;
import javax.inject.Named;
import org.jclouds.compute.domain.ExecResponse; import org.jclouds.compute.domain.ExecResponse;
import org.jclouds.compute.domain.NodeMetadata; import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.domain.NodeMetadataBuilder; import org.jclouds.compute.domain.NodeMetadataBuilder;
import org.jclouds.compute.events.InitScriptOnNodeSubmission;
import org.jclouds.compute.events.StatementOnNodeCompletion;
import org.jclouds.compute.events.StatementOnNodeFailure;
import org.jclouds.compute.options.RunScriptOptions; import org.jclouds.compute.options.RunScriptOptions;
import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.domain.LoginCredentials; import org.jclouds.domain.LoginCredentials;
import org.jclouds.logging.Logger; import org.jclouds.scriptbuilder.InitScript;
import org.jclouds.scriptbuilder.InitBuilder;
import org.jclouds.scriptbuilder.domain.AdminAccessVisitor; import org.jclouds.scriptbuilder.domain.AdminAccessVisitor;
import org.jclouds.scriptbuilder.domain.AppendFile; import org.jclouds.scriptbuilder.domain.AppendFile;
import org.jclouds.scriptbuilder.domain.OsFamily; import org.jclouds.scriptbuilder.domain.OsFamily;
@ -45,6 +41,8 @@ import org.jclouds.ssh.SshException;
import com.google.common.base.Function; import com.google.common.base.Function;
import com.google.common.base.Splitter; import com.google.common.base.Splitter;
import com.google.common.base.Throwables;
import com.google.common.eventbus.EventBus;
import com.google.inject.assistedinject.Assisted; import com.google.inject.assistedinject.Assisted;
import com.google.inject.assistedinject.AssistedInject; import com.google.inject.assistedinject.AssistedInject;
@ -53,28 +51,18 @@ import com.google.inject.assistedinject.AssistedInject;
* @author Adrian Cole * @author Adrian Cole
*/ */
public class RunScriptOnNodeAsInitScriptUsingSsh extends SudoAwareInitManager implements RunScriptOnNode { public class RunScriptOnNodeAsInitScriptUsingSsh extends SudoAwareInitManager implements RunScriptOnNode {
@Resource
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
protected Logger logger = Logger.NULL;
protected final String initFile; protected final EventBus eventBus;
/**
* @return the absolute path to the file on disk relating to this task.
*/
public String getInitFile() {
return initFile;
}
@AssistedInject @AssistedInject
public RunScriptOnNodeAsInitScriptUsingSsh(Function<NodeMetadata, SshClient> sshFactory, public RunScriptOnNodeAsInitScriptUsingSsh(Function<NodeMetadata, SshClient> sshFactory, EventBus eventBus,
InitScriptConfigurationForTasks initScriptConfiguration, @Assisted NodeMetadata node, InitScriptConfigurationForTasks initScriptConfiguration, @Assisted NodeMetadata node,
@Assisted Statement script, @Assisted RunScriptOptions options) { @Assisted Statement script, @Assisted RunScriptOptions options) {
super(sshFactory, options.shouldRunAsRoot(), checkNotNull(node, "node"), super(sshFactory, options.shouldRunAsRoot(), checkNotNull(node, "node"),
checkNotNull(script, "script") instanceof InitBuilder ? InitBuilder.class.cast(script) initScriptConfiguration, checkNotNull(script, "script") instanceof InitScript ? InitScript.class.cast(script)
: createInitScript(checkNotNull(initScriptConfiguration, "initScriptConfiguration"), options : createInitScript(checkNotNull(initScriptConfiguration, "initScriptConfiguration"), options
.getTaskName(), script)); .getTaskName(), script));
this.initFile = String.format(initScriptConfiguration.getInitScriptPattern(), init.getInstanceName()); this.eventBus = checkNotNull(eventBus, "eventBus");
} }
@Override @Override
@ -88,19 +76,20 @@ public class RunScriptOnNodeAsInitScriptUsingSsh extends SudoAwareInitManager im
checkState(ssh != null, "please call init() before invoking call"); checkState(ssh != null, "please call init() before invoking call");
try { try {
ssh.connect(); ssh.connect();
return doCall(); ExecResponse returnVal = doCall();
eventBus.post(new StatementOnNodeCompletion(init, node, returnVal));
return returnVal;
} finally { } finally {
if (ssh != null) if (ssh != null)
ssh.disconnect(); ssh.disconnect();
} }
} }
public static InitBuilder createInitScript(InitScriptConfigurationForTasks config, String name, Statement script) { public static InitScript createInitScript(InitScriptConfigurationForTasks config, String name, Statement script) {
if (name == null) { if (name == null) {
name = "jclouds-script-" + config.getAnonymousTaskSuffixSupplier().get(); name = "jclouds-script-" + config.getAnonymousTaskSuffixSupplier().get();
} }
return new InitBuilder(name, config.getBasedir() + "/" + name, config.getBasedir() + "/" + name, Collections return InitScript.builder().name(name).home(config.getBasedir() + "/" + name).run(script).build();
.<String, String> emptyMap(), Collections.singleton(script));
} }
protected void refreshSshIfNewAdminCredentialsConfigured(AdminAccess input) { protected void refreshSshIfNewAdminCredentialsConfigured(AdminAccess input) {
@ -115,10 +104,13 @@ public class RunScriptOnNodeAsInitScriptUsingSsh extends SudoAwareInitManager im
} }
protected ExecResponse doCall() { protected ExecResponse doCall() {
eventBus.post(new InitScriptOnNodeSubmission(init, node));
try {
try { try {
ssh.put(initFile, init.render(OsFamily.UNIX)); ssh.put(initFile, init.render(OsFamily.UNIX));
} catch (SshException e) { } catch (SshException e) {
// If there's a problem with the sftp configuration, we can try via ssh exec // If there's a problem with the sftp configuration, we can try via
// ssh exec
if (logger.isTraceEnabled()) if (logger.isTraceEnabled())
logger.warn(e, "<< (%s) problem using sftp [%s], attempting via sshexec", ssh.toString(), e.getMessage()); logger.warn(e, "<< (%s) problem using sftp [%s], attempting via sshexec", ssh.toString(), e.getMessage());
else else
@ -127,7 +119,7 @@ public class RunScriptOnNodeAsInitScriptUsingSsh extends SudoAwareInitManager im
ssh.connect(); ssh.connect();
ssh.exec("rm " + initFile); ssh.exec("rm " + initFile);
ssh.exec(Statements.appendFile(initFile, Splitter.on('\n').split(init.render(OsFamily.UNIX)), ssh.exec(Statements.appendFile(initFile, Splitter.on('\n').split(init.render(OsFamily.UNIX)),
AppendFile.MARKER + "_" + init.getInstanceName()).render(OsFamily.UNIX)); AppendFile.DELIMETER + "_" + init.getInstanceName()).render(OsFamily.UNIX));
} }
ssh.exec("chmod 755 " + initFile); ssh.exec("chmod 755 " + initFile);
@ -143,6 +135,10 @@ public class RunScriptOnNodeAsInitScriptUsingSsh extends SudoAwareInitManager im
}); });
return runAction("start"); return runAction("start");
} catch (Throwable e) {
eventBus.post(new StatementOnNodeFailure(init, node, e));
throw Throwables.propagate(e);
}
} }
protected void setupLinkToInitFile() { protected void setupLinkToInitFile() {

View File

@ -19,7 +19,6 @@
package org.jclouds.compute.callables; package org.jclouds.compute.callables;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@ -27,6 +26,7 @@ import javax.inject.Inject;
import org.jclouds.compute.domain.ExecResponse; import org.jclouds.compute.domain.ExecResponse;
import org.jclouds.compute.domain.NodeMetadata; import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.events.StatementOnNodeFailure;
import org.jclouds.compute.options.RunScriptOptions; import org.jclouds.compute.options.RunScriptOptions;
import org.jclouds.compute.reference.ComputeServiceConstants.Timeouts; import org.jclouds.compute.reference.ComputeServiceConstants.Timeouts;
import org.jclouds.scriptbuilder.domain.Statement; import org.jclouds.scriptbuilder.domain.Statement;
@ -34,6 +34,7 @@ import org.jclouds.ssh.SshClient;
import com.google.common.base.Function; import com.google.common.base.Function;
import com.google.common.base.Throwables; import com.google.common.base.Throwables;
import com.google.common.eventbus.EventBus;
import com.google.inject.assistedinject.Assisted; import com.google.inject.assistedinject.Assisted;
/** /**
@ -47,9 +48,10 @@ public class RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilComplete extends Ru
@Inject @Inject
public RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilComplete( public RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilComplete(
BlockUntilInitScriptStatusIsZeroThenReturnOutput.Factory statusFactory, Timeouts timeouts, BlockUntilInitScriptStatusIsZeroThenReturnOutput.Factory statusFactory, Timeouts timeouts,
Function<NodeMetadata, SshClient> sshFactory, InitScriptConfigurationForTasks initScriptConfiguration, Function<NodeMetadata, SshClient> sshFactory, EventBus eventBus,
@Assisted NodeMetadata node, @Assisted Statement script, @Assisted RunScriptOptions options) { InitScriptConfigurationForTasks initScriptConfiguration, @Assisted NodeMetadata node,
super(sshFactory, initScriptConfiguration, node, script, options); @Assisted Statement script, @Assisted RunScriptOptions options) {
super(sshFactory, eventBus, initScriptConfiguration, node, script, options);
this.statusFactory = checkNotNull(statusFactory, "statusFactory"); this.statusFactory = checkNotNull(statusFactory, "statusFactory");
this.timeouts = checkNotNull(timeouts, "timeouts"); this.timeouts = checkNotNull(timeouts, "timeouts");
} }
@ -58,16 +60,21 @@ public class RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilComplete extends Ru
public ExecResponse doCall() { public ExecResponse doCall() {
try { try {
return future().get(timeouts.scriptComplete, TimeUnit.MILLISECONDS); return future().get(timeouts.scriptComplete, TimeUnit.MILLISECONDS);
} catch (Exception e) { } catch (Throwable e) {
Throwables.propagate(e); eventBus.post(new StatementOnNodeFailure(init, node, e));
return null; throw Throwables.propagate(e);
} }
} }
public BlockUntilInitScriptStatusIsZeroThenReturnOutput future() { public BlockUntilInitScriptStatusIsZeroThenReturnOutput future() {
ExecResponse returnVal = super.doCall(); ExecResponse returnVal = super.doCall();
checkState(returnVal.getExitCode() == 0, String.format("task: %s had non-zero exit status: %s", init if (returnVal.getExitStatus() != 0) {
.getInstanceName(), returnVal)); IllegalStateException e = new IllegalStateException(String.format(
"instance: %s on node: %s had non-zero exit status: %s", init.getInstanceName(), getNode().getId(),
returnVal));
eventBus.post(new StatementOnNodeFailure(init, node, e));
throw e;
}
return statusFactory.create(this).init(); return statusFactory.create(this).init();
} }

View File

@ -26,6 +26,9 @@ import javax.inject.Named;
import org.jclouds.compute.domain.ExecResponse; import org.jclouds.compute.domain.ExecResponse;
import org.jclouds.compute.domain.NodeMetadata; import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.events.StatementOnNodeFailure;
import org.jclouds.compute.events.StatementOnNodeCompletion;
import org.jclouds.compute.events.StatementOnNodeSubmission;
import org.jclouds.compute.options.RunScriptOptions; import org.jclouds.compute.options.RunScriptOptions;
import org.jclouds.compute.reference.ComputeServiceConstants; import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.logging.Logger; import org.jclouds.logging.Logger;
@ -36,6 +39,8 @@ import org.jclouds.ssh.SshClient;
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function; import com.google.common.base.Function;
import com.google.common.base.Objects; import com.google.common.base.Objects;
import com.google.common.base.Throwables;
import com.google.common.eventbus.EventBus;
import com.google.inject.assistedinject.Assisted; import com.google.inject.assistedinject.Assisted;
import com.google.inject.assistedinject.AssistedInject; import com.google.inject.assistedinject.AssistedInject;
@ -51,6 +56,7 @@ public class RunScriptOnNodeUsingSsh implements RunScriptOnNode {
protected Logger logger = Logger.NULL; protected Logger logger = Logger.NULL;
protected final Function<NodeMetadata, SshClient> sshFactory; protected final Function<NodeMetadata, SshClient> sshFactory;
protected final EventBus eventBus;
protected final NodeMetadata node; protected final NodeMetadata node;
protected final Statement statement; protected final Statement statement;
protected final boolean runAsRoot; protected final boolean runAsRoot;
@ -58,9 +64,10 @@ public class RunScriptOnNodeUsingSsh implements RunScriptOnNode {
protected SshClient ssh; protected SshClient ssh;
@AssistedInject @AssistedInject
public RunScriptOnNodeUsingSsh(Function<NodeMetadata, SshClient> sshFactory, @Assisted NodeMetadata node, public RunScriptOnNodeUsingSsh(Function<NodeMetadata, SshClient> sshFactory, EventBus eventBus,
@Assisted Statement statement, @Assisted RunScriptOptions options) { @Assisted NodeMetadata node, @Assisted Statement statement, @Assisted RunScriptOptions options) {
this.sshFactory = checkNotNull(sshFactory, "sshFactory"); this.sshFactory = checkNotNull(sshFactory, "sshFactory");
this.eventBus = checkNotNull(eventBus, "eventBus");
this.node = checkNotNull(node, "node"); this.node = checkNotNull(node, "node");
this.statement = checkNotNull(statement, "statement"); this.statement = checkNotNull(statement, "statement");
this.runAsRoot = options.shouldRunAsRoot(); this.runAsRoot = options.shouldRunAsRoot();
@ -72,13 +79,20 @@ public class RunScriptOnNodeUsingSsh implements RunScriptOnNode {
try { try {
ssh.connect(); ssh.connect();
ExecResponse returnVal; ExecResponse returnVal;
eventBus.post(new StatementOnNodeSubmission(statement, node));
String command = (runAsRoot) ? execAsRoot(statement.render(OsFamily.UNIX)) : execScriptAsDefaultUser(statement String command = (runAsRoot) ? execAsRoot(statement.render(OsFamily.UNIX)) : execScriptAsDefaultUser(statement
.render(OsFamily.UNIX)); .render(OsFamily.UNIX));
try {
returnVal = runCommand(command); returnVal = runCommand(command);
} catch (Throwable e) {
eventBus.post(new StatementOnNodeFailure(statement, node, e));
throw Throwables.propagate(e);
}
eventBus.post(new StatementOnNodeCompletion(statement, node, returnVal));
if (logger.isTraceEnabled()) if (logger.isTraceEnabled())
logger.trace("<< %s[%s]", statement, returnVal); logger.trace("<< %s[%s]", statement, returnVal);
else else
logger.debug("<< %s(%d)", statement, returnVal.getExitCode()); logger.debug("<< %s(%d)", statement, returnVal.getExitStatus());
return returnVal; return returnVal;
} finally { } finally {
if (ssh != null) if (ssh != null)

View File

@ -28,7 +28,7 @@ import org.jclouds.compute.domain.ExecResponse;
import org.jclouds.compute.domain.NodeMetadata; import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.reference.ComputeServiceConstants; import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.logging.Logger; import org.jclouds.logging.Logger;
import org.jclouds.scriptbuilder.InitBuilder; import org.jclouds.scriptbuilder.InitScript;
import org.jclouds.ssh.SshClient; import org.jclouds.ssh.SshClient;
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
@ -47,16 +47,25 @@ public class SudoAwareInitManager {
protected Logger computeLogger = Logger.NULL; protected Logger computeLogger = Logger.NULL;
protected Logger logger = Logger.NULL; protected Logger logger = Logger.NULL;
protected NodeMetadata node; protected NodeMetadata node;
protected final InitBuilder init; protected final String initFile;
protected final InitScript init;
protected final boolean runAsRoot; protected final boolean runAsRoot;
protected final Function<NodeMetadata, SshClient> sshFactory; protected final Function<NodeMetadata, SshClient> sshFactory;
protected SshClient ssh; protected SshClient ssh;
/**
* @return the absolute path to the file on disk relating to this task.
*/
public String getInitFile() {
return initFile;
}
public SudoAwareInitManager(Function<NodeMetadata, SshClient> sshFactory, boolean runAsRoot, NodeMetadata node, public SudoAwareInitManager(Function<NodeMetadata, SshClient> sshFactory, boolean runAsRoot, NodeMetadata node,
InitBuilder init) { InitScriptConfigurationForTasks initScriptConfiguration, InitScript init) {
this.sshFactory = checkNotNull(sshFactory, "sshFactory"); this.sshFactory = checkNotNull(sshFactory, "sshFactory");
this.runAsRoot = runAsRoot; this.runAsRoot = runAsRoot;
this.node = checkNotNull(node, "node"); this.node = checkNotNull(node, "node");
this.initFile = String.format(initScriptConfiguration.getInitScriptPattern(), init.getInstanceName());
this.init = checkNotNull(init, "init"); this.init = checkNotNull(init, "init");
} }
@ -82,41 +91,44 @@ public class SudoAwareInitManager {
: execScriptAsDefaultUser(action); : execScriptAsDefaultUser(action);
returnVal = runCommand(command); returnVal = runCommand(command);
if ("status".equals(action)) if ("status".equals(action))
logger.trace("<< %s(%d)", action, returnVal.getExitCode()); logger.trace("<< %s(%d)", action, returnVal.getExitStatus());
else if (computeLogger.isTraceEnabled()) else if (computeLogger.isTraceEnabled())
computeLogger.trace("<< %s[%s]", action, returnVal); computeLogger.trace("<< %s[%s]", action, returnVal);
else else
computeLogger.debug("<< %s(%d)", action, returnVal.getExitCode()); computeLogger.debug("<< %s(%d)", action, returnVal.getExitStatus());
return returnVal; return returnVal;
} }
ExecResponse runCommand(String command) { ExecResponse runCommand(String command) {
String statement = String.format(">> running [%s] as %s@%s", command.replace( String statement = String.format("[%s] as %s@%s", command.replace(
node.getCredentials().getPassword() != null ? node.getCredentials().getPassword() : "XXXXX", "XXXXX"), ssh node.getCredentials().getPassword() != null ? node.getCredentials().getPassword() : "XXXXX", "XXXXX"), ssh
.getUsername(), ssh.getHostAddress()); .getUsername(), ssh.getHostAddress());
if (command.endsWith("status")) if (command.endsWith("status"))
logger.trace(statement); logger.trace(">> running " + statement);
else else
computeLogger.debug(statement); computeLogger.debug(">> running " + statement);
return ssh.exec(command); ExecResponse returnVal = ssh.exec(command);
if (!command.endsWith("status"))
checkState(returnVal.getExitStatus() == 0, "error running %s; returnVal !=0: %s", statement, returnVal);
return returnVal;
} }
@VisibleForTesting @VisibleForTesting
String execScriptAsRoot(String action) { String execScriptAsRoot(String action) {
String command; String command;
if (node.getCredentials().identity.equals("root")) { if (node.getCredentials().identity.equals("root")) {
command = "./" + init.getInstanceName() + " " + action; command = initFile + " " + action;
} else if (node.getCredentials().shouldAuthenticateSudo()) { } else if (node.getCredentials().shouldAuthenticateSudo()) {
command = String.format("echo '%s'|sudo -S ./%s %s", node.getCredentials().getPassword(), command = String.format("echo '%s'|sudo -S %s %s", node.getCredentials().getPassword(),
init.getInstanceName(), action); initFile, action);
} else { } else {
command = "sudo ./" + init.getInstanceName() + " " + action; command = "sudo " + initFile + " " + action;
} }
return command; return command;
} }
protected String execScriptAsDefaultUser(String action) { protected String execScriptAsDefaultUser(String action) {
return "./" + init.getInstanceName() + " " + action; return initFile + " " + action;
} }
public NodeMetadata getNode() { public NodeMetadata getNode() {
@ -125,11 +137,11 @@ public class SudoAwareInitManager {
@Override @Override
public String toString() { public String toString() {
return Objects.toStringHelper(this).add("node", node).add("name", init.getInstanceName()) return Objects.toStringHelper(this).add("node", node.getId()).add("name", init.getInstanceName())
.add("runAsRoot", runAsRoot).toString(); .add("runAsRoot", runAsRoot).toString();
} }
public InitBuilder getStatement() { public InitScript getStatement() {
return init; return init;
} }
} }

View File

@ -103,7 +103,7 @@ public abstract class BaseComputeServiceContextModule extends AbstractModule {
install(new FactoryModuleBuilder().implement(new TypeLiteral<Callable<Void>>() { install(new FactoryModuleBuilder().implement(new TypeLiteral<Callable<Void>>() {
}, CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap.class) }, CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap.class)
.implement(new TypeLiteral<Function<NodeMetadata, Void>>() { .implement(new TypeLiteral<Function<AtomicReference<NodeMetadata>, Void>>() {
}, CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap.class) }, CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap.class)
.build(CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap.Factory.class)); .build(CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap.Factory.class));

View File

@ -20,10 +20,13 @@ package org.jclouds.compute.config;
import static com.google.common.base.Predicates.not; import static com.google.common.base.Predicates.not;
import java.util.concurrent.atomic.AtomicReference;
import javax.inject.Named; import javax.inject.Named;
import javax.inject.Singleton; import javax.inject.Singleton;
import org.jclouds.compute.domain.NodeMetadata; import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.predicates.AtomicNodeRunning;
import org.jclouds.compute.predicates.NodeRunning; import org.jclouds.compute.predicates.NodeRunning;
import org.jclouds.compute.predicates.NodeSuspended; import org.jclouds.compute.predicates.NodeSuspended;
import org.jclouds.compute.predicates.NodeTerminated; import org.jclouds.compute.predicates.NodeTerminated;
@ -46,6 +49,32 @@ public class ComputeServiceTimeoutsModule extends AbstractModule {
@Provides @Provides
@Singleton @Singleton
@Named("NODE_RUNNING") @Named("NODE_RUNNING")
protected Predicate<AtomicReference<NodeMetadata>> nodeRunning(AtomicNodeRunning stateRunning, Timeouts timeouts) {
return timeouts.nodeRunning == 0 ? stateRunning : new RetryablePredicate<AtomicReference<NodeMetadata>>(stateRunning,
timeouts.nodeRunning);
}
@Provides
@Singleton
@Named("NODE_TERMINATED")
protected Predicate<AtomicReference<NodeMetadata>> serverTerminated(AtomicNodeRunning stateTerminated, Timeouts timeouts) {
return timeouts.nodeTerminated == 0 ? stateTerminated : new RetryablePredicate<AtomicReference<NodeMetadata>>(stateTerminated,
timeouts.nodeTerminated);
}
@Provides
@Singleton
@Named("NODE_SUSPENDED")
protected Predicate<AtomicReference<NodeMetadata>> serverSuspended(AtomicNodeRunning stateSuspended, Timeouts timeouts) {
return timeouts.nodeSuspended == 0 ? stateSuspended : new RetryablePredicate<AtomicReference<NodeMetadata>>(stateSuspended,
timeouts.nodeSuspended);
}
@Provides
@Singleton
@Named("NODE_RUNNING")
@Deprecated
protected Predicate<NodeMetadata> nodeRunning(NodeRunning stateRunning, Timeouts timeouts) { protected Predicate<NodeMetadata> nodeRunning(NodeRunning stateRunning, Timeouts timeouts) {
return timeouts.nodeRunning == 0 ? stateRunning : new RetryablePredicate<NodeMetadata>(stateRunning, return timeouts.nodeRunning == 0 ? stateRunning : new RetryablePredicate<NodeMetadata>(stateRunning,
timeouts.nodeRunning); timeouts.nodeRunning);
@ -54,6 +83,7 @@ public class ComputeServiceTimeoutsModule extends AbstractModule {
@Provides @Provides
@Singleton @Singleton
@Named("NODE_TERMINATED") @Named("NODE_TERMINATED")
@Deprecated
protected Predicate<NodeMetadata> serverTerminated(NodeTerminated stateTerminated, Timeouts timeouts) { protected Predicate<NodeMetadata> serverTerminated(NodeTerminated stateTerminated, Timeouts timeouts) {
return timeouts.nodeTerminated == 0 ? stateTerminated : new RetryablePredicate<NodeMetadata>(stateTerminated, return timeouts.nodeTerminated == 0 ? stateTerminated : new RetryablePredicate<NodeMetadata>(stateTerminated,
timeouts.nodeTerminated); timeouts.nodeTerminated);
@ -63,6 +93,7 @@ public class ComputeServiceTimeoutsModule extends AbstractModule {
@Provides @Provides
@Singleton @Singleton
@Named("NODE_SUSPENDED") @Named("NODE_SUSPENDED")
@Deprecated
protected Predicate<NodeMetadata> serverSuspended(NodeSuspended stateSuspended, Timeouts timeouts) { protected Predicate<NodeMetadata> serverSuspended(NodeSuspended stateSuspended, Timeouts timeouts) {
return timeouts.nodeSuspended == 0 ? stateSuspended : new RetryablePredicate<NodeMetadata>(stateSuspended, return timeouts.nodeSuspended == 0 ? stateSuspended : new RetryablePredicate<NodeMetadata>(stateSuspended,
timeouts.nodeSuspended); timeouts.nodeSuspended);

View File

@ -20,19 +20,21 @@ package org.jclouds.compute.domain;
import org.jclouds.compute.config.CustomizationResponse; import org.jclouds.compute.config.CustomizationResponse;
import com.google.common.base.Objects;
/** /**
* @author Adrian Cole * @author Adrian Cole
*/ */
public class ExecResponse implements CustomizationResponse { public class ExecResponse implements CustomizationResponse {
private final String error;
private final String output; private final String output;
private final int exitCode; private final String error;
private final int exitStatus;
public ExecResponse(String output, String error, int exitCode) { public ExecResponse(String output, String error, int exitStatus) {
this.output = output; this.output = output;
this.error = error; this.error = error;
this.exitCode = exitCode; this.exitStatus = exitStatus;
} }
public String getError() { public String getError() {
@ -43,47 +45,38 @@ public class ExecResponse implements CustomizationResponse {
return output; return output;
} }
@Override /**
public String toString() { * @see #getExitStatus
return "[output=" + output + ", error=" + error + ", exitCode=" + exitCode + "]"; */
@Deprecated
public int getExitCode() {
return exitStatus;
}
public int getExitStatus() {
return exitStatus;
} }
@Override @Override
public int hashCode() { public int hashCode() {
final int prime = 31; return Objects.hashCode(output, error, exitStatus);
int result = 1;
result = prime * result + ((error == null) ? 0 : error.hashCode());
result = prime * result + exitCode;
result = prime * result + ((output == null) ? 0 : output.hashCode());
return result;
} }
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object o) {
if (this == obj) if (o == null)
return true;
if (obj == null)
return false; return false;
if (getClass() != obj.getClass()) if (!o.getClass().equals(getClass()))
return false; return false;
ExecResponse other = (ExecResponse) obj; ExecResponse that = ExecResponse.class.cast(o);
if (error == null) { return Objects.equal(this.output, that.output) && Objects.equal(this.error, that.error)
if (other.error != null) && Objects.equal(this.exitStatus, that.exitStatus);
return false;
} else if (!error.equals(other.error))
return false;
if (exitCode != other.exitCode)
return false;
if (output == null) {
if (other.output != null)
return false;
} else if (!output.equals(other.output))
return false;
return true;
} }
public int getExitCode() { @Override
return exitCode; public String toString() {
return Objects.toStringHelper("").add("output", output).add("error", error).add("exitStatus", exitStatus)
.toString();
} }
} }

View File

@ -69,6 +69,11 @@ public interface TemplateBuilder {
*/ */
TemplateBuilder biggest(); TemplateBuilder biggest();
/**
* Configure this template to have an hypervisor that matches the regular expression
*/
TemplateBuilder hypervisorMatches(String hypervisorRegex);
/** /**
* Configure this template to use a specific operating system image. * Configure this template to use a specific operating system image.
*/ */

View File

@ -220,7 +220,6 @@ public class NodeMetadataImpl extends ComputeMetadataImpl implements NodeMetadat
result = prime * result + ((imageId == null) ? 0 : imageId.hashCode()); result = prime * result + ((imageId == null) ? 0 : imageId.hashCode());
result = prime * result + ((hardware == null) ? 0 : hardware.hashCode()); result = prime * result + ((hardware == null) ? 0 : hardware.hashCode());
result = prime * result + ((os == null) ? 0 : os.hashCode()); result = prime * result + ((os == null) ? 0 : os.hashCode());
result = prime * result + ((credentials == null) ? 0 : credentials.hashCode());
return result; return result;
} }
@ -270,11 +269,6 @@ public class NodeMetadataImpl extends ComputeMetadataImpl implements NodeMetadat
return false; return false;
} else if (!os.equals(other.os)) } else if (!os.equals(other.os))
return false; return false;
if (credentials == null) {
if (other.credentials != null)
return false;
} else if (!credentials.equals(other.credentials))
return false;
return true; return true;
} }

View File

@ -89,6 +89,8 @@ public class TemplateBuilderImpl implements TemplateBuilder {
@VisibleForTesting @VisibleForTesting
protected String hardwareId; protected String hardwareId;
@VisibleForTesting @VisibleForTesting
protected String hypervisor;
@VisibleForTesting
protected String imageVersion; protected String imageVersion;
@VisibleForTesting @VisibleForTesting
protected OsFamily osFamily; protected OsFamily osFamily;
@ -347,12 +349,17 @@ public class TemplateBuilderImpl implements TemplateBuilder {
return "imageDescription(" + imageDescription + ")"; return "imageDescription(" + imageDescription + ")";
} }
}; };
private final Predicate<Hardware> hardwareIdPredicate = new Predicate<Hardware>() { private final Predicate<Hardware> hardwareIdPredicate = new Predicate<Hardware>() {
@Override @Override
public boolean apply(Hardware input) { public boolean apply(Hardware input) {
boolean returnVal = true; boolean returnVal = true;
if (hardwareId != null) { if (hardwareId != null) {
returnVal = hardwareId.equals(input.getId()); returnVal = hardwareId.equals(input.getId());
// match our input params so that the later predicates pass.
if (returnVal) {
fromHardware(input);
}
} }
return returnVal; return returnVal;
} }
@ -363,6 +370,26 @@ public class TemplateBuilderImpl implements TemplateBuilder {
} }
}; };
private final Predicate<Hardware> hypervisorPredicate = new Predicate<Hardware>() {
@Override
public boolean apply(Hardware input) {
boolean returnVal = true;
if (hypervisor != null) {
if (input.getHypervisor() == null)
returnVal = false;
else
returnVal = input.getHypervisor().contains(hypervisor)
|| input.getHypervisor().matches(hypervisor);
}
return returnVal;
}
@Override
public String toString() {
return "hypervisorMatches(" + hypervisor + ")";
}
};
private final Predicate<Hardware> hardwareCoresPredicate = new Predicate<Hardware>() { private final Predicate<Hardware> hardwareCoresPredicate = new Predicate<Hardware>() {
@Override @Override
public boolean apply(Hardware input) { public boolean apply(Hardware input) {
@ -406,6 +433,8 @@ public class TemplateBuilderImpl implements TemplateBuilder {
return locationPredicate.toString(); return locationPredicate.toString();
} }
}); });
if (hypervisor != null)
predicates.add(hypervisorPredicate);
predicates.add(hardwareCoresPredicate); predicates.add(hardwareCoresPredicate);
predicates.add(hardwareRamPredicate); predicates.add(hardwareRamPredicate);
} }
@ -466,6 +495,7 @@ public class TemplateBuilderImpl implements TemplateBuilder {
this.location = hardware.getLocation(); this.location = hardware.getLocation();
this.minCores = getCores(hardware); this.minCores = getCores(hardware);
this.minRam = hardware.getRam(); this.minRam = hardware.getRam();
this.hypervisor = hardware.getHypervisor();
return this; return this;
} }
@ -901,6 +931,16 @@ public class TemplateBuilderImpl implements TemplateBuilder {
@Override @Override
public TemplateBuilder hardwareId(String hardwareId) { public TemplateBuilder hardwareId(String hardwareId) {
this.hardwareId = hardwareId; this.hardwareId = hardwareId;
this.hypervisor = null;
return this;
}
/**
* {@inheritDoc}
*/
@Override
public TemplateBuilder hypervisorMatches(String hypervisor) {
this.hypervisor = hypervisor;
return this; return this;
} }
@ -916,10 +956,10 @@ public class TemplateBuilderImpl implements TemplateBuilder {
@VisibleForTesting @VisibleForTesting
boolean nothingChangedExceptOptions() { boolean nothingChangedExceptOptions() {
return osFamily == null && location == null && imageId == null && hardwareId == null && osName == null return osFamily == null && location == null && imageId == null && hardwareId == null && hypervisor == null
&& imagePredicate == null && osDescription == null && imageVersion == null && osVersion == null && osName == null && imagePredicate == null && osDescription == null && imageVersion == null
&& osArch == null && os64Bit == null && imageName == null && imageDescription == null && minCores == 0 && osVersion == null && osArch == null && os64Bit == null && imageName == null && imageDescription == null
&& minRam == 0 && !biggest && !fastest; && minCores == 0 && minRam == 0 && !biggest && !fastest;
} }
/** /**
@ -936,7 +976,7 @@ public class TemplateBuilderImpl implements TemplateBuilder {
+ imageDescription + ", imageId=" + imageId + ", imagePredicate=" + imagePredicate + ", imageVersion=" + imageVersion + ", location=" + location + imageDescription + ", imageId=" + imageId + ", imagePredicate=" + imagePredicate + ", imageVersion=" + imageVersion + ", location=" + location
+ ", minCores=" + minCores + ", minRam=" + minRam + ", osFamily=" + osFamily + ", osName=" + osName + ", minCores=" + minCores + ", minRam=" + minRam + ", osFamily=" + osFamily + ", osName=" + osName
+ ", osDescription=" + osDescription + ", osVersion=" + osVersion + ", osArch=" + osArch + ", os64Bit=" + ", osDescription=" + osDescription + ", osVersion=" + osVersion + ", osArch=" + osArch + ", os64Bit="
+ os64Bit + ", hardwareId=" + hardwareId + "]"; + os64Bit + ", hardwareId=" + hardwareId + ", hypervisor=" + hypervisor + "]";
} }
@Override @Override

View File

@ -0,0 +1,44 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.compute.events;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.scriptbuilder.InitScript;
import com.google.common.annotations.Beta;
/**
* An init script was submitted to a node for exectuion.
* <p/>
* Note this does not guarantee that there was success, nor that the init script started.
*
* @author Adrian Cole
*/
@Beta
public class InitScriptOnNodeSubmission extends StatementOnNodeSubmission {
public InitScriptOnNodeSubmission(InitScript statement, NodeMetadata node) {
super(statement, node);
}
public InitScript getStatement() {
return InitScript.class.cast(statement);
}
}

View File

@ -0,0 +1,76 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.compute.events;
import static com.google.common.base.Preconditions.checkNotNull;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.scriptbuilder.domain.Statement;
import com.google.common.annotations.Beta;
import com.google.common.base.Objects;
import com.google.common.base.Objects.ToStringHelper;
/**
* @author Adrian Cole
*/
@Beta
public class StatementOnNode {
protected final Statement statement;
protected final NodeMetadata node;
public StatementOnNode(Statement statement, NodeMetadata node) {
this.statement = checkNotNull(statement, "statement");
this.node = checkNotNull(node, "node");
}
public Statement getStatement() {
return statement;
}
public NodeMetadata getNode() {
return node;
}
@Override
public int hashCode() {
return Objects.hashCode(statement, node);
}
@Override
public boolean equals(Object o) {
if (o == null)
return false;
if (!o.getClass().equals(getClass()))
return false;
StatementOnNode that = StatementOnNode.class.cast(o);
return Objects.equal(this.statement, that.statement) && Objects.equal(this.node, that.node);
}
@Override
public String toString() {
return string().toString();
}
protected ToStringHelper string() {
return Objects.toStringHelper(this).add("statement", statement).add("node", node.getId());
}
}

View File

@ -0,0 +1,53 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.compute.events;
import static com.google.common.base.Preconditions.checkNotNull;
import org.jclouds.compute.domain.ExecResponse;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.scriptbuilder.domain.Statement;
import com.google.common.annotations.Beta;
import com.google.common.base.Objects.ToStringHelper;
/**
* A statement that completed execution on a node.
*
* @author Adrian Cole
*/
@Beta
public class StatementOnNodeCompletion extends StatementOnNode {
private final ExecResponse response;
public StatementOnNodeCompletion(Statement statement, NodeMetadata node, ExecResponse response) {
super(statement, node);
this.response = checkNotNull(response, "response");
}
public ExecResponse getResponse() {
return response;
}
@Override
protected ToStringHelper string() {
return super.string().add("response", response);
}
}

View File

@ -0,0 +1,52 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.compute.events;
import static com.google.common.base.Preconditions.checkNotNull;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.scriptbuilder.domain.Statement;
import com.google.common.annotations.Beta;
import com.google.common.base.Objects.ToStringHelper;
/**
* A statement that failed execution on a node.
*
* @author Adrian Cole
*/
@Beta
public class StatementOnNodeFailure extends StatementOnNode {
private final Throwable cause;
public StatementOnNodeFailure(Statement statement, NodeMetadata node, Throwable cause) {
super(statement, node);
this.cause = checkNotNull(cause, "cause");
}
public Throwable getCause() {
return cause;
}
@Override
protected ToStringHelper string() {
return super.string().add("cause", cause.getMessage());
}
}

View File

@ -0,0 +1,41 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.compute.events;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.scriptbuilder.domain.Statement;
import com.google.common.annotations.Beta;
/**
* A statement was submitted to a node for exectuion.
* <p/>
* Note this does not guarantee that there was success, nor that the node
* received the statement.
*
* @author Adrian Cole
*/
@Beta
public class StatementOnNodeSubmission extends StatementOnNode {
public StatementOnNodeSubmission(Statement statement, NodeMetadata node) {
super(statement, node);
}
}

View File

@ -25,7 +25,7 @@ import java.util.List;
import javax.inject.Singleton; import javax.inject.Singleton;
import org.jclouds.compute.options.TemplateOptions; import org.jclouds.compute.options.TemplateOptions;
import org.jclouds.scriptbuilder.InitBuilder; import org.jclouds.scriptbuilder.InitScript;
import org.jclouds.scriptbuilder.domain.Statement; import org.jclouds.scriptbuilder.domain.Statement;
import org.jclouds.scriptbuilder.domain.StatementList; import org.jclouds.scriptbuilder.domain.StatementList;
import org.jclouds.scriptbuilder.statements.ssh.AuthorizeRSAPublicKeys; import org.jclouds.scriptbuilder.statements.ssh.AuthorizeRSAPublicKeys;
@ -51,7 +51,7 @@ public class TemplateOptionsToStatement implements Function<TemplateOptions, Sta
if (options.getPrivateKey() != null) if (options.getPrivateKey() != null)
bootstrap.add(new InstallRSAPrivateKey(options.getPrivateKey())); bootstrap.add(new InstallRSAPrivateKey(options.getPrivateKey()));
if (bootstrap.size() >= 1) { if (bootstrap.size() >= 1) {
if (options.getTaskName() == null && !(options.getRunScript() instanceof InitBuilder)) if (options.getTaskName() == null && !(options.getRunScript() instanceof InitScript))
options.nameTask("bootstrap"); options.nameTask("bootstrap");
return bootstrap.size() == 1 ? bootstrap.get(0) : new StatementList(bootstrap); return bootstrap.size() == 1 ? bootstrap.get(0) : new StatementList(bootstrap);
} }

View File

@ -125,9 +125,9 @@ public class BaseComputeService implements ComputeService {
private final SuspendNodeStrategy suspendNodeStrategy; private final SuspendNodeStrategy suspendNodeStrategy;
private final Provider<TemplateBuilder> templateBuilderProvider; private final Provider<TemplateBuilder> templateBuilderProvider;
private final Provider<TemplateOptions> templateOptionsProvider; private final Provider<TemplateOptions> templateOptionsProvider;
private final Predicate<NodeMetadata> nodeRunning; private final Predicate<AtomicReference<NodeMetadata>> nodeRunning;
private final Predicate<NodeMetadata> nodeTerminated; private final Predicate<AtomicReference<NodeMetadata>> nodeTerminated;
private final Predicate<NodeMetadata> nodeSuspended; private final Predicate<AtomicReference<NodeMetadata>> nodeSuspended;
private final InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory; private final InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory;
private final Timeouts timeouts; private final Timeouts timeouts;
private final InitAdminAccess initAdminAccess; private final InitAdminAccess initAdminAccess;
@ -143,9 +143,9 @@ public class BaseComputeService implements ComputeService {
RebootNodeStrategy rebootNodeStrategy, DestroyNodeStrategy destroyNodeStrategy, RebootNodeStrategy rebootNodeStrategy, DestroyNodeStrategy destroyNodeStrategy,
ResumeNodeStrategy resumeNodeStrategy, SuspendNodeStrategy suspendNodeStrategy, ResumeNodeStrategy resumeNodeStrategy, SuspendNodeStrategy suspendNodeStrategy,
Provider<TemplateBuilder> templateBuilderProvider, Provider<TemplateOptions> templateOptionsProvider, Provider<TemplateBuilder> templateBuilderProvider, Provider<TemplateOptions> templateOptionsProvider,
@Named("NODE_RUNNING") Predicate<NodeMetadata> nodeRunning, @Named("NODE_RUNNING") Predicate<AtomicReference<NodeMetadata>> nodeRunning,
@Named("NODE_TERMINATED") Predicate<NodeMetadata> nodeTerminated, @Named("NODE_TERMINATED") Predicate<AtomicReference<NodeMetadata>> nodeTerminated,
@Named("NODE_SUSPENDED") Predicate<NodeMetadata> nodeSuspended, @Named("NODE_SUSPENDED") Predicate<AtomicReference<NodeMetadata>> nodeSuspended,
InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory, InitAdminAccess initAdminAccess, InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory, InitAdminAccess initAdminAccess,
RunScriptOnNode.Factory runScriptOnNodeFactory, PersistNodeCredentials persistNodeCredentials, RunScriptOnNode.Factory runScriptOnNodeFactory, PersistNodeCredentials persistNodeCredentials,
Timeouts timeouts, @Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor) { Timeouts timeouts, @Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor) {
@ -285,7 +285,7 @@ public class BaseComputeService implements ComputeService {
}, timeouts.nodeRunning, 1000, TimeUnit.MILLISECONDS); }, timeouts.nodeRunning, 1000, TimeUnit.MILLISECONDS);
boolean successful = tester.apply(id) && (node.get() == null || nodeTerminated.apply(node.get())); boolean successful = tester.apply(id) && (node.get() == null || nodeTerminated.apply(node));
if (successful) if (successful)
credentialStore.remove("node#" + id); credentialStore.remove("node#" + id);
logger.debug("<< destroyed node(%s) success(%s)", id, successful); logger.debug("<< destroyed node(%s) success(%s)", id, successful);
@ -383,7 +383,7 @@ public class BaseComputeService implements ComputeService {
public void rebootNode(String id) { public void rebootNode(String id) {
checkNotNull(id, "id"); checkNotNull(id, "id");
logger.debug(">> rebooting node(%s)", id); logger.debug(">> rebooting node(%s)", id);
NodeMetadata node = rebootNodeStrategy.rebootNode(id); AtomicReference<NodeMetadata> node = new AtomicReference<NodeMetadata>(rebootNodeStrategy.rebootNode(id));
boolean successful = nodeRunning.apply(node); boolean successful = nodeRunning.apply(node);
logger.debug("<< rebooted node(%s) success(%s)", id, successful); logger.debug("<< rebooted node(%s) success(%s)", id, successful);
} }
@ -414,7 +414,7 @@ public class BaseComputeService implements ComputeService {
public void resumeNode(String id) { public void resumeNode(String id) {
checkNotNull(id, "id"); checkNotNull(id, "id");
logger.debug(">> resuming node(%s)", id); logger.debug(">> resuming node(%s)", id);
NodeMetadata node = resumeNodeStrategy.resumeNode(id); AtomicReference<NodeMetadata> node = new AtomicReference<NodeMetadata>(resumeNodeStrategy.resumeNode(id));
boolean successful = nodeRunning.apply(node); boolean successful = nodeRunning.apply(node);
logger.debug("<< resumed node(%s) success(%s)", id, successful); logger.debug("<< resumed node(%s) success(%s)", id, successful);
} }
@ -445,7 +445,7 @@ public class BaseComputeService implements ComputeService {
public void suspendNode(String id) { public void suspendNode(String id) {
checkNotNull(id, "id"); checkNotNull(id, "id");
logger.debug(">> suspending node(%s)", id); logger.debug(">> suspending node(%s)", id);
NodeMetadata node = suspendNodeStrategy.suspendNode(id); AtomicReference<NodeMetadata> node = new AtomicReference<NodeMetadata>(suspendNodeStrategy.suspendNode(id));
boolean successful = nodeSuspended.apply(node); boolean successful = nodeSuspended.apply(node);
logger.debug("<< suspended node(%s) success(%s)", id, successful); logger.debug("<< suspended node(%s) success(%s)", id, successful);
} }

View File

@ -37,6 +37,7 @@ import org.jclouds.ssh.SshClient;
import org.jclouds.ssh.SshClient.Factory; import org.jclouds.ssh.SshClient.Factory;
import com.google.common.base.Function; import com.google.common.base.Function;
import com.google.common.eventbus.EventBus;
import com.google.inject.Inject; import com.google.inject.Inject;
/** /**
@ -50,11 +51,12 @@ public class UtilsImpl extends org.jclouds.rest.internal.UtilsImpl implements Ut
private final Function<NodeMetadata, SshClient> sshForNode; private final Function<NodeMetadata, SshClient> sshForNode;
@Inject @Inject
UtilsImpl(Injector injector, Json json, HttpClient simpleClient, HttpAsyncClient simpleAsyncClient, Crypto encryption, UtilsImpl(Injector injector, Json json, HttpClient simpleClient, HttpAsyncClient simpleAsyncClient,
DateService date, @Named(Constants.PROPERTY_USER_THREADS) ExecutorService userThreads, Crypto encryption, DateService date, @Named(Constants.PROPERTY_USER_THREADS) ExecutorService userThreads,
@Named(Constants.PROPERTY_IO_WORKER_THREADS) ExecutorService ioThreads, LoggerFactory loggerFactory, @Named(Constants.PROPERTY_IO_WORKER_THREADS) ExecutorService ioThreads, EventBus eventBus,
Function<NodeMetadata, SshClient> sshForNode) { LoggerFactory loggerFactory, Function<NodeMetadata, SshClient> sshForNode) {
super(injector, json, simpleClient, simpleAsyncClient, encryption, date, userThreads, ioThreads, loggerFactory); super(injector, json, simpleClient, simpleAsyncClient, encryption, date, userThreads, ioThreads, eventBus,
loggerFactory);
this.sshForNode = sshForNode; this.sshForNode = sshForNode;
} }

View File

@ -0,0 +1,42 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.compute.predicates;
import javax.inject.Singleton;
import org.jclouds.compute.domain.NodeState;
import org.jclouds.compute.strategy.GetNodeMetadataStrategy;
import com.google.common.collect.ImmutableSet;
import com.google.inject.Inject;
/**
*
* Tests to see if a node is running.
*
* @author Adrian Cole
*/
@Singleton
public class AtomicNodeRunning extends RefreshAndDoubleCheckOnFailUnlessStateInvalid {
@Inject
public AtomicNodeRunning(GetNodeMetadataStrategy client) {
super(NodeState.RUNNING, ImmutableSet.of(NodeState.ERROR, NodeState.TERMINATED), client);
}
}

View File

@ -0,0 +1,41 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.compute.predicates;
import javax.inject.Singleton;
import org.jclouds.compute.domain.NodeState;
import org.jclouds.compute.strategy.GetNodeMetadataStrategy;
import com.google.inject.Inject;
/**
*
* Tests to see if a node is suspended.
*
* @author Adrian Cole
*/
@Singleton
public class AtomicNodeSuspended extends RefreshAndDoubleCheckOnFailUnlessStateInvalid {
@Inject
public AtomicNodeSuspended(GetNodeMetadataStrategy client) {
super(NodeState.SUSPENDED, client);
}
}

View File

@ -39,7 +39,9 @@ import com.google.inject.Inject;
* Tests to see if a node is active. * Tests to see if a node is active.
* *
* @author Adrian Cole * @author Adrian Cole
* @see RefreshAndDoubleCheckOnFailUnlessStateInvalid
*/ */
@Deprecated
@Singleton @Singleton
public class NodePresentAndInIntendedState implements Predicate<NodeMetadata> { public class NodePresentAndInIntendedState implements Predicate<NodeMetadata> {

View File

@ -31,8 +31,10 @@ import com.google.inject.Inject;
* Tests to see if a node is running. * Tests to see if a node is running.
* *
* @author Adrian Cole * @author Adrian Cole
* @see AtomicNodeRunning
*/ */
@Singleton @Singleton
@Deprecated
public class NodeRunning extends NodePresentAndInIntendedState { public class NodeRunning extends NodePresentAndInIntendedState {
@Inject @Inject

View File

@ -30,8 +30,10 @@ import com.google.inject.Inject;
* Tests to see if a node is suspended. * Tests to see if a node is suspended.
* *
* @author Adrian Cole * @author Adrian Cole
* @see AtomicNodeSuspended
*/ */
@Singleton @Singleton
@Deprecated
public class NodeSuspended extends NodePresentAndInIntendedState { public class NodeSuspended extends NodePresentAndInIntendedState {
@Inject @Inject

View File

@ -36,8 +36,10 @@ import com.google.inject.Inject;
* Tests to see if a node is deleted * Tests to see if a node is deleted
* *
* @author Adrian Cole * @author Adrian Cole
* @see TrueIfNullOrTerminatedRefreshAndDoubleCheckOnFalse
*/ */
@Singleton @Singleton
@Deprecated
public class NodeTerminated implements Predicate<NodeMetadata> { public class NodeTerminated implements Predicate<NodeMetadata> {
private final GetNodeMetadataStrategy client; private final GetNodeMetadataStrategy client;

View File

@ -0,0 +1,86 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.compute.predicates;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;
import javax.annotation.Resource;
import javax.inject.Singleton;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.domain.NodeState;
import org.jclouds.compute.strategy.GetNodeMetadataStrategy;
import org.jclouds.logging.Logger;
import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableSet;
import com.google.inject.Inject;
/**
*
* Tests to see if a node is active.
*
* @author Adrian Cole
*/
@Singleton
public class RefreshAndDoubleCheckOnFailUnlessStateInvalid implements Predicate<AtomicReference<NodeMetadata>> {
private final GetNodeMetadataStrategy client;
private final NodeState intended;
private final Set<NodeState> invalids;
@Resource
protected Logger logger = Logger.NULL;
@Inject
public RefreshAndDoubleCheckOnFailUnlessStateInvalid(NodeState intended, GetNodeMetadataStrategy client) {
this(intended, ImmutableSet.of(NodeState.ERROR), client);
}
public RefreshAndDoubleCheckOnFailUnlessStateInvalid(NodeState intended, Set<NodeState> invalids, GetNodeMetadataStrategy client) {
this.intended = intended;
this.client = client;
this.invalids = invalids;
}
public boolean apply(AtomicReference<NodeMetadata> atomicNode) {
NodeMetadata node = atomicNode.get();
if (checkState(node))
return true;
node = refresh(node);
atomicNode.set(node);
return checkState(node);
}
public boolean checkState(NodeMetadata node) {
if (node == null)
return false;
logger.trace("%s: looking for node state %s: currently: %s", node.getId(), intended, node.getState());
if (invalids.contains(node.getState()))
throw new IllegalStateException("node " + node.getId() + " in location " + node.getLocation()
+ " is in invalid state "+node.getState());
return node.getState() == intended;
}
private NodeMetadata refresh(NodeMetadata node) {
if (node == null || node.getId() == null)
return null;
return client.getNode(node.getId());
}
}

View File

@ -44,11 +44,11 @@ public class ScriptStatusReturnsZero implements Predicate<ScriptStatusReturnsZer
logger.trace("looking for [%s] state on %s@%s", commandUsingClient.command, commandUsingClient.client logger.trace("looking for [%s] state on %s@%s", commandUsingClient.command, commandUsingClient.client
.getUsername(), commandUsingClient.client.getHostAddress()); .getUsername(), commandUsingClient.client.getHostAddress());
ExecResponse response = refresh(commandUsingClient); ExecResponse response = refresh(commandUsingClient);
while (response.getExitCode() == -1) while (response.getExitStatus() == -1)
response = refresh(commandUsingClient); response = refresh(commandUsingClient);
logger.trace("%s@%s: looking for exit code 0: currently: %s", commandUsingClient.client.getUsername(), logger.trace("%s@%s: looking for exit code 0: currently: %s", commandUsingClient.client.getUsername(),
commandUsingClient.client.getHostAddress(), response.getExitCode()); commandUsingClient.client.getHostAddress(), response.getExitStatus());
return 0 == response.getExitCode(); return 0 == response.getExitStatus();
} }
private ExecResponse refresh(CommandUsingClient commandUsingClient) { private ExecResponse refresh(CommandUsingClient commandUsingClient) {

View File

@ -0,0 +1,69 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.compute.predicates;
import java.util.concurrent.atomic.AtomicReference;
import javax.annotation.Resource;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.domain.NodeState;
import org.jclouds.compute.strategy.GetNodeMetadataStrategy;
import org.jclouds.logging.Logger;
import com.google.common.base.Predicate;
import com.google.inject.Inject;
/**
*
*
* @author Adrian Cole
*/
public class TrueIfNullOrTerminatedRefreshAndDoubleCheckOnFalse implements Predicate<AtomicReference<NodeMetadata>> {
private final GetNodeMetadataStrategy client;
@Resource
protected Logger logger = Logger.NULL;
@Inject
public TrueIfNullOrTerminatedRefreshAndDoubleCheckOnFalse(GetNodeMetadataStrategy client) {
this.client = client;
}
public boolean apply(AtomicReference<NodeMetadata> atomicNode) {
NodeMetadata node = atomicNode.get();
if (checkState(node))
return true;
node = refresh(node);
atomicNode.set(node);
return checkState(node);
}
public boolean checkState(NodeMetadata node) {
if (node == null)
return true;
logger.trace("%s: looking for node state %s: currently: %s", node.getId(), NodeState.TERMINATED, node.getState());
return node.getState() == NodeState.TERMINATED;
}
private NodeMetadata refresh(NodeMetadata node) {
return client.getNode(node.getId());
}
}

View File

@ -27,8 +27,8 @@ import static org.jclouds.compute.util.ComputeServiceUtils.findReachableSocketOn
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
import java.util.concurrent.atomic.AtomicReference;
import org.jclouds.javax.annotation.Nullable;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.inject.Named; import javax.inject.Named;
@ -41,6 +41,7 @@ import org.jclouds.compute.options.TemplateOptions;
import org.jclouds.compute.predicates.RetryIfSocketNotYetOpen; import org.jclouds.compute.predicates.RetryIfSocketNotYetOpen;
import org.jclouds.compute.reference.ComputeServiceConstants; import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.compute.reference.ComputeServiceConstants.Timeouts; import org.jclouds.compute.reference.ComputeServiceConstants.Timeouts;
import org.jclouds.javax.annotation.Nullable;
import org.jclouds.logging.Logger; import org.jclouds.logging.Logger;
import org.jclouds.scriptbuilder.domain.Statement; import org.jclouds.scriptbuilder.domain.Statement;
@ -55,31 +56,28 @@ import com.google.inject.assistedinject.AssistedInject;
* @author Adrian Cole * @author Adrian Cole
*/ */
public class CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap implements Callable<Void>, public class CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap implements Callable<Void>,
Function<NodeMetadata, Void> { Function<AtomicReference<NodeMetadata>, Void> {
public static interface Factory { public static interface Factory {
Callable<Void> create(TemplateOptions options, NodeMetadata node, Set<NodeMetadata> goodNodes, Callable<Void> create(TemplateOptions options, AtomicReference<NodeMetadata> node, Set<NodeMetadata> goodNodes,
Map<NodeMetadata, Exception> badNodes, Map<NodeMetadata, Exception> badNodes, Multimap<NodeMetadata, CustomizationResponse> customizationResponses);
Multimap<NodeMetadata, CustomizationResponse> customizationResponses);
Function<NodeMetadata, Void> create(TemplateOptions options, Set<NodeMetadata> goodNodes, Function<AtomicReference<NodeMetadata>, Void> create(TemplateOptions options, Set<NodeMetadata> goodNodes,
Map<NodeMetadata, Exception> badNodes, Map<NodeMetadata, Exception> badNodes, Multimap<NodeMetadata, CustomizationResponse> customizationResponses);
Multimap<NodeMetadata, CustomizationResponse> customizationResponses);
} }
@Resource @Resource
@Named(ComputeServiceConstants.COMPUTE_LOGGER) @Named(ComputeServiceConstants.COMPUTE_LOGGER)
protected Logger logger = Logger.NULL; protected Logger logger = Logger.NULL;
private final Predicate<NodeMetadata> nodeRunning; private final Predicate<AtomicReference<NodeMetadata>> nodeRunning;
private final InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory; private final InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory;
private final GetNodeMetadataStrategy getNode;
private final RetryIfSocketNotYetOpen socketTester; private final RetryIfSocketNotYetOpen socketTester;
private final Timeouts timeouts; private final Timeouts timeouts;
@Nullable @Nullable
private final Statement statement; private final Statement statement;
private final TemplateOptions options; private final TemplateOptions options;
private NodeMetadata node; private AtomicReference<NodeMetadata> node;
private final Set<NodeMetadata> goodNodes; private final Set<NodeMetadata> goodNodes;
private final Map<NodeMetadata, Exception> badNodes; private final Map<NodeMetadata, Exception> badNodes;
private final Multimap<NodeMetadata, CustomizationResponse> customizationResponses; private final Multimap<NodeMetadata, CustomizationResponse> customizationResponses;
@ -88,18 +86,17 @@ public class CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap implements Cal
@AssistedInject @AssistedInject
public CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap( public CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap(
@Named("NODE_RUNNING") Predicate<NodeMetadata> nodeRunning, GetNodeMetadataStrategy getNode, @Named("NODE_RUNNING") Predicate<AtomicReference<NodeMetadata>> nodeRunning,
RetryIfSocketNotYetOpen socketTester, Timeouts timeouts, RetryIfSocketNotYetOpen socketTester, Timeouts timeouts,
Function<TemplateOptions, Statement> templateOptionsToStatement, Function<TemplateOptions, Statement> templateOptionsToStatement,
InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory, InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory, @Assisted TemplateOptions options,
@Assisted TemplateOptions options, @Assisted @Nullable NodeMetadata node, @Assisted AtomicReference<NodeMetadata> node, @Assisted Set<NodeMetadata> goodNodes,
@Assisted Set<NodeMetadata> goodNodes, @Assisted Map<NodeMetadata, Exception> badNodes, @Assisted Map<NodeMetadata, Exception> badNodes,
@Assisted Multimap<NodeMetadata, CustomizationResponse> customizationResponses) { @Assisted Multimap<NodeMetadata, CustomizationResponse> customizationResponses) {
this.statement = checkNotNull(templateOptionsToStatement, "templateOptionsToStatement").apply( this.statement = checkNotNull(templateOptionsToStatement, "templateOptionsToStatement").apply(
checkNotNull(options, "options")); checkNotNull(options, "options"));
this.nodeRunning = checkNotNull(nodeRunning, "nodeRunning"); this.nodeRunning = checkNotNull(nodeRunning, "nodeRunning");
this.initScriptRunnerFactory = checkNotNull(initScriptRunnerFactory, "initScriptRunnerFactory"); this.initScriptRunnerFactory = checkNotNull(initScriptRunnerFactory, "initScriptRunnerFactory");
this.getNode = checkNotNull(getNode, "getNode");
this.socketTester = checkNotNull(socketTester, "socketTester"); this.socketTester = checkNotNull(socketTester, "socketTester");
this.timeouts = checkNotNull(timeouts, "timeouts"); this.timeouts = checkNotNull(timeouts, "timeouts");
this.node = node; this.node = node;
@ -111,61 +108,65 @@ public class CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap implements Cal
@AssistedInject @AssistedInject
public CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap( public CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap(
@Named("NODE_RUNNING") Predicate<NodeMetadata> nodeRunning, GetNodeMetadataStrategy getNode, @Named("NODE_RUNNING") Predicate<AtomicReference<NodeMetadata>> nodeRunning, GetNodeMetadataStrategy getNode,
RetryIfSocketNotYetOpen socketTester, Timeouts timeouts, RetryIfSocketNotYetOpen socketTester, Timeouts timeouts,
Function<TemplateOptions, Statement> templateOptionsToStatement, Function<TemplateOptions, Statement> templateOptionsToStatement,
InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory, InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory, @Assisted TemplateOptions options,
@Assisted TemplateOptions options, @Assisted Set<NodeMetadata> goodNodes, @Assisted Set<NodeMetadata> goodNodes, @Assisted Map<NodeMetadata, Exception> badNodes,
@Assisted Map<NodeMetadata, Exception> badNodes,
@Assisted Multimap<NodeMetadata, CustomizationResponse> customizationResponses) { @Assisted Multimap<NodeMetadata, CustomizationResponse> customizationResponses) {
this(nodeRunning, getNode, socketTester, timeouts, templateOptionsToStatement, initScriptRunnerFactory, options, this(nodeRunning, socketTester, timeouts, templateOptionsToStatement, initScriptRunnerFactory, options,
null, goodNodes, badNodes, customizationResponses); new AtomicReference<NodeMetadata>(null), goodNodes, badNodes, customizationResponses);
} }
@Override @Override
public Void call() { public Void call() {
checkState(!tainted, "this object is not designed to be reused: %s", toString()); checkState(!tainted, "this object is not designed to be reused: %s", toString());
tainted = true; tainted = true;
String originalId = node.getId(); String originalId = node.get().getId();
NodeMetadata originalNode = node; NodeMetadata originalNode = node.get();
try { try {
if (options.shouldBlockUntilRunning()) { if (options.shouldBlockUntilRunning()) {
if (nodeRunning.apply(node)) { try {
node = getNode.getNode(originalId); if (!nodeRunning.apply(node)) {
} else { if (node.get() == null) {
NodeMetadata nodeForState = getNode.getNode(originalId); node.set(originalNode);
NodeState state = nodeForState == null ? NodeState.TERMINATED : nodeForState.getState(); throw new IllegalStateException(format("api response for node(%s) was null, so we can't customize",
if (state == NodeState.TERMINATED) originalId));
throw new IllegalStateException(format("node(%s) terminated before we could customize", originalId)); }
else throw new IllegalStateException(
throw new IllegalStateException(format( format(
"node(%s) didn't achieve the state running within %d seconds, final state: %s", originalId, "node(%s) didn't achieve the state running within %d seconds, so we couldn't customize; final state: %s",
timeouts.nodeRunning / 1000, state)); originalId, timeouts.nodeRunning / 1000, node.get().getState()));
}
} catch (IllegalStateException e) {
if (node.get().getState() == NodeState.TERMINATED) {
throw new IllegalStateException(format("node(%s) terminated before we could customize", originalId));
} else {
throw e;
}
} }
if (node == null)
throw new IllegalStateException(format("node %s terminated before applying options", originalId));
if (statement != null) { if (statement != null) {
RunScriptOnNode runner = initScriptRunnerFactory.create(node, statement, options, badNodes).call(); RunScriptOnNode runner = initScriptRunnerFactory.create(node.get(), statement, options, badNodes).call();
if (runner != null) { if (runner != null) {
ExecResponse exec = runner.call(); ExecResponse exec = runner.call();
customizationResponses.put(node, exec); customizationResponses.put(node.get(), exec);
} }
} }
if (options.getPort() > 0) { if (options.getPort() > 0) {
findReachableSocketOnNode(socketTester.seconds(options.getSeconds()), node, options.getPort()); findReachableSocketOnNode(socketTester.seconds(options.getSeconds()), node.get(), options.getPort());
} }
} }
logger.debug("<< options applied node(%s)", originalId); logger.debug("<< customized node(%s)", originalId);
goodNodes.add(node); goodNodes.add(node.get());
} catch (Exception e) { } catch (Exception e) {
logger.error(e, "<< problem applying options to node(%s): ", originalId, getRootCause(e).getMessage()); logger.error(e, "<< problem customizing node(%s): ", originalId, getRootCause(e).getMessage());
badNodes.put(node == null ? originalNode : node, e); badNodes.put(node.get(), e);
} }
return null; return null;
} }
@Override @Override
public Void apply(NodeMetadata input) { public Void apply(AtomicReference<NodeMetadata> input) {
this.node = input; this.node = input;
call(); call();
return null; return null;

View File

@ -67,8 +67,8 @@ public class RunScriptOnNodeAndAddToGoodMapOrPutExceptionIntoBadMap implements C
tainted = true; tainted = true;
try { try {
ExecResponse exec = runScriptOnNode.call(); ExecResponse exec = runScriptOnNode.call();
logger.trace("<< script output for node(%s): %s", runScriptOnNode.getNode().getId(), exec);
logger.debug("<< options applied node(%s)", runScriptOnNode.getNode().getId()); logger.debug("<< options applied node(%s)", runScriptOnNode.getNode().getId());
logger.trace("<< script output for node(%s): %s", runScriptOnNode.getNode().getId(), exec);
goodNodes.put(runScriptOnNode.getNode(), exec); goodNodes.put(runScriptOnNode.getNode(), exec);
return exec; return exec;
} catch (Exception e) { } catch (Exception e) {

View File

@ -31,6 +31,7 @@ import java.util.Set;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future; import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicReference;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.inject.Inject; import javax.inject.Inject;
@ -60,7 +61,7 @@ import com.google.common.collect.Multimap;
@Singleton @Singleton
public class CreateNodesWithGroupEncodedIntoNameThenAddToSet implements CreateNodesInGroupThenAddToSet { public class CreateNodesWithGroupEncodedIntoNameThenAddToSet implements CreateNodesInGroupThenAddToSet {
private class AddNode implements Callable<NodeMetadata> { private class AddNode implements Callable<AtomicReference<NodeMetadata>> {
private final String name; private final String name;
private final String group; private final String group;
private final Template template; private final Template template;
@ -72,14 +73,14 @@ public class CreateNodesWithGroupEncodedIntoNameThenAddToSet implements CreateNo
} }
@Override @Override
public NodeMetadata call() throws Exception { public AtomicReference<NodeMetadata> call() throws Exception {
NodeMetadata node = null; NodeMetadata node = null;
logger.debug(">> adding node location(%s) name(%s) image(%s) hardware(%s)", logger.debug(">> adding node location(%s) name(%s) image(%s) hardware(%s)",
template.getLocation().getId(), name, template.getImage().getProviderId(), template.getHardware() template.getLocation().getId(), name, template.getImage().getProviderId(), template.getHardware()
.getProviderId()); .getProviderId());
node = addNodeWithGroupStrategy.createNodeWithGroupEncodedIntoName(group, name, template); node = addNodeWithGroupStrategy.createNodeWithGroupEncodedIntoName(group, name, template);
logger.debug("<< %s node(%s)", node.getState(), node.getId()); logger.debug("<< %s node(%s)", node.getState(), node.getId());
return node; return new AtomicReference<NodeMetadata>(node);
} }
public String toString() { public String toString() {

View File

@ -24,6 +24,7 @@ import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future; import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicReference;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Named; import javax.inject.Named;
@ -60,7 +61,7 @@ public class ComputeUtils {
Map<NodeMetadata, Future<Void>> responses = newLinkedHashMap(); Map<NodeMetadata, Future<Void>> responses = newLinkedHashMap();
for (NodeMetadata node : runningNodes) { for (NodeMetadata node : runningNodes) {
responses.put(node, executor.submit(customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory.create( responses.put(node, executor.submit(customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory.create(
options, node, goodNodes, badNodes, customizationResponses))); options, new AtomicReference<NodeMetadata>(node), goodNodes, badNodes, customizationResponses)));
} }
return responses; return responses;
} }

View File

@ -1,111 +0,0 @@
;
; Licensed to jclouds, Inc. (jclouds) under one or more
; contributor license agreements. See the NOTICE file
; distributed with this work for additional information
; regarding copyright ownership. jclouds licenses this file
; to you under the Apache License, Version 2.0 (the
; "License"); you may not use this file except in compliance
; with the License. You may obtain a copy of the License at
;
; http://www.apache.org/licenses/LICENSE-2.0
;
; Unless required by applicable law or agreed to in writing,
; software distributed under the License is distributed on an
; "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
; KIND, either express or implied. See the License for the
; specific language governing permissions and limitations
; under the License.
;
(ns org.jclouds.compute-test
(:use [org.jclouds.compute] :reload-all)
(:use clojure.test)
(:import
org.jclouds.compute.domain.OsFamily))
(defmacro with-private-vars [[ns fns] & tests]
"Refers private fns from ns and runs tests in context. From users mailing
list, Alan Dipert and MeikelBrandmeyer."
`(let ~(reduce #(conj %1 %2 `@(ns-resolve '~ns '~%2)) [] fns)
~@tests))
(deftest os-families-test
(is (some #{"centos"} (map str (os-families)))))
(defn clean-stub-fixture
"This should allow basic tests to easily be run with another service."
[service account key & options]
(fn [f]
(with-compute-service [(apply compute-service service account key options)]
(doseq [node (nodes)]
(destroy-node (.getId node)))
(f))))
(use-fixtures :each (clean-stub-fixture "stub" "compute.clj" ""))
(deftest compute-service?-test
(is (compute-service? *compute*)))
(deftest as-compute-service-test
(is (compute-service? (compute-service "stub" "compute.clj" "")))
(is (compute-service? (as-compute-service *compute*)))
(is (compute-service? (as-compute-service (compute-context *compute*)))))
(deftest nodes-test
(is (create-node "fred" (build-template
*compute* {} )))
(is (= 1 (count (nodes))))
(is (= 1 (count (nodes-in-group "fred"))))
(suspend-nodes-in-group "fred")
(is (suspended? (first (nodes-in-group "fred"))))
(resume-nodes-in-group "fred")
(is (running? (first (nodes-in-group "fred"))))
(reboot-nodes-in-group "fred")
(is (running? (first (nodes-in-group "fred"))))
(is (create-nodes "fred" 2 (build-template
*compute* {} )))
(is (= 3 (count (nodes-in-group "fred"))))
(is (= "fred" (group (first (nodes)))))
(destroy-nodes-in-group "fred")
(is (terminated? (first (nodes-in-group "fred")))))
(deftest build-template-test
(let [service (compute-service "stub" "compute.clj" "")]
(testing "nullary"
(is (>= (-> (build-template service {:fastest true})
bean :hardware bean :processors first bean :cores)
8.0)))
(testing "one arg"
(is (> (-> (build-template service {:min-ram 512})
bean :hardware bean :ram)
512))
(let [credentials (org.jclouds.domain.Credentials. "user" "pwd")
f (juxt #(.identity %) #(.credential %))
template (build-template
service {:override-credentials-with credentials})
node (create-node "something" template service)]
(is (= (-> node bean :credentials f)
(f credentials))))
(let [user "fred"
f #(.identity %)
template (build-template service {:override-login-user-with user})
node (create-node "something" template service)]
(is (= (-> node bean :credentials f) user)))
(let [credential "fred"
f #(.credential %)
template (build-template
service {:override-login-credential-with credential})
node (create-node "something" template service)]
(is (= (-> node bean :credentials f) credential))))
(testing "enumerated"
(is (= OsFamily/CENTOS
(-> (build-template service {:os-family :centos})
bean :image bean :operatingSystem bean :family))))
(testing "varags"
(is (java.util.Arrays/equals
(int-array [22 8080])
(-> (build-template service {:inbound-ports [22 8080]})
bean :options bean :inboundPorts))))
(testing "invalid"
(is (thrown? Exception (build-template service {:xx :yy}))))))

View File

@ -50,7 +50,7 @@
(merge (merge
{:exit 0 :err "stderr" :out "stdout"} {:exit 0 :err "stderr" :out "stdout"}
(condp = cmd (condp = cmd
"./bootstrap status" {:exit 1 :out "[]"} "/tmp/init-bootstrap status" {:exit 1 :out "[]"}
{}))) {})))

View File

@ -31,10 +31,8 @@ import static com.google.common.collect.Sets.newTreeSet;
import static java.lang.String.format; import static java.lang.String.format;
import static java.lang.System.currentTimeMillis; import static java.lang.System.currentTimeMillis;
import static java.util.logging.Logger.getAnonymousLogger; import static java.util.logging.Logger.getAnonymousLogger;
import static org.jclouds.compute.ComputeTestUtils.buildScript;
import static org.jclouds.compute.RunScriptData.JBOSS7_URL; import static org.jclouds.compute.RunScriptData.JBOSS7_URL;
import static org.jclouds.compute.RunScriptData.JBOSS_HOME; import static org.jclouds.compute.RunScriptData.JBOSS_HOME;
import static org.jclouds.compute.RunScriptData.JDK7_URL;
import static org.jclouds.compute.RunScriptData.installAdminUserJBossAndOpenPorts; import static org.jclouds.compute.RunScriptData.installAdminUserJBossAndOpenPorts;
import static org.jclouds.compute.RunScriptData.startJBoss; import static org.jclouds.compute.RunScriptData.startJBoss;
import static org.jclouds.compute.options.RunScriptOptions.Builder.nameTask; import static org.jclouds.compute.options.RunScriptOptions.Builder.nameTask;
@ -78,7 +76,6 @@ import org.jclouds.compute.domain.Image;
import org.jclouds.compute.domain.NodeMetadata; import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.domain.NodeState; import org.jclouds.compute.domain.NodeState;
import org.jclouds.compute.domain.OperatingSystem; import org.jclouds.compute.domain.OperatingSystem;
import org.jclouds.compute.domain.OsFamily;
import org.jclouds.compute.domain.Template; import org.jclouds.compute.domain.Template;
import org.jclouds.compute.domain.TemplateBuilder; import org.jclouds.compute.domain.TemplateBuilder;
import org.jclouds.compute.options.TemplateOptions; import org.jclouds.compute.options.TemplateOptions;
@ -93,6 +90,7 @@ import org.jclouds.predicates.SocketOpen;
import org.jclouds.rest.AuthorizationException; import org.jclouds.rest.AuthorizationException;
import org.jclouds.scriptbuilder.domain.SaveHttpResponseTo; import org.jclouds.scriptbuilder.domain.SaveHttpResponseTo;
import org.jclouds.scriptbuilder.domain.Statements; import org.jclouds.scriptbuilder.domain.Statements;
import org.jclouds.scriptbuilder.statements.java.InstallJDK;
import org.jclouds.scriptbuilder.statements.login.AdminAccess; import org.jclouds.scriptbuilder.statements.login.AdminAccess;
import org.jclouds.ssh.SshClient; import org.jclouds.ssh.SshClient;
import org.jclouds.ssh.SshException; import org.jclouds.ssh.SshException;
@ -210,8 +208,7 @@ public abstract class BaseComputeServiceLiveTest extends BaseVersionedServiceLiv
@Test(enabled = true, expectedExceptions = NoSuchElementException.class) @Test(enabled = true, expectedExceptions = NoSuchElementException.class)
public void testCorrectExceptionRunningNodesNotFound() throws Exception { public void testCorrectExceptionRunningNodesNotFound() throws Exception {
client.runScriptOnNodesMatching(runningInGroup("zebras-are-awesome"), buildScript(new OperatingSystem.Builder() client.runScriptOnNodesMatching(runningInGroup("zebras-are-awesome"), InstallJDK.fromURL());
.family(OsFamily.UBUNTU).description("ffoo").build()));
} }
// since surefire and eclipse don't otherwise guarantee the order, we are // since surefire and eclipse don't otherwise guarantee the order, we are
@ -259,7 +256,7 @@ public abstract class BaseComputeServiceLiveTest extends BaseVersionedServiceLiv
response = future.get(3, TimeUnit.MINUTES); response = future.get(3, TimeUnit.MINUTES);
assert response.getExitCode() == 0 : node.getId() + ": " + response; assert response.getExitStatus() == 0 : node.getId() + ": " + response;
node = client.getNodeMetadata(node.getId()); node = client.getNodeMetadata(node.getId());
// test that the node updated to the correct admin user! // test that the node updated to the correct admin user!
@ -268,7 +265,7 @@ public abstract class BaseComputeServiceLiveTest extends BaseVersionedServiceLiv
weCanCancelTasks(node); weCanCancelTasks(node);
assert response.getExitCode() == 0 : node.getId() + ": " + response; assert response.getExitStatus() == 0 : node.getId() + ": " + response;
response = client.runScriptOnNode(node.getId(), "echo $USER", wrapInInitScript(false).runAsRoot(false)); response = client.runScriptOnNode(node.getId(), "echo $USER", wrapInInitScript(false).runAsRoot(false));
@ -307,11 +304,11 @@ public abstract class BaseComputeServiceLiveTest extends BaseVersionedServiceLiv
assert false : node.getId() + ": " + response; assert false : node.getId() + ": " + response;
} catch (TimeoutException e) { } catch (TimeoutException e) {
assert !future.isDone(); assert !future.isDone();
response = client.runScriptOnNode(node.getId(), Statements.exec("./sleeper status"), wrapInInitScript(false) response = client.runScriptOnNode(node.getId(), Statements.exec("/tmp/init-sleeper status"), wrapInInitScript(false)
.runAsRoot(false)); .runAsRoot(false));
assert !response.getOutput().trim().equals("") : node.getId() + ": " + response; assert !response.getOutput().trim().equals("") : node.getId() + ": " + response;
future.cancel(true); future.cancel(true);
response = client.runScriptOnNode(node.getId(), Statements.exec("./sleeper status"), wrapInInitScript(false) response = client.runScriptOnNode(node.getId(), Statements.exec("/tmp/init-sleeper status"), wrapInInitScript(false)
.runAsRoot(false)); .runAsRoot(false));
assert response.getOutput().trim().equals("") : node.getId() + ": " + response; assert response.getOutput().trim().equals("") : node.getId() + ": " + response;
try { try {
@ -373,7 +370,7 @@ public abstract class BaseComputeServiceLiveTest extends BaseVersionedServiceLiv
protected static Template addRunScriptToTemplate(Template template) { protected static Template addRunScriptToTemplate(Template template) {
template.getOptions().runScript( template.getOptions().runScript(
Statements.newStatementList(AdminAccess.standard(), buildScript(template.getImage().getOperatingSystem()))); Statements.newStatementList(AdminAccess.standard(), InstallJDK.fromURL()));
return template; return template;
} }
@ -437,7 +434,7 @@ public abstract class BaseComputeServiceLiveTest extends BaseVersionedServiceLiv
protected Map<? extends NodeMetadata, ExecResponse> runScriptWithCreds(final String group, OperatingSystem os, protected Map<? extends NodeMetadata, ExecResponse> runScriptWithCreds(final String group, OperatingSystem os,
LoginCredentials creds) throws RunScriptOnNodesException { LoginCredentials creds) throws RunScriptOnNodesException {
return client.runScriptOnNodesMatching(runningInGroup(group), buildScript(os), overrideLoginCredentials(creds) return client.runScriptOnNodesMatching(runningInGroup(group), InstallJDK.fromURL(), overrideLoginCredentials(creds)
.nameTask("runScriptWithCreds")); .nameTask("runScriptWithCreds"));
} }
@ -595,10 +592,10 @@ public abstract class BaseComputeServiceLiveTest extends BaseVersionedServiceLiv
IPSocket socket = new IPSocket(Iterables.get(node.getPublicAddresses(), 0), 8080); IPSocket socket = new IPSocket(Iterables.get(node.getPublicAddresses(), 0), 8080);
assert preciseSocketTester.apply(socket) : String.format("failed to open socket %s on node %s:%n%s%s", socket, assert preciseSocketTester.apply(socket) : String.format("failed to open socket %s on node %s:%n%s%s", socket,
node, init(node, processName, "tail"), init(node, processName, "tailerr")); node, init(node, processName, "stdout"), init(node, processName, "stderr"));
stats.socketOpenMilliseconds = watch.elapsedTime(TimeUnit.MILLISECONDS); stats.socketOpenMilliseconds = watch.elapsedTime(TimeUnit.MILLISECONDS);
exec = init(node, processName, "tail"); exec = init(node, processName, "stdout");
Matcher matcher = parseReported.matcher(exec.getOutput()); Matcher matcher = parseReported.matcher(exec.getOutput());
if (matcher.find()) if (matcher.find())
@ -609,7 +606,7 @@ public abstract class BaseComputeServiceLiveTest extends BaseVersionedServiceLiv
} }
public ExecResponse init(NodeMetadata node, String processName, String command) { public ExecResponse init(NodeMetadata node, String processName, String command) {
return client.runScriptOnNode(node.getId(), "./" + processName + " "+command, runAsRoot(false) return client.runScriptOnNode(node.getId(), "/tmp/init-" + processName + " "+command, runAsRoot(false)
.wrapInInitScript(false)); .wrapInInitScript(false));
} }
@ -679,7 +676,7 @@ public abstract class BaseComputeServiceLiveTest extends BaseVersionedServiceLiv
format("ls %s/bundles/org/jboss/as/osgi/configadmin/main|sed -e 's/.*-//g' -e 's/.jar//g'", format("ls %s/bundles/org/jboss/as/osgi/configadmin/main|sed -e 's/.*-//g' -e 's/.jar//g'",
JBOSS_HOME)), configureSeconds)); JBOSS_HOME)), configureSeconds));
for (Entry<String, URI> download : ImmutableMap.<String, URI> of("jboss7", JBOSS7_URL, "jdk7", JDK7_URL) for (Entry<String, URI> download : ImmutableMap.<String, URI> of("jboss7", JBOSS7_URL, "jdk7", InstallJDK.FromURL.JDK7_URL)
.entrySet()) { .entrySet()) {
// note we cannot use nslookup until we've configured the system, as // note we cannot use nslookup until we've configured the system, as
// it may have not been present checking the address of the download // it may have not been present checking the address of the download
@ -719,13 +716,13 @@ public abstract class BaseComputeServiceLiveTest extends BaseVersionedServiceLiv
}), "jboss", node, JBOSS_PATTERN); }), "jboss", node, JBOSS_PATTERN);
client.runScriptOnNode(nodeId, "./jboss stop", runAsRoot(false).wrapInInitScript(false)); client.runScriptOnNode(nodeId, "/tmp/init-jboss stop", runAsRoot(false).wrapInInitScript(false));
trackAvailabilityOfProcessOnNode(context.utils().userExecutor().submit(new Callable<ExecResponse>() { trackAvailabilityOfProcessOnNode(context.utils().userExecutor().submit(new Callable<ExecResponse>() {
@Override @Override
public ExecResponse call() { public ExecResponse call() {
return client.runScriptOnNode(nodeId, "./jboss start", runAsRoot(false).wrapInInitScript(false)); return client.runScriptOnNode(nodeId, "/tmp/init-jboss start", runAsRoot(false).wrapInInitScript(false));
} }
@Override @Override

View File

@ -31,9 +31,7 @@ import java.util.Map;
import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeoutException;
import org.jclouds.compute.domain.NodeMetadata; import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.domain.OperatingSystem;
import org.jclouds.rest.HttpClient; import org.jclouds.rest.HttpClient;
import org.jclouds.scriptbuilder.domain.Statement;
import org.jclouds.util.Preconditions2; import org.jclouds.util.Preconditions2;
import com.google.common.base.Charsets; import com.google.common.base.Charsets;
@ -46,9 +44,6 @@ import com.google.common.io.Files;
* @author Adrian Cole * @author Adrian Cole
*/ */
public class ComputeTestUtils { public class ComputeTestUtils {
public static Statement buildScript(OperatingSystem os) {
return RunScriptData.installJavaAndCurl(os);
}
public static Map<String, String> setupKeyPair() throws FileNotFoundException, IOException { public static Map<String, String> setupKeyPair() throws FileNotFoundException, IOException {
String secretKeyFile; String secretKeyFile;

View File

@ -70,6 +70,7 @@ public class StubComputeServiceIntegrationTest extends BaseComputeServiceLiveTes
private static final ExecResponse EXEC_GOOD = new ExecResponse("", "", 0); private static final ExecResponse EXEC_GOOD = new ExecResponse("", "", 0);
private static final ExecResponse EXEC_BAD = new ExecResponse("", "", 1); private static final ExecResponse EXEC_BAD = new ExecResponse("", "", 1);
private static final ExecResponse EXEC_RC_GOOD = new ExecResponse("0", "", 0);
public StubComputeServiceIntegrationTest() { public StubComputeServiceIntegrationTest() {
provider = "stub"; provider = "stub";
@ -268,13 +269,15 @@ public class StubComputeServiceIntegrationTest extends BaseComputeServiceLiveTes
expect(client.exec("ln -fs /tmp/init-" + scriptName + " " + scriptName)).andReturn(EXEC_GOOD); expect(client.exec("ln -fs /tmp/init-" + scriptName + " " + scriptName)).andReturn(EXEC_GOOD);
expect(client.getUsername()).andReturn("root").atLeastOnce(); expect(client.getUsername()).andReturn("root").atLeastOnce();
expect(client.getHostAddress()).andReturn("localhost").atLeastOnce(); expect(client.getHostAddress()).andReturn("localhost").atLeastOnce();
expect(client.exec("./" + scriptName + " init")).andReturn(EXEC_GOOD); expect(client.exec("/tmp/init-" + scriptName + " init")).andReturn(EXEC_GOOD);
expect(client.exec("./" + scriptName + " start")).andReturn(EXEC_GOOD); expect(client.exec("/tmp/init-" + scriptName + " start")).andReturn(EXEC_GOOD);
expect(client.exec("./" + scriptName + " status")).andReturn(EXEC_GOOD); expect(client.exec("/tmp/init-" + scriptName + " status")).andReturn(EXEC_GOOD);
// next status says the script is done, since not found. // next status says the script is done, since not found.
expect(client.exec("./" + scriptName + " status")).andReturn(EXEC_BAD); expect(client.exec("/tmp/init-" + scriptName + " status")).andReturn(EXEC_BAD);
expect(client.exec("./" + scriptName + " tail")).andReturn(EXEC_GOOD); expect(client.exec("/tmp/init-" + scriptName + " stdout")).andReturn(EXEC_GOOD);
expect(client.exec("./" + scriptName + " tailerr")).andReturn(EXEC_GOOD); expect(client.exec("/tmp/init-" + scriptName + " stderr")).andReturn(EXEC_GOOD);
expect(client.exec("/tmp/init-" + scriptName + " exitstatus")).andReturn(EXEC_RC_GOOD);
// note we have to reconnect here, as we updated the login user. // note we have to reconnect here, as we updated the login user.
client.disconnect(); client.disconnect();
@ -307,23 +310,23 @@ public class StubComputeServiceIntegrationTest extends BaseComputeServiceLiveTes
expect(clientNew.exec("ln -fs /tmp/init-" + scriptName + " " + scriptName)).andReturn(EXEC_GOOD); expect(clientNew.exec("ln -fs /tmp/init-" + scriptName + " " + scriptName)).andReturn(EXEC_GOOD);
expect(clientNew.getUsername()).andReturn("web").atLeastOnce(); expect(clientNew.getUsername()).andReturn("web").atLeastOnce();
expect(clientNew.getHostAddress()).andReturn("localhost").atLeastOnce(); expect(clientNew.getHostAddress()).andReturn("localhost").atLeastOnce();
expect(clientNew.exec("./" + scriptName + " init")).andReturn(EXEC_GOOD); expect(clientNew.exec("/tmp/init-" + scriptName + " init")).andReturn(EXEC_GOOD);
expect(clientNew.exec("./" + scriptName + " start")).andReturn(EXEC_GOOD); expect(clientNew.exec("/tmp/init-" + scriptName + " start")).andReturn(EXEC_GOOD);
clientNew.disconnect(); clientNew.disconnect();
clientNew.connect(); clientNew.connect();
expect(clientNew.exec("./" + scriptName + " tail\n")).andReturn(EXEC_GOOD); expect(clientNew.exec("/tmp/init-" + scriptName + " stdout\n")).andReturn(EXEC_GOOD);
clientNew.disconnect(); clientNew.disconnect();
clientNew.connect(); clientNew.connect();
expect(clientNew.exec("./" + scriptName + " stop\n")).andReturn(EXEC_GOOD); expect(clientNew.exec("/tmp/init-" + scriptName + " stop\n")).andReturn(EXEC_GOOD);
clientNew.disconnect(); clientNew.disconnect();
clientNew.connect(); clientNew.connect();
expect(clientNew.exec("./" + scriptName + " start\n")).andReturn(EXEC_GOOD); expect(clientNew.exec("/tmp/init-" + scriptName + " start\n")).andReturn(EXEC_GOOD);
clientNew.disconnect(); clientNew.disconnect();
clientNew.connect(); clientNew.connect();
expect(clientNew.exec("./" + scriptName + " tail\n")).andReturn(EXEC_GOOD); expect(clientNew.exec("/tmp/init-" + scriptName + " stdout\n")).andReturn(EXEC_GOOD);
clientNew.disconnect(); clientNew.disconnect();
} catch (IOException e) { } catch (IOException e) {
Throwables.propagate(e); Throwables.propagate(e);
@ -352,13 +355,14 @@ public class StubComputeServiceIntegrationTest extends BaseComputeServiceLiveTes
expect(client.exec("ln -fs /tmp/init-" + scriptName + " " + scriptName)).andReturn(EXEC_GOOD); expect(client.exec("ln -fs /tmp/init-" + scriptName + " " + scriptName)).andReturn(EXEC_GOOD);
expect(client.getUsername()).andReturn("root").atLeastOnce(); expect(client.getUsername()).andReturn("root").atLeastOnce();
expect(client.getHostAddress()).andReturn(nodeId + "").atLeastOnce(); expect(client.getHostAddress()).andReturn(nodeId + "").atLeastOnce();
expect(client.exec("./" + scriptName + " init")).andReturn(EXEC_GOOD); expect(client.exec("/tmp/init-" + scriptName + " init")).andReturn(EXEC_GOOD);
expect(client.exec("./" + scriptName + " start")).andReturn(EXEC_GOOD); expect(client.exec("/tmp/init-" + scriptName + " start")).andReturn(EXEC_GOOD);
expect(client.exec("./" + scriptName + " status")).andReturn(EXEC_GOOD); expect(client.exec("/tmp/init-" + scriptName + " status")).andReturn(EXEC_GOOD);
// next status says the script is done, since not found. // next status says the script is done, since not found.
expect(client.exec("./" + scriptName + " status")).andReturn(EXEC_BAD); expect(client.exec("/tmp/init-" + scriptName + " status")).andReturn(EXEC_BAD);
expect(client.exec("./" + scriptName + " tail")).andReturn(EXEC_GOOD); expect(client.exec("/tmp/init-" + scriptName + " stdout")).andReturn(EXEC_GOOD);
expect(client.exec("./" + scriptName + " tailerr")).andReturn(EXEC_GOOD); expect(client.exec("/tmp/init-" + scriptName + " stderr")).andReturn(EXEC_GOOD);
expect(client.exec("/tmp/init-" + scriptName + " exitstatus")).andReturn(EXEC_RC_GOOD);
} }
private void helloAndJava(SshClient client) { private void helloAndJava(SshClient client) {

View File

@ -41,7 +41,7 @@ import org.jclouds.concurrent.MoreExecutors;
import org.jclouds.concurrent.config.ExecutorServiceModule; import org.jclouds.concurrent.config.ExecutorServiceModule;
import org.jclouds.domain.LoginCredentials; import org.jclouds.domain.LoginCredentials;
import org.jclouds.predicates.RetryablePredicateTest; import org.jclouds.predicates.RetryablePredicateTest;
import org.jclouds.scriptbuilder.InitBuilder; import org.jclouds.scriptbuilder.InitScript;
import org.jclouds.scriptbuilder.domain.OsFamily; import org.jclouds.scriptbuilder.domain.OsFamily;
import org.jclouds.scriptbuilder.domain.Statement; import org.jclouds.scriptbuilder.domain.Statement;
import org.jclouds.ssh.SshClient; import org.jclouds.ssh.SshClient;
@ -50,7 +50,7 @@ import org.testng.annotations.Test;
import com.google.common.base.Functions; import com.google.common.base.Functions;
import com.google.common.base.Stopwatch; import com.google.common.base.Stopwatch;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet; import com.google.common.eventbus.EventBus;
import com.google.inject.AbstractModule; import com.google.inject.AbstractModule;
import com.google.inject.Guice; import com.google.inject.Guice;
import com.google.inject.assistedinject.FactoryModuleBuilder; import com.google.inject.assistedinject.FactoryModuleBuilder;
@ -62,6 +62,8 @@ import com.google.inject.name.Names;
@Test(groups = "unit", singleThreaded = true, testName = "RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilCompleteTest") @Test(groups = "unit", singleThreaded = true, testName = "RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilCompleteTest")
public class RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilCompleteTest { public class RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilCompleteTest {
EventBus eventBus = new EventBus();
BlockUntilInitScriptStatusIsZeroThenReturnOutput.Factory statusFactory = Guice.createInjector( BlockUntilInitScriptStatusIsZeroThenReturnOutput.Factory statusFactory = Guice.createInjector(
new ExecutorServiceModule(MoreExecutors.sameThreadExecutor(), MoreExecutors.sameThreadExecutor()), new ExecutorServiceModule(MoreExecutors.sameThreadExecutor(), MoreExecutors.sameThreadExecutor()),
new AbstractModule() { new AbstractModule() {
@ -98,7 +100,7 @@ public class RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilCompleteTest {
RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilComplete testMe = new RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilComplete( RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilComplete testMe = new RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilComplete(
statusFactory, timeouts, Functions.forMap(ImmutableMap.of(node, sshClient)), statusFactory, timeouts, Functions.forMap(ImmutableMap.of(node, sshClient)),
InitScriptConfigurationForTasks.create().appendIncrementingNumberToAnonymousTaskNames(), node, command, eventBus, InitScriptConfigurationForTasks.create().appendIncrementingNumberToAnonymousTaskNames(), node, command,
new RunScriptOptions()); new RunScriptOptions());
testMe.call(); testMe.call();
@ -137,13 +139,13 @@ public class RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilCompleteTest {
*/ */
private void runDefaults(IAnswer<ExecResponse> answerForScriptStatus, int timesForScriptStatus) { private void runDefaults(IAnswer<ExecResponse> answerForScriptStatus, int timesForScriptStatus) {
Statement command = exec("doFoo"); Statement command = exec("doFoo");
NodeMetadata node = new NodeMetadataBuilder().ids("id").state(NodeState.RUNNING).credentials( NodeMetadata node = new NodeMetadataBuilder().ids("id").state(NodeState.RUNNING)
new LoginCredentials("tester", "testpassword!", null, false)).build(); .credentials(LoginCredentials.builder().user("tester").password("testpassword!").build()).build();
SshClient sshClient = createMock(SshClient.class); SshClient sshClient = createMock(SshClient.class);
InitBuilder init = new InitBuilder("jclouds-script-0", "/tmp/jclouds-script-0", "/tmp/jclouds-script-0", InitScript init = InitScript.builder().name("jclouds-script-0").home("/tmp/jclouds-script-0").run(command)
ImmutableMap.<String, String> of(), ImmutableSet.of(command)); .build();
sshClient.connect(); sshClient.connect();
sshClient.put("/tmp/init-jclouds-script-0", init.render(OsFamily.UNIX)); sshClient.put("/tmp/init-jclouds-script-0", init.render(OsFamily.UNIX));
@ -154,27 +156,28 @@ public class RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilCompleteTest {
expect(sshClient.exec("chmod 755 /tmp/init-jclouds-script-0")).andReturn(new ExecResponse("", "", 0)); expect(sshClient.exec("chmod 755 /tmp/init-jclouds-script-0")).andReturn(new ExecResponse("", "", 0));
expect(sshClient.exec("ln -fs /tmp/init-jclouds-script-0 jclouds-script-0")).andReturn( expect(sshClient.exec("ln -fs /tmp/init-jclouds-script-0 jclouds-script-0")).andReturn(
new ExecResponse("", "", 0)); new ExecResponse("", "", 0));
expect(sshClient.exec("./jclouds-script-0 init")).andReturn(new ExecResponse("", "", 0)); expect(sshClient.exec("/tmp/init-jclouds-script-0 init")).andReturn(new ExecResponse("", "", 0));
// start script as root via sudo, note that since there's no adminPassword we do a straight // start script as root via sudo, note that since there's no adminPassword we do a straight
// sudo // sudo
expect(sshClient.exec("sudo ./jclouds-script-0 start")).andReturn(new ExecResponse("", "", 0)); expect(sshClient.exec("sudo /tmp/init-jclouds-script-0 start")).andReturn(new ExecResponse("", "", 0));
// signal the command completed // signal the command completed
if (answerForScriptStatus == null) { if (answerForScriptStatus == null) {
expect(sshClient.exec("./jclouds-script-0 status")).andReturn(new ExecResponse("", "", 1)).times(1); expect(sshClient.exec("/tmp/init-jclouds-script-0 status")).andReturn(new ExecResponse("", "", 1)).times(1);
} else { } else {
expect(sshClient.exec("./jclouds-script-0 status")).andAnswer(answerForScriptStatus).times(timesForScriptStatus); expect(sshClient.exec("/tmp/init-jclouds-script-0 status")).andAnswer(answerForScriptStatus).times(timesForScriptStatus);
} }
expect(sshClient.exec("./jclouds-script-0 tail")).andReturn(new ExecResponse("out", "", 0)); expect(sshClient.exec("/tmp/init-jclouds-script-0 stdout")).andReturn(new ExecResponse("out", "", 0));
expect(sshClient.exec("./jclouds-script-0 tailerr")).andReturn(new ExecResponse("err", "", 0)); expect(sshClient.exec("/tmp/init-jclouds-script-0 stderr")).andReturn(new ExecResponse("err", "", 0));
expect(sshClient.exec("/tmp/init-jclouds-script-0 exitstatus")).andReturn(new ExecResponse("0", "", 0));
sshClient.disconnect(); sshClient.disconnect();
replay(sshClient); replay(sshClient);
RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilComplete testMe = new RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilComplete( RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilComplete testMe = new RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilComplete(
statusFactory, timeouts, Functions.forMap(ImmutableMap.of(node, sshClient)), statusFactory, timeouts, Functions.forMap(ImmutableMap.of(node, sshClient)),
InitScriptConfigurationForTasks.create().appendIncrementingNumberToAnonymousTaskNames(), node, command, eventBus, InitScriptConfigurationForTasks.create().appendIncrementingNumberToAnonymousTaskNames(), node, command,
new RunScriptOptions()); new RunScriptOptions());
assertEquals(testMe.getInitFile(), "/tmp/init-jclouds-script-0"); assertEquals(testMe.getInitFile(), "/tmp/init-jclouds-script-0");
@ -195,8 +198,8 @@ public class RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilCompleteTest {
SshClient sshClient = createMock(SshClient.class); SshClient sshClient = createMock(SshClient.class);
InitBuilder init = new InitBuilder("jclouds-script-0", "/tmp/jclouds-script-0", "/tmp/jclouds-script-0", InitScript init = InitScript.builder().name("jclouds-script-0").home("/tmp/jclouds-script-0").run(command)
ImmutableMap.<String, String> of(), ImmutableSet.of(command)); .build();
sshClient.connect(); sshClient.connect();
sshClient.put("/tmp/init-jclouds-script-0", init.render(OsFamily.UNIX)); sshClient.put("/tmp/init-jclouds-script-0", init.render(OsFamily.UNIX));
@ -207,22 +210,23 @@ public class RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilCompleteTest {
expect(sshClient.exec("chmod 755 /tmp/init-jclouds-script-0")).andReturn(new ExecResponse("", "", 0)); expect(sshClient.exec("chmod 755 /tmp/init-jclouds-script-0")).andReturn(new ExecResponse("", "", 0));
expect(sshClient.exec("ln -fs /tmp/init-jclouds-script-0 jclouds-script-0")).andReturn( expect(sshClient.exec("ln -fs /tmp/init-jclouds-script-0 jclouds-script-0")).andReturn(
new ExecResponse("", "", 0)); new ExecResponse("", "", 0));
expect(sshClient.exec("./jclouds-script-0 init")).andReturn(new ExecResponse("", "", 0)); expect(sshClient.exec("/tmp/init-jclouds-script-0 init")).andReturn(new ExecResponse("", "", 0));
// since there's an adminPassword we must pass this in // since there's an adminPassword we must pass this in
expect(sshClient.exec("echo 'testpassword!'|sudo -S ./jclouds-script-0 start")).andReturn(new ExecResponse("", "", 0)); expect(sshClient.exec("echo 'testpassword!'|sudo -S /tmp/init-jclouds-script-0 start")).andReturn(new ExecResponse("", "", 0));
// signal the command completed // signal the command completed
expect(sshClient.exec("./jclouds-script-0 status")).andReturn(new ExecResponse("", "", 1)); expect(sshClient.exec("/tmp/init-jclouds-script-0 status")).andReturn(new ExecResponse("", "", 1));
expect(sshClient.exec("./jclouds-script-0 tail")).andReturn(new ExecResponse("out", "", 0)); expect(sshClient.exec("/tmp/init-jclouds-script-0 stdout")).andReturn(new ExecResponse("out", "", 0));
expect(sshClient.exec("./jclouds-script-0 tailerr")).andReturn(new ExecResponse("err", "", 0)); expect(sshClient.exec("/tmp/init-jclouds-script-0 stderr")).andReturn(new ExecResponse("err", "", 0));
expect(sshClient.exec("/tmp/init-jclouds-script-0 exitstatus")).andReturn(new ExecResponse("0", "", 0));
sshClient.disconnect(); sshClient.disconnect();
replay(sshClient); replay(sshClient);
RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilComplete testMe = new RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilComplete( RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilComplete testMe = new RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilComplete(
statusFactory, timeouts, Functions.forMap(ImmutableMap.of(node, sshClient)), statusFactory, timeouts, Functions.forMap(ImmutableMap.of(node, sshClient)),
InitScriptConfigurationForTasks.create().appendIncrementingNumberToAnonymousTaskNames(), node, command, eventBus, InitScriptConfigurationForTasks.create().appendIncrementingNumberToAnonymousTaskNames(), node, command,
new RunScriptOptions()); new RunScriptOptions());
assertEquals(testMe.getInitFile(), "/tmp/init-jclouds-script-0"); assertEquals(testMe.getInitFile(), "/tmp/init-jclouds-script-0");
@ -243,8 +247,8 @@ public class RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilCompleteTest {
SshClient sshClient = createMock(SshClient.class); SshClient sshClient = createMock(SshClient.class);
InitBuilder init = new InitBuilder("jclouds-script-0", "/tmp/jclouds-script-0", "/tmp/jclouds-script-0", InitScript init = InitScript.builder().name("jclouds-script-0").home("/tmp/jclouds-script-0").run(command)
ImmutableMap.<String, String> of(), ImmutableSet.of(command)); .build();
sshClient.connect(); sshClient.connect();
sshClient.put("/tmp/init-jclouds-script-0", init.render(OsFamily.UNIX)); sshClient.put("/tmp/init-jclouds-script-0", init.render(OsFamily.UNIX));
@ -255,22 +259,23 @@ public class RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilCompleteTest {
expect(sshClient.exec("chmod 755 /tmp/init-jclouds-script-0")).andReturn(new ExecResponse("", "", 0)); expect(sshClient.exec("chmod 755 /tmp/init-jclouds-script-0")).andReturn(new ExecResponse("", "", 0));
expect(sshClient.exec("ln -fs /tmp/init-jclouds-script-0 jclouds-script-0")).andReturn( expect(sshClient.exec("ln -fs /tmp/init-jclouds-script-0 jclouds-script-0")).andReturn(
new ExecResponse("", "", 0)); new ExecResponse("", "", 0));
expect(sshClient.exec("./jclouds-script-0 init")).andReturn(new ExecResponse("", "", 0)); expect(sshClient.exec("/tmp/init-jclouds-script-0 init")).andReturn(new ExecResponse("", "", 0));
// kick off as current user // kick off as current user
expect(sshClient.exec("./jclouds-script-0 start")).andReturn(new ExecResponse("", "", 0)); expect(sshClient.exec("/tmp/init-jclouds-script-0 start")).andReturn(new ExecResponse("", "", 0));
// signal the command completed // signal the command completed
expect(sshClient.exec("./jclouds-script-0 status")).andReturn(new ExecResponse("", "", 1)); expect(sshClient.exec("/tmp/init-jclouds-script-0 status")).andReturn(new ExecResponse("", "", 1));
expect(sshClient.exec("./jclouds-script-0 tail")).andReturn(new ExecResponse("out", "", 0)); expect(sshClient.exec("/tmp/init-jclouds-script-0 stdout")).andReturn(new ExecResponse("out", "", 0));
expect(sshClient.exec("./jclouds-script-0 tailerr")).andReturn(new ExecResponse("err", "", 0)); expect(sshClient.exec("/tmp/init-jclouds-script-0 stderr")).andReturn(new ExecResponse("err", "", 0));
expect(sshClient.exec("/tmp/init-jclouds-script-0 exitstatus")).andReturn(new ExecResponse("0", "", 0));
sshClient.disconnect(); sshClient.disconnect();
replay(sshClient); replay(sshClient);
RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilComplete testMe = new RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilComplete( RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilComplete testMe = new RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilComplete(
statusFactory, timeouts, Functions.forMap(ImmutableMap.of(node, sshClient)), statusFactory, timeouts, Functions.forMap(ImmutableMap.of(node, sshClient)),
InitScriptConfigurationForTasks.create().appendIncrementingNumberToAnonymousTaskNames(), node, command, eventBus, InitScriptConfigurationForTasks.create().appendIncrementingNumberToAnonymousTaskNames(), node, command,
new RunScriptOptions().runAsRoot(false)); new RunScriptOptions().runAsRoot(false));
assertEquals(testMe.getInitFile(), "/tmp/init-jclouds-script-0"); assertEquals(testMe.getInitFile(), "/tmp/init-jclouds-script-0");
@ -284,4 +289,53 @@ public class RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilCompleteTest {
verify(sshClient); verify(sshClient);
} }
public void testBadReturnCode() {
Statement command = exec("doFoo");
NodeMetadata node = new NodeMetadataBuilder().ids("badreturncode").state(NodeState.RUNNING).credentials(
new LoginCredentials("tester", "testpassword!", null, true)).build();
SshClient sshClient = createMock(SshClient.class);
InitScript init = InitScript.builder().name("jclouds-script-0").home("/tmp/jclouds-script-0").run(command)
.build();
sshClient.connect();
sshClient.put("/tmp/init-jclouds-script-0", init.render(OsFamily.UNIX));
expect(sshClient.getUsername()).andReturn("tester").atLeastOnce();
expect(sshClient.getHostAddress()).andReturn("somewhere.example.com").atLeastOnce();
// setup script as default user
expect(sshClient.exec("chmod 755 /tmp/init-jclouds-script-0")).andReturn(new ExecResponse("", "", 0));
expect(sshClient.exec("ln -fs /tmp/init-jclouds-script-0 jclouds-script-0")).andReturn(
new ExecResponse("", "", 0));
expect(sshClient.exec("/tmp/init-jclouds-script-0 init")).andReturn(new ExecResponse("", "", 0));
// kick off as current user
expect(sshClient.exec("/tmp/init-jclouds-script-0 start")).andReturn(new ExecResponse("", "", 0));
// signal the command completed
expect(sshClient.exec("/tmp/init-jclouds-script-0 status")).andReturn(new ExecResponse("", "", 1));
expect(sshClient.exec("/tmp/init-jclouds-script-0 stdout")).andReturn(new ExecResponse("out", "", 0));
expect(sshClient.exec("/tmp/init-jclouds-script-0 stderr")).andReturn(new ExecResponse("err", "", 0));
expect(sshClient.exec("/tmp/init-jclouds-script-0 exitstatus")).andReturn(new ExecResponse("1", "", 0));
sshClient.disconnect();
replay(sshClient);
RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilComplete testMe = new RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilComplete(
statusFactory, timeouts, Functions.forMap(ImmutableMap.of(node, sshClient)),
eventBus, InitScriptConfigurationForTasks.create().appendIncrementingNumberToAnonymousTaskNames(), node, command,
new RunScriptOptions().runAsRoot(false));
assertEquals(testMe.getInitFile(), "/tmp/init-jclouds-script-0");
assertEquals(testMe.getNode(), node);
assertEquals(testMe.getStatement(), init);
testMe.init();
assertEquals(testMe.call(), new ExecResponse("out", "err", 1));
verify(sshClient);
}
} }

View File

@ -31,7 +31,7 @@ import org.jclouds.compute.domain.NodeMetadataBuilder;
import org.jclouds.compute.domain.NodeState; import org.jclouds.compute.domain.NodeState;
import org.jclouds.compute.options.RunScriptOptions; import org.jclouds.compute.options.RunScriptOptions;
import org.jclouds.domain.LoginCredentials; import org.jclouds.domain.LoginCredentials;
import org.jclouds.scriptbuilder.InitBuilder; import org.jclouds.scriptbuilder.InitScript;
import org.jclouds.scriptbuilder.domain.OsFamily; import org.jclouds.scriptbuilder.domain.OsFamily;
import org.jclouds.scriptbuilder.domain.Statement; import org.jclouds.scriptbuilder.domain.Statement;
import org.jclouds.ssh.SshClient; import org.jclouds.ssh.SshClient;
@ -39,13 +39,14 @@ import org.testng.annotations.Test;
import com.google.common.base.Functions; import com.google.common.base.Functions;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet; import com.google.common.eventbus.EventBus;
/** /**
* @author Adrian Cole * @author Adrian Cole
*/ */
@Test(groups = "unit", singleThreaded = true, testName = "RunScriptOnNodeAsInitScriptUsingSshTest") @Test(groups = "unit", singleThreaded = true, testName = "RunScriptOnNodeAsInitScriptUsingSshTest")
public class RunScriptOnNodeAsInitScriptUsingSshTest { public class RunScriptOnNodeAsInitScriptUsingSshTest {
EventBus eventBus = new EventBus();
@Test(expectedExceptions = IllegalStateException.class) @Test(expectedExceptions = IllegalStateException.class)
public void testWithoutInitThrowsIllegalStateException() { public void testWithoutInitThrowsIllegalStateException() {
@ -58,7 +59,7 @@ public class RunScriptOnNodeAsInitScriptUsingSshTest {
replay(sshClient); replay(sshClient);
RunScriptOnNodeAsInitScriptUsingSsh testMe = new RunScriptOnNodeAsInitScriptUsingSsh(Functions RunScriptOnNodeAsInitScriptUsingSsh testMe = new RunScriptOnNodeAsInitScriptUsingSsh(Functions
.forMap(ImmutableMap.of(node, sshClient)), InitScriptConfigurationForTasks.create() .forMap(ImmutableMap.of(node, sshClient)), eventBus, InitScriptConfigurationForTasks.create()
.appendIncrementingNumberToAnonymousTaskNames(), node, command, new RunScriptOptions()); .appendIncrementingNumberToAnonymousTaskNames(), node, command, new RunScriptOptions());
testMe.call(); testMe.call();
@ -71,8 +72,8 @@ public class RunScriptOnNodeAsInitScriptUsingSshTest {
SshClient sshClient = createMock(SshClient.class); SshClient sshClient = createMock(SshClient.class);
InitBuilder init = new InitBuilder("jclouds-script-0", "/tmp/jclouds-script-0", "/tmp/jclouds-script-0", InitScript init = InitScript.builder().name("jclouds-script-0").home("/tmp/jclouds-script-0").run(command)
ImmutableMap.<String, String> of(), ImmutableSet.of(command)); .build();
sshClient.connect(); sshClient.connect();
sshClient.put("/tmp/init-jclouds-script-0", init.render(OsFamily.UNIX)); sshClient.put("/tmp/init-jclouds-script-0", init.render(OsFamily.UNIX));
@ -82,17 +83,17 @@ public class RunScriptOnNodeAsInitScriptUsingSshTest {
// setup script as default user // setup script as default user
expect(sshClient.exec("chmod 755 /tmp/init-jclouds-script-0")).andReturn(new ExecResponse("", "", 0)); expect(sshClient.exec("chmod 755 /tmp/init-jclouds-script-0")).andReturn(new ExecResponse("", "", 0));
expect(sshClient.exec("ln -fs /tmp/init-jclouds-script-0 jclouds-script-0")).andReturn(new ExecResponse("", "", 0)); expect(sshClient.exec("ln -fs /tmp/init-jclouds-script-0 jclouds-script-0")).andReturn(new ExecResponse("", "", 0));
expect(sshClient.exec("./jclouds-script-0 init")).andReturn(new ExecResponse("", "", 0)); expect(sshClient.exec("/tmp/init-jclouds-script-0 init")).andReturn(new ExecResponse("", "", 0));
// start script as root via sudo, note that since there's no adminPassword we do a straight sudo // start script as root via sudo, note that since there's no adminPassword we do a straight sudo
expect(sshClient.exec("sudo ./jclouds-script-0 start")).andReturn(new ExecResponse("", "", 0)); expect(sshClient.exec("sudo /tmp/init-jclouds-script-0 start")).andReturn(new ExecResponse("", "", 0));
sshClient.disconnect(); sshClient.disconnect();
replay(sshClient); replay(sshClient);
RunScriptOnNodeAsInitScriptUsingSsh testMe = new RunScriptOnNodeAsInitScriptUsingSsh(Functions RunScriptOnNodeAsInitScriptUsingSsh testMe = new RunScriptOnNodeAsInitScriptUsingSsh(Functions
.forMap(ImmutableMap.of(node, sshClient)), InitScriptConfigurationForTasks.create() .forMap(ImmutableMap.of(node, sshClient)), eventBus, InitScriptConfigurationForTasks.create()
.appendIncrementingNumberToAnonymousTaskNames(), node, command, new RunScriptOptions()); .appendIncrementingNumberToAnonymousTaskNames(), node, command, new RunScriptOptions());
assertEquals(testMe.getInitFile(), "/tmp/init-jclouds-script-0"); assertEquals(testMe.getInitFile(), "/tmp/init-jclouds-script-0");
@ -112,8 +113,8 @@ public class RunScriptOnNodeAsInitScriptUsingSshTest {
SshClient sshClient = createMock(SshClient.class); SshClient sshClient = createMock(SshClient.class);
InitBuilder init = new InitBuilder("jclouds-script-0", "/tmp/jclouds-script-0", "/tmp/jclouds-script-0", InitScript init = InitScript.builder().name("jclouds-script-0").home("/tmp/jclouds-script-0").run(command)
ImmutableMap.<String, String> of(), ImmutableSet.of(command)); .build();
sshClient.connect(); sshClient.connect();
sshClient.put("/tmp/init-jclouds-script-0", init.render(OsFamily.UNIX)); sshClient.put("/tmp/init-jclouds-script-0", init.render(OsFamily.UNIX));
@ -123,17 +124,17 @@ public class RunScriptOnNodeAsInitScriptUsingSshTest {
// setup script as default user // setup script as default user
expect(sshClient.exec("chmod 755 /tmp/init-jclouds-script-0")).andReturn(new ExecResponse("", "", 0)); expect(sshClient.exec("chmod 755 /tmp/init-jclouds-script-0")).andReturn(new ExecResponse("", "", 0));
expect(sshClient.exec("ln -fs /tmp/init-jclouds-script-0 jclouds-script-0")).andReturn(new ExecResponse("", "", 0)); expect(sshClient.exec("ln -fs /tmp/init-jclouds-script-0 jclouds-script-0")).andReturn(new ExecResponse("", "", 0));
expect(sshClient.exec("./jclouds-script-0 init")).andReturn(new ExecResponse("", "", 0)); expect(sshClient.exec("/tmp/init-jclouds-script-0 init")).andReturn(new ExecResponse("", "", 0));
// since there's an adminPassword we must pass this in // since there's an adminPassword we must pass this in
expect(sshClient.exec("echo 'notalot'|sudo -S ./jclouds-script-0 start")).andReturn(new ExecResponse("", "", 0)); expect(sshClient.exec("echo 'notalot'|sudo -S /tmp/init-jclouds-script-0 start")).andReturn(new ExecResponse("", "", 0));
sshClient.disconnect(); sshClient.disconnect();
replay(sshClient); replay(sshClient);
RunScriptOnNodeAsInitScriptUsingSsh testMe = new RunScriptOnNodeAsInitScriptUsingSsh(Functions RunScriptOnNodeAsInitScriptUsingSsh testMe = new RunScriptOnNodeAsInitScriptUsingSsh(Functions
.forMap(ImmutableMap.of(node, sshClient)), InitScriptConfigurationForTasks.create() .forMap(ImmutableMap.of(node, sshClient)), eventBus, InitScriptConfigurationForTasks.create()
.appendIncrementingNumberToAnonymousTaskNames(), node, command, new RunScriptOptions()); .appendIncrementingNumberToAnonymousTaskNames(), node, command, new RunScriptOptions());
assertEquals(testMe.getInitFile(), "/tmp/init-jclouds-script-0"); assertEquals(testMe.getInitFile(), "/tmp/init-jclouds-script-0");
@ -154,8 +155,8 @@ public class RunScriptOnNodeAsInitScriptUsingSshTest {
SshClient sshClient = createMock(SshClient.class); SshClient sshClient = createMock(SshClient.class);
InitBuilder init = new InitBuilder("jclouds-script-0", "/tmp/jclouds-script-0", "/tmp/jclouds-script-0", InitScript init = InitScript.builder().name("jclouds-script-0").home("/tmp/jclouds-script-0").run(command)
ImmutableMap.<String, String> of(), ImmutableSet.of(command)); .build();
sshClient.connect(); sshClient.connect();
sshClient.put("/tmp/init-jclouds-script-0", init.render(OsFamily.UNIX)); sshClient.put("/tmp/init-jclouds-script-0", init.render(OsFamily.UNIX));
@ -165,16 +166,16 @@ public class RunScriptOnNodeAsInitScriptUsingSshTest {
// setup script as default user // setup script as default user
expect(sshClient.exec("chmod 755 /tmp/init-jclouds-script-0")).andReturn(new ExecResponse("", "", 0)); expect(sshClient.exec("chmod 755 /tmp/init-jclouds-script-0")).andReturn(new ExecResponse("", "", 0));
expect(sshClient.exec("ln -fs /tmp/init-jclouds-script-0 jclouds-script-0")).andReturn(new ExecResponse("", "", 0)); expect(sshClient.exec("ln -fs /tmp/init-jclouds-script-0 jclouds-script-0")).andReturn(new ExecResponse("", "", 0));
expect(sshClient.exec("./jclouds-script-0 init")).andReturn(new ExecResponse("", "", 0)); expect(sshClient.exec("/tmp/init-jclouds-script-0 init")).andReturn(new ExecResponse("", "", 0));
// kick off as current user // kick off as current user
expect(sshClient.exec("./jclouds-script-0 start")).andReturn(new ExecResponse("", "", 0)); expect(sshClient.exec("/tmp/init-jclouds-script-0 start")).andReturn(new ExecResponse("", "", 0));
sshClient.disconnect(); sshClient.disconnect();
replay(sshClient); replay(sshClient);
RunScriptOnNodeAsInitScriptUsingSsh testMe = new RunScriptOnNodeAsInitScriptUsingSsh(Functions RunScriptOnNodeAsInitScriptUsingSsh testMe = new RunScriptOnNodeAsInitScriptUsingSsh(Functions
.forMap(ImmutableMap.of(node, sshClient)), InitScriptConfigurationForTasks.create() .forMap(ImmutableMap.of(node, sshClient)), eventBus, InitScriptConfigurationForTasks.create()
.appendIncrementingNumberToAnonymousTaskNames(), node, command, new RunScriptOptions().runAsRoot(false)); .appendIncrementingNumberToAnonymousTaskNames(), node, command, new RunScriptOptions().runAsRoot(false));
assertEquals(testMe.getInitFile(), "/tmp/init-jclouds-script-0"); assertEquals(testMe.getInitFile(), "/tmp/init-jclouds-script-0");

View File

@ -34,12 +34,15 @@ import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.base.Function; import com.google.common.base.Function;
import com.google.common.eventbus.EventBus;
/** /**
* @author Adam Lowe * @author Adam Lowe
*/ */
@Test(groups = { "unit" }, singleThreaded = true) @Test(groups = { "unit" }, singleThreaded = true)
public class RunScriptOnNodeUsingSshTest { public class RunScriptOnNodeUsingSshTest {
EventBus eventBus = new EventBus();
private SshClient sshClient; private SshClient sshClient;
private NodeMetadata node; private NodeMetadata node;
private Function<NodeMetadata, SshClient> sshFactory; private Function<NodeMetadata, SshClient> sshFactory;
@ -59,7 +62,7 @@ public class RunScriptOnNodeUsingSshTest {
} }
public void simpleTest() { public void simpleTest() {
RunScriptOnNodeUsingSsh testMe = new RunScriptOnNodeUsingSsh(sshFactory, node, exec("echo $USER\necho $USER"), RunScriptOnNodeUsingSsh testMe = new RunScriptOnNodeUsingSsh(sshFactory, eventBus, node, exec("echo $USER\necho $USER"),
wrapInInitScript(false).runAsRoot(false)); wrapInInitScript(false).runAsRoot(false));
testMe.init(); testMe.init();
@ -75,7 +78,7 @@ public class RunScriptOnNodeUsingSshTest {
} }
public void simpleRootTest() { public void simpleRootTest() {
RunScriptOnNodeUsingSsh testMe = new RunScriptOnNodeUsingSsh(sshFactory, node, exec("echo $USER\necho $USER"), RunScriptOnNodeUsingSsh testMe = new RunScriptOnNodeUsingSsh(sshFactory, eventBus, node, exec("echo $USER\necho $USER"),
wrapInInitScript(false).runAsRoot(true)); wrapInInitScript(false).runAsRoot(true));
testMe.init(); testMe.init();
@ -97,7 +100,7 @@ public class RunScriptOnNodeUsingSshTest {
expect(node.getCredentials()).andReturn(new LoginCredentials("tester", "testpassword!", null, true)) expect(node.getCredentials()).andReturn(new LoginCredentials("tester", "testpassword!", null, true))
.atLeastOnce(); .atLeastOnce();
replay(node); replay(node);
RunScriptOnNodeUsingSsh testMe = new RunScriptOnNodeUsingSsh(sshFactory, node, exec("echo $USER\necho $USER"), RunScriptOnNodeUsingSsh testMe = new RunScriptOnNodeUsingSsh(sshFactory, eventBus, node, exec("echo $USER\necho $USER"),
wrapInInitScript(false).runAsRoot(true)); wrapInInitScript(false).runAsRoot(true));
testMe.init(); testMe.init();
@ -114,7 +117,7 @@ public class RunScriptOnNodeUsingSshTest {
} }
public void testUserAddAsRoot() { public void testUserAddAsRoot() {
RunScriptOnNodeUsingSsh testMe = new RunScriptOnNodeUsingSsh(sshFactory, node, UserAdd.builder() RunScriptOnNodeUsingSsh testMe = new RunScriptOnNodeUsingSsh(sshFactory, eventBus, node, UserAdd.builder()
.login("testuser").build(), wrapInInitScript(false).runAsRoot(true).overrideLoginPassword("test")); .login("testuser").build(), wrapInInitScript(false).runAsRoot(true).overrideLoginPassword("test"));
testMe.init(); testMe.init();

View File

@ -32,9 +32,13 @@ import javax.inject.Provider;
import org.jclouds.compute.domain.Hardware; import org.jclouds.compute.domain.Hardware;
import org.jclouds.compute.domain.HardwareBuilder; import org.jclouds.compute.domain.HardwareBuilder;
import org.jclouds.compute.domain.Image; import org.jclouds.compute.domain.Image;
import org.jclouds.compute.domain.ImageBuilder;
import org.jclouds.compute.domain.OperatingSystem; import org.jclouds.compute.domain.OperatingSystem;
import org.jclouds.compute.domain.OsFamily; import org.jclouds.compute.domain.OsFamily;
import org.jclouds.compute.domain.Processor;
import org.jclouds.compute.domain.Template;
import org.jclouds.compute.domain.TemplateBuilder; import org.jclouds.compute.domain.TemplateBuilder;
import org.jclouds.compute.domain.Volume;
import org.jclouds.compute.options.TemplateOptions; import org.jclouds.compute.options.TemplateOptions;
import org.jclouds.compute.predicates.ImagePredicates; import org.jclouds.compute.predicates.ImagePredicates;
import org.jclouds.domain.Location; import org.jclouds.domain.Location;
@ -43,6 +47,7 @@ import org.testng.annotations.Test;
import com.google.common.base.Supplier; import com.google.common.base.Supplier;
import com.google.common.base.Suppliers; import com.google.common.base.Suppliers;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
/** /**
@ -385,7 +390,7 @@ public class TemplateBuilderImplTest {
// make sure big data is not in the exception message // make sure big data is not in the exception message
assertEquals( assertEquals(
e.getMessage(), e.getMessage(),
"no hardware profiles support images matching params: [biggest=false, fastest=false, imageName=null, imageDescription=null, imageId=myregion/imageId, imagePredicate=null, imageVersion=null, location=EasyMock for interface org.jclouds.domain.Location, minCores=0.0, minRam=0, osFamily=null, osName=null, osDescription=null, osVersion=null, osArch=null, os64Bit=false, hardwareId=null]"); "no hardware profiles support images matching params: [biggest=false, fastest=false, imageName=null, imageDescription=null, imageId=myregion/imageId, imagePredicate=null, imageVersion=null, location=EasyMock for interface org.jclouds.domain.Location, minCores=0.0, minRam=0, osFamily=null, osName=null, osDescription=null, osVersion=null, osArch=null, os64Bit=false, hardwareId=null, hypervisor=null]");
verify(image); verify(image);
verify(os); verify(os);
verify(defaultTemplate); verify(defaultTemplate);
@ -772,4 +777,110 @@ public class TemplateBuilderImplTest {
verify(templateBuilderProvider); verify(templateBuilderProvider);
} }
@SuppressWarnings("unchecked")
@Test
public void testHardwareIdNullsHypervisor() {
Supplier<Set<? extends Location>> locations = Suppliers.<Set<? extends Location>> ofInstance(ImmutableSet
.<Location> of());
Supplier<Set<? extends Image>> images = Suppliers.<Set<? extends Image>> ofInstance(ImmutableSet.<Image> of());
Supplier<Set<? extends Hardware>> hardwares = Suppliers.<Set<? extends Hardware>> ofInstance(ImmutableSet
.<Hardware> of());
Location defaultLocation = createMock(Location.class);
Provider<TemplateOptions> optionsProvider = createMock(Provider.class);
Provider<TemplateBuilder> templateBuilderProvider = createMock(Provider.class);
replay(defaultLocation);
replay(optionsProvider);
replay(templateBuilderProvider);
TemplateBuilderImpl template = createTemplateBuilder(null, locations, images, hardwares, defaultLocation,
optionsProvider, templateBuilderProvider);
template.hypervisorMatches("OpenVZ");
assertEquals(template.hardwareId, null);
assertEquals(template.hypervisor, "OpenVZ");
template.hardwareId("myid");
assertEquals(template.hardwareId, "myid");
assertEquals(template.hypervisor, null);
verify(defaultLocation);
verify(optionsProvider);
verify(templateBuilderProvider);
}
@Test
public void testMatchesHardwareWithIdPredicate() {
final Location defaultLocation = createMock(Location.class);
final Supplier<Set<? extends Location>> locations = Suppliers.<Set<? extends Location>> ofInstance(ImmutableSet
.<Location> of(defaultLocation));
final Supplier<Set<? extends Image>> images = Suppliers.<Set<? extends Image>> ofInstance(ImmutableSet
.<Image> of(
new ImageBuilder()
.ids("Ubuntu 11.04 x64")
.name("Ubuntu 11.04 x64")
.description("Ubuntu 11.04 x64")
.location(defaultLocation)
.operatingSystem(
OperatingSystem.builder().name("Ubuntu 11.04 x64").description("Ubuntu 11.04 x64")
.is64Bit(true).version("11.04").family(OsFamily.UBUNTU).build()).build(),
new ImageBuilder()
.ids("Ubuntu 11.04 64-bit")
.name("Ubuntu 11.04 64-bit")
.description("Ubuntu 11.04 64-bit")
.location(defaultLocation)
.operatingSystem(
OperatingSystem.builder().name("Ubuntu 11.04 64-bit").description("Ubuntu 11.04 64-bit")
.is64Bit(true).version("11.04").family(OsFamily.UBUNTU).build()).build()));
final Supplier<Set<? extends Hardware>> hardwares = Suppliers.<Set<? extends Hardware>> ofInstance(ImmutableSet
.<Hardware> of(
new HardwareBuilder()
.ids(String.format("datacenter(%s)platform(%s)cpuCores(%d)memorySizeMB(%d)diskSizeGB(%d)",
"Falkenberg", "Xen", 1, 512, 5)).ram(512)
.processors(ImmutableList.of(new Processor(1, 1.0)))
.volumes(ImmutableList.<Volume> of(new VolumeImpl((float) 5, true, true))).hypervisor("Xen")
.location(defaultLocation)
.supportsImage(ImagePredicates.idIn(ImmutableSet.of("Ubuntu 11.04 x64"))).build(),
new HardwareBuilder()
.ids(String.format("datacenter(%s)platform(%s)cpuCores(%d)memorySizeMB(%d)diskSizeGB(%d)",
"Falkenberg", "OpenVZ", 1, 512, 5)).ram(512)
.processors(ImmutableList.of(new Processor(1, 1.0)))
.volumes(ImmutableList.<Volume> of(new VolumeImpl((float) 5, true, true))).hypervisor("OpenVZ")
.location(defaultLocation)
.supportsImage(ImagePredicates.idIn(ImmutableSet.of("Ubuntu 11.04 64-bit"))).build()));
final Provider<TemplateOptions> optionsProvider = new Provider<TemplateOptions>() {
@Override
public TemplateOptions get() {
return new TemplateOptions();
}
};
Provider<TemplateBuilder> templateBuilderProvider = new Provider<TemplateBuilder>() {
@Override
public TemplateBuilder get() {
return createTemplateBuilder(null, locations, images, hardwares, defaultLocation, optionsProvider, this);
}
};
expect(defaultLocation.getId()).andReturn("region").anyTimes();
replay(defaultLocation);
TemplateBuilder templateBuilder = templateBuilderProvider.get().minRam(512).osFamily(OsFamily.UBUNTU)
.hypervisorMatches("OpenVZ").osVersionMatches("1[10].[10][04]").os64Bit(true);
Template template = templateBuilder.build();
assertEquals(template.getHardware().getHypervisor(), "OpenVZ");
assertEquals(template.getImage().getId(), "Ubuntu 11.04 64-bit");
verify(defaultLocation);
}
} }

View File

@ -0,0 +1,144 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.compute.predicates;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import static org.easymock.EasyMock.verify;
import java.util.concurrent.atomic.AtomicReference;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.domain.NodeMetadataBuilder;
import org.jclouds.compute.domain.NodeState;
import org.jclouds.compute.strategy.GetNodeMetadataStrategy;
import org.testng.Assert;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
/**
* Tests possible uses of NodePredicates
*
* @author Aled Sage, Adrian Cole
*/
@Test(singleThreaded = true, testName = "AtomicNodePredicatesTest")
public class AtomicNodePredicatesTest {
private NodeMetadata node;
private GetNodeMetadataStrategy computeService;
@Test
public void testNoUpdatesAtomicReferenceOnPass() {
NodeMetadata running = new NodeMetadataBuilder().id("myid").state(NodeState.RUNNING).build();
GetNodeMetadataStrategy computeService = createMock(GetNodeMetadataStrategy.class);
replay(computeService);
AtomicNodeRunning nodeRunning = new AtomicNodeRunning(computeService);
AtomicReference<NodeMetadata> reference = new AtomicReference<NodeMetadata>(running);
Assert.assertTrue(nodeRunning.apply(reference));
Assert.assertEquals(reference.get(), running);
verify(computeService);
}
@Test
public void testRefreshUpdatesAtomicReferenceOnRecheckPending() {
NodeMetadata pending = new NodeMetadataBuilder().id("myid").state(NodeState.PENDING).build();
GetNodeMetadataStrategy computeService = createMock(GetNodeMetadataStrategy.class);
expect(computeService.getNode("myid")).andReturn(pending);
replay(computeService);
AtomicNodeRunning nodeRunning = new AtomicNodeRunning(computeService);
AtomicReference<NodeMetadata> reference = new AtomicReference<NodeMetadata>(pending);
Assert.assertFalse(nodeRunning.apply(reference));
Assert.assertEquals(reference.get(), pending);
verify(computeService);
}
@Test
public void testRefreshUpdatesAtomicReferenceOnRecheckRunning() {
NodeMetadata running = new NodeMetadataBuilder().id("myid").state(NodeState.RUNNING).build();
NodeMetadata pending = new NodeMetadataBuilder().id("myid").state(NodeState.PENDING).build();
GetNodeMetadataStrategy computeService = createMock(GetNodeMetadataStrategy.class);
expect(computeService.getNode("myid")).andReturn(running);
replay(computeService);
AtomicNodeRunning nodeRunning = new AtomicNodeRunning(computeService);
AtomicReference<NodeMetadata> reference = new AtomicReference<NodeMetadata>(pending);
Assert.assertTrue(nodeRunning.apply(reference));
Assert.assertEquals(reference.get(), running);
verify(computeService);
}
@BeforeMethod
public void setUp() throws Exception {
node = createMock(NodeMetadata.class);
computeService = createMock(GetNodeMetadataStrategy.class);
expect(node.getId()).andReturn("myid").anyTimes();
expect(computeService.getNode("myid")).andReturn(node).anyTimes();
expect(node.getLocation()).andReturn(null).anyTimes();
}
@Test
public void testNodeRunningReturnsTrueWhenRunning() {
expect(node.getState()).andReturn(NodeState.RUNNING).atLeastOnce();
replay(node);
replay(computeService);
AtomicNodeRunning nodeRunning = new AtomicNodeRunning(computeService);
AtomicReference<NodeMetadata> reference = new AtomicReference<NodeMetadata>(node);
Assert.assertTrue(nodeRunning.apply(reference));
Assert.assertEquals(reference.get(), node);
}
@Test(expectedExceptions = IllegalStateException.class)
public void testNodeRunningFailsOnTerminated() {
expect(node.getState()).andReturn(NodeState.TERMINATED).atLeastOnce();
replay(node);
replay(computeService);
AtomicNodeRunning nodeRunning = new AtomicNodeRunning(computeService);
AtomicReference<NodeMetadata> reference = new AtomicReference<NodeMetadata>(node);
nodeRunning.apply(reference);
Assert.assertEquals(reference.get(), node);
}
@Test(expectedExceptions = IllegalStateException.class)
public void testNodeRunningFailsOnError() {
expect(node.getState()).andReturn(NodeState.ERROR).atLeastOnce();
replay(node);
replay(computeService);
AtomicNodeRunning nodeRunning = new AtomicNodeRunning(computeService);
AtomicReference<NodeMetadata> reference = new AtomicReference<NodeMetadata>(node);
nodeRunning.apply(reference);
Assert.assertEquals(reference.get(), node);
}
}

View File

@ -18,14 +18,14 @@
*/ */
package org.jclouds.compute.strategy; package org.jclouds.compute.strategy;
import static org.easymock.EasyMock.expect; import static org.easymock.EasyMock.createMock;
import static org.easymock.classextension.EasyMock.createMock; import static org.easymock.EasyMock.replay;
import static org.easymock.classextension.EasyMock.replay; import static org.easymock.EasyMock.verify;
import static org.easymock.classextension.EasyMock.verify;
import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertEquals;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;
import org.jclouds.compute.config.CustomizationResponse; import org.jclouds.compute.config.CustomizationResponse;
import org.jclouds.compute.domain.NodeMetadata; import org.jclouds.compute.domain.NodeMetadata;
@ -33,13 +33,14 @@ import org.jclouds.compute.domain.NodeMetadataBuilder;
import org.jclouds.compute.domain.NodeState; import org.jclouds.compute.domain.NodeState;
import org.jclouds.compute.functions.TemplateOptionsToStatement; import org.jclouds.compute.functions.TemplateOptionsToStatement;
import org.jclouds.compute.options.TemplateOptions; import org.jclouds.compute.options.TemplateOptions;
import org.jclouds.compute.predicates.AtomicNodeRunning;
import org.jclouds.compute.predicates.RetryIfSocketNotYetOpen; import org.jclouds.compute.predicates.RetryIfSocketNotYetOpen;
import org.jclouds.compute.reference.ComputeServiceConstants.Timeouts; import org.jclouds.compute.reference.ComputeServiceConstants.Timeouts;
import org.jclouds.scriptbuilder.domain.Statement; import org.jclouds.scriptbuilder.domain.Statement;
import org.testng.Assert;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.base.Function; import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.common.collect.LinkedHashMultimap; import com.google.common.collect.LinkedHashMultimap;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
@ -52,11 +53,8 @@ import com.google.common.collect.Sets;
@Test(groups = "unit") @Test(groups = "unit")
public class CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapTest { public class CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapTest {
@SuppressWarnings("unchecked")
public void testBreakWhenNodeStillPending() { public void testBreakWhenNodeStillPending() {
Predicate<NodeMetadata> nodeRunning = createMock(Predicate.class);
InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory = createMock(InitializeRunScriptOnNodeOrPlaceInBadMap.Factory.class); InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory = createMock(InitializeRunScriptOnNodeOrPlaceInBadMap.Factory.class);
GetNodeMetadataStrategy getNode = createMock(GetNodeMetadataStrategy.class);
RetryIfSocketNotYetOpen socketTester = createMock(RetryIfSocketNotYetOpen.class); RetryIfSocketNotYetOpen socketTester = createMock(RetryIfSocketNotYetOpen.class);
Timeouts timeouts = new Timeouts(); Timeouts timeouts = new Timeouts();
Function<TemplateOptions, Statement> templateOptionsToStatement = new TemplateOptionsToStatement(); Function<TemplateOptions, Statement> templateOptionsToStatement = new TemplateOptionsToStatement();
@ -67,41 +65,39 @@ public class CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapTest {
Map<NodeMetadata, Exception> badNodes = Maps.newLinkedHashMap(); Map<NodeMetadata, Exception> badNodes = Maps.newLinkedHashMap();
Multimap<NodeMetadata, CustomizationResponse> customizationResponses = LinkedHashMultimap.create(); Multimap<NodeMetadata, CustomizationResponse> customizationResponses = LinkedHashMultimap.create();
NodeMetadata node = new NodeMetadataBuilder().ids("id").state(NodeState.PENDING).build(); final NodeMetadata node = new NodeMetadataBuilder().ids("id").state(NodeState.PENDING).build();
// node never reached running state // node always stays pending
expect(nodeRunning.apply(node)).andReturn(false); GetNodeMetadataStrategy nodeRunning = new GetNodeMetadataStrategy(){
expect(getNode.getNode(node.getId())).andReturn(node);
@Override
public NodeMetadata getNode(String input) {
Assert.assertEquals(input, node.getId());
return node;
}
};
// replay mocks // replay mocks
replay(nodeRunning); replay(initScriptRunnerFactory, socketTester);
replay(initScriptRunnerFactory);
replay(getNode);
replay(socketTester);
// run // run
new CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap(nodeRunning, getNode, socketTester, timeouts, AtomicReference<NodeMetadata> atomicNode = new AtomicReference<NodeMetadata>(node);
templateOptionsToStatement, initScriptRunnerFactory, options, node, goodNodes, badNodes, new CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap( new AtomicNodeRunning(nodeRunning), socketTester, timeouts,
customizationResponses).apply(node); templateOptionsToStatement, initScriptRunnerFactory, options, atomicNode, goodNodes, badNodes,
customizationResponses).apply(atomicNode);
assertEquals(goodNodes.size(), 0); assertEquals(goodNodes.size(), 0);
assertEquals(badNodes.keySet(), ImmutableSet.of(node)); assertEquals(badNodes.keySet(), ImmutableSet.of(node));
assertEquals(badNodes.get(node).getMessage(), assertEquals(badNodes.get(node).getMessage(),
"node(id) didn't achieve the state running within 1200 seconds, final state: PENDING"); "node(id) didn't achieve the state running within 1200 seconds, so we couldn't customize; final state: PENDING");
assertEquals(customizationResponses.size(), 0); assertEquals(customizationResponses.size(), 0);
// verify mocks // verify mocks
verify(nodeRunning); verify(initScriptRunnerFactory, socketTester);
verify(initScriptRunnerFactory);
verify(getNode);
verify(socketTester);
} }
@SuppressWarnings("unchecked")
public void testBreakGraceFullyWhenNodeDied() { public void testBreakGraceFullyWhenNodeDied() {
Predicate<NodeMetadata> nodeRunning = createMock(Predicate.class);
InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory = createMock(InitializeRunScriptOnNodeOrPlaceInBadMap.Factory.class); InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory = createMock(InitializeRunScriptOnNodeOrPlaceInBadMap.Factory.class);
GetNodeMetadataStrategy getNode = createMock(GetNodeMetadataStrategy.class);
RetryIfSocketNotYetOpen socketTester = createMock(RetryIfSocketNotYetOpen.class); RetryIfSocketNotYetOpen socketTester = createMock(RetryIfSocketNotYetOpen.class);
Timeouts timeouts = new Timeouts(); Timeouts timeouts = new Timeouts();
Function<TemplateOptions, Statement> templateOptionsToStatement = new TemplateOptionsToStatement(); Function<TemplateOptions, Statement> templateOptionsToStatement = new TemplateOptionsToStatement();
@ -112,32 +108,35 @@ public class CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapTest {
Map<NodeMetadata, Exception> badNodes = Maps.newLinkedHashMap(); Map<NodeMetadata, Exception> badNodes = Maps.newLinkedHashMap();
Multimap<NodeMetadata, CustomizationResponse> customizationResponses = LinkedHashMultimap.create(); Multimap<NodeMetadata, CustomizationResponse> customizationResponses = LinkedHashMultimap.create();
NodeMetadata node = new NodeMetadataBuilder().ids("id").state(NodeState.PENDING).build(); final NodeMetadata node = new NodeMetadataBuilder().ids("id").state(NodeState.PENDING).build();
final NodeMetadata deadNnode = new NodeMetadataBuilder().ids("id").state(NodeState.TERMINATED).build();
// node never reached running state // node dies
expect(nodeRunning.apply(node)).andReturn(false); GetNodeMetadataStrategy nodeRunning = new GetNodeMetadataStrategy(){
expect(getNode.getNode(node.getId())).andReturn(null);
@Override
public NodeMetadata getNode(String input) {
Assert.assertEquals(input, node.getId());
return deadNnode;
}
};
// replay mocks // replay mocks
replay(nodeRunning); replay(initScriptRunnerFactory, socketTester);
replay(initScriptRunnerFactory);
replay(getNode);
replay(socketTester);
// run // run
new CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap(nodeRunning, getNode, socketTester, timeouts, AtomicReference<NodeMetadata> atomicNode = new AtomicReference<NodeMetadata>(node);
templateOptionsToStatement, initScriptRunnerFactory, options, node, goodNodes, badNodes, new CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap( new AtomicNodeRunning(nodeRunning), socketTester, timeouts,
customizationResponses).apply(node); templateOptionsToStatement, initScriptRunnerFactory, options, atomicNode, goodNodes, badNodes,
customizationResponses).apply(atomicNode);
assertEquals(goodNodes.size(), 0); assertEquals(goodNodes.size(), 0);
assertEquals(badNodes.keySet(), ImmutableSet.of(node)); assertEquals(badNodes.keySet(), ImmutableSet.of(node));
badNodes.get(node).printStackTrace();
assertEquals(badNodes.get(node).getMessage(), "node(id) terminated before we could customize"); assertEquals(badNodes.get(node).getMessage(), "node(id) terminated before we could customize");
assertEquals(customizationResponses.size(), 0); assertEquals(customizationResponses.size(), 0);
// verify mocks // verify mocks
verify(nodeRunning); verify(initScriptRunnerFactory, socketTester);
verify(initScriptRunnerFactory);
verify(getNode);
verify(socketTester);
} }
} }

View File

@ -10,11 +10,11 @@ function abort {
function default { function default {
export INSTANCE_NAME="bootstrap" export INSTANCE_NAME="bootstrap"
export INSTANCE_HOME="/tmp/bootstrap" export INSTANCE_HOME="/tmp/bootstrap"
export LOG_DIR="/tmp/bootstrap" export LOG_DIR="$INSTANCE_HOME"
return 0 return $?
} }
function bootstrap { function bootstrap {
return 0 return $?
} }
function findPid { function findPid {
unset FOUND_PID; unset FOUND_PID;
@ -62,75 +62,134 @@ init)
mkdir -p $INSTANCE_HOME mkdir -p $INSTANCE_HOME
# create runscript header # create runscript header
cat > $INSTANCE_HOME/bootstrap.sh <<END_OF_SCRIPT cat > $INSTANCE_HOME/bootstrap.sh <<-'END_OF_JCLOUDS_SCRIPT'
#!/bin/bash #!/bin/bash
set +u set +u
shopt -s xpg_echo shopt -s xpg_echo
shopt -s expand_aliases shopt -s expand_aliases
PROMPT_COMMAND='echo -ne "\033]0;bootstrap\007"'
export PATH=/usr/ucb/bin:/bin:/sbin:/usr/bin:/usr/sbin PROMPT_COMMAND='echo -ne \"\033]0;bootstrap\007\"'
export INSTANCE_NAME='bootstrap' export PATH=/usr/ucb/bin:/bin:/sbin:/usr/bin:/usr/sbin
export INSTANCE_NAME='$INSTANCE_NAME'
export INSTANCE_HOME='$INSTANCE_HOME' export INSTANCE_NAME='bootstrap'
export LOG_DIR='$LOG_DIR' END_OF_JCLOUDS_SCRIPT
END_OF_SCRIPT cat >> $INSTANCE_HOME/bootstrap.sh <<-END_OF_JCLOUDS_SCRIPT
export INSTANCE_NAME='$INSTANCE_NAME'
export INSTANCE_HOME='$INSTANCE_HOME'
export LOG_DIR='$LOG_DIR'
END_OF_JCLOUDS_SCRIPT
cat >> $INSTANCE_HOME/bootstrap.sh <<-'END_OF_JCLOUDS_SCRIPT'
function abort {
echo "aborting: $@" 1>&2
exit 1
}
alias apt-get-install="apt-get install -f -y -qq --force-yes"
alias apt-get-upgrade="(apt-get update -qq&&apt-get upgrade -y -qq)"
function ensure_cmd_or_install_package_apt(){
local cmd=$1
local pkg=$2
hash $cmd 2>/dev/null || apt-get-install $pkg || ( apt-get-upgrade && apt-get-install $pkg )
}
function ensure_cmd_or_install_package_yum(){
local cmd=$1
local pkg=$2
hash $cmd 2>/dev/null || yum --nogpgcheck -y ensure $pkg
}
function ensure_netutils_apt() {
ensure_cmd_or_install_package_apt nslookup dnsutils
ensure_cmd_or_install_package_apt curl curl
}
function ensure_netutils_yum() {
ensure_cmd_or_install_package_yum nslookup bind-utils
ensure_cmd_or_install_package_yum curl curl
}
# most network services require that the hostname is in
# the /etc/hosts file, or they won't operate
function ensure_hostname_in_hosts() {
egrep -q `hostname` /etc/hosts || awk -v hostname=`hostname` 'END { print $1" "hostname }' /proc/net/arp >> /etc/hosts
}
# download locations for many services are at public dns
function ensure_can_resolve_public_dns() {
nslookup yahoo.com > /dev/null || echo nameserver 208.67.222.222 >> /etc/resolv.conf
}
function setupPublicCurl() {
ensure_hostname_in_hosts
if hash apt-get 2>/dev/null; then
ensure_netutils_apt
elif hash yum 2>/dev/null; then
ensure_netutils_yum
else
abort "we only support apt-get and yum right now... please contribute!"
return 1
fi
ensure_can_resolve_public_dns
return 0
}
END_OF_JCLOUDS_SCRIPT
# add desired commands from the user # add desired commands from the user
cat >> $INSTANCE_HOME/bootstrap.sh <<'END_OF_SCRIPT' cat >> $INSTANCE_HOME/bootstrap.sh <<-'END_OF_JCLOUDS_SCRIPT'
cd $INSTANCE_HOME cd $INSTANCE_HOME
rm /etc/sudoers rm -f $INSTANCE_HOME/rc
cat >> /etc/sudoers <<'END_OF_FILE' trap 'echo $?>$INSTANCE_HOME/rc' 0 1 2 3 15
root ALL = (ALL) ALL cat > /etc/sudoers <<-'END_OF_JCLOUDS_FILE'
%wheel ALL = (ALL) NOPASSWD:ALL root ALL = (ALL) ALL
END_OF_FILE %wheel ALL = (ALL) NOPASSWD:ALL
chmod 0440 /etc/sudoers END_OF_JCLOUDS_FILE
mkdir -p /home/users chmod 0440 /etc/sudoers
groupadd -f wheel mkdir -p /home/users
useradd -s /bin/bash -g wheel -m -d /home/users/defaultAdminUsername -p 'crypt(randompassword)' defaultAdminUsername groupadd -f wheel
mkdir -p /home/users/defaultAdminUsername/.ssh useradd -s /bin/bash -g wheel -m -d /home/users/defaultAdminUsername -p 'crypt(randompassword)' defaultAdminUsername
cat >> /home/users/defaultAdminUsername/.ssh/authorized_keys <<'END_OF_FILE' mkdir -p /home/users/defaultAdminUsername/.ssh
publicKey cat >> /home/users/defaultAdminUsername/.ssh/authorized_keys <<-'END_OF_JCLOUDS_FILE'
END_OF_FILE publicKey
chmod 600 /home/users/defaultAdminUsername/.ssh/authorized_keys END_OF_JCLOUDS_FILE
chown -R defaultAdminUsername /home/users/defaultAdminUsername chmod 600 /home/users/defaultAdminUsername/.ssh/authorized_keys
exec 3<> /etc/ssh/sshd_config && awk -v TEXT="PasswordAuthentication no chown -R defaultAdminUsername /home/users/defaultAdminUsername
PermitRootLogin no exec 3<> /etc/ssh/sshd_config && awk -v TEXT="PasswordAuthentication no
" 'BEGIN {print TEXT}{print}' /etc/ssh/sshd_config >&3 PermitRootLogin no
/etc/init.d/sshd reload||/etc/init.d/ssh reload " 'BEGIN {print TEXT}{print}' /etc/ssh/sshd_config >&3
awk -v user=^${SUDO_USER:=${USER}}: -v password='crypt(randompassword)' 'BEGIN { FS=OFS=":" } $0 ~ user { $2 = password } 1' /etc/shadow >/etc/shadow.${SUDO_USER:=${USER}} hash service 2>/dev/null && service ssh reload || /etc/init.d/ssh* reload
test -f /etc/shadow.${SUDO_USER:=${USER}} && mv /etc/shadow.${SUDO_USER:=${USER}} /etc/shadow awk -v user=^${SUDO_USER:=${USER}}: -v password='crypt(randompassword)' 'BEGIN { FS=OFS=":" } $0 ~ user { $2 = password } 1' /etc/shadow >/etc/shadow.${SUDO_USER:=${USER}}
which nslookup >&- 2>&-|| apt-get install -f -y -qq --force-yes dnsutils|| (apt-get update -qq&&apt-get upgrade -y -qq)&&apt-get install -f -y -qq --force-yes dnsutils test -f /etc/shadow.${SUDO_USER:=${USER}} && mv /etc/shadow.${SUDO_USER:=${USER}} /etc/shadow
grep `hostname` /etc/hosts >/dev/null || awk -v hostname=`hostname` 'END { print $1" "hostname }' /proc/net/arp >> /etc/hosts setupPublicCurl || return 1
nslookup yahoo.com >/dev/null || echo nameserver 208.67.222.222 >> /etc/resolv.conf curl -q -s -S -L --connect-timeout 10 --max-time 600 --retry 20 -X GET http://download.oracle.com/otn-pub/java/jdk/7/jdk-7-linux-x64.tar.gz |(mkdir -p /usr/local &&cd /usr/local &&tar -xpzf -)
which curl >&- 2>&-|| apt-get install -f -y -qq --force-yes curl|| (apt-get update -qq&&apt-get upgrade -y -qq)&&apt-get install -f -y -qq --force-yes curl mv /usr/local/jdk* /usr/local/jdk/
mkdir -p /usr/local/jdk test -n "$SUDO_USER" &&
curl -q -s -S -L --connect-timeout 10 --max-time 600 --retry 20 -X GET http://download.oracle.com/otn-pub/java/jdk/7u2-b13/jdk-7u2-linux-x64.tar.gz |(mkdir -p /usr/local &&cd /usr/local &&tar -xpzf -) cat >> /home/$SUDO_USER/.bashrc <<-'END_OF_JCLOUDS_FILE'
mv /usr/local/jdk1.7*/* /usr/local/jdk/ export JAVA_HOME=/usr/local/jdk
test -n "$SUDO_USER" && export PATH=$JAVA_HOME/bin:$PATH
cat >> /home/$SUDO_USER/.bashrc <<'END_OF_FILE' END_OF_JCLOUDS_FILE
export JAVA_HOME=/usr/local/jdk cat >> /etc/bashrc <<-'END_OF_JCLOUDS_FILE'
export PATH=$JAVA_HOME/bin:$PATH export JAVA_HOME=/usr/local/jdk
END_OF_FILE export PATH=$JAVA_HOME/bin:$PATH
cat >> /etc/bashrc <<'END_OF_FILE' END_OF_JCLOUDS_FILE
export JAVA_HOME=/usr/local/jdk cat >> $HOME/.bashrc <<-'END_OF_JCLOUDS_FILE'
export PATH=$JAVA_HOME/bin:$PATH export JAVA_HOME=/usr/local/jdk
END_OF_FILE export PATH=$JAVA_HOME/bin:$PATH
cat >> $HOME/.bashrc <<'END_OF_FILE' END_OF_JCLOUDS_FILE
export JAVA_HOME=/usr/local/jdk cat >> /etc/skel/.bashrc <<-'END_OF_JCLOUDS_FILE'
export PATH=$JAVA_HOME/bin:$PATH export JAVA_HOME=/usr/local/jdk
END_OF_FILE export PATH=$JAVA_HOME/bin:$PATH
cat >> /etc/skel/.bashrc <<'END_OF_FILE' END_OF_JCLOUDS_FILE
export JAVA_HOME=/usr/local/jdk ln -fs /usr/local/jdk/bin/java /usr/bin/java
export PATH=$JAVA_HOME/bin:$PATH
END_OF_FILE
ln -fs /usr/local/jdk/bin/java /usr/bin/java
END_OF_SCRIPT END_OF_JCLOUDS_SCRIPT
# add runscript footer # add runscript footer
cat >> $INSTANCE_HOME/bootstrap.sh <<'END_OF_SCRIPT' cat >> $INSTANCE_HOME/bootstrap.sh <<-'END_OF_JCLOUDS_SCRIPT'
exit 0 exit $?
END_OF_SCRIPT
END_OF_JCLOUDS_SCRIPT
chmod u+x $INSTANCE_HOME/bootstrap.sh chmod u+x $INSTANCE_HOME/bootstrap.sh
;; ;;
@ -151,6 +210,17 @@ start)
default || exit 1 default || exit 1
forget $INSTANCE_NAME $INSTANCE_HOME/$INSTANCE_NAME.sh $LOG_DIR || exit 1 forget $INSTANCE_NAME $INSTANCE_HOME/$INSTANCE_NAME.sh $LOG_DIR || exit 1
;; ;;
stdout)
default || exit 1
cat $LOG_DIR/stdout.log
;;
stderr)
default || exit 1
cat $LOG_DIR/stderr.log
;;
exitstatus)
default || exit 1
[ -f $LOG_DIR/rc ] && cat $LOG_DIR/rc;;
tail) tail)
default || exit 1 default || exit 1
tail $LOG_DIR/stdout.log tail $LOG_DIR/stdout.log
@ -164,4 +234,4 @@ run)
$INSTANCE_HOME/$INSTANCE_NAME.sh $INSTANCE_HOME/$INSTANCE_NAME.sh
;; ;;
esac esac
exit 0 exit $?

View File

@ -10,11 +10,11 @@ function abort {
function default { function default {
export INSTANCE_NAME="configure-jboss" export INSTANCE_NAME="configure-jboss"
export INSTANCE_HOME="/tmp/configure-jboss" export INSTANCE_HOME="/tmp/configure-jboss"
export LOG_DIR="/tmp/configure-jboss" export LOG_DIR="$INSTANCE_HOME"
return 0 return $?
} }
function configure-jboss { function configure-jboss {
return 0 return $?
} }
function findPid { function findPid {
unset FOUND_PID; unset FOUND_PID;
@ -62,84 +62,143 @@ init)
mkdir -p $INSTANCE_HOME mkdir -p $INSTANCE_HOME
# create runscript header # create runscript header
cat > $INSTANCE_HOME/configure-jboss.sh <<END_OF_SCRIPT cat > $INSTANCE_HOME/configure-jboss.sh <<-'END_OF_JCLOUDS_SCRIPT'
#!/bin/bash #!/bin/bash
set +u set +u
shopt -s xpg_echo shopt -s xpg_echo
shopt -s expand_aliases shopt -s expand_aliases
PROMPT_COMMAND='echo -ne "\033]0;configure-jboss\007"'
export PATH=/usr/ucb/bin:/bin:/sbin:/usr/bin:/usr/sbin PROMPT_COMMAND='echo -ne \"\033]0;configure-jboss\007\"'
export INSTANCE_NAME='configure-jboss' export PATH=/usr/ucb/bin:/bin:/sbin:/usr/bin:/usr/sbin
export INSTANCE_NAME='$INSTANCE_NAME'
export INSTANCE_HOME='$INSTANCE_HOME' export INSTANCE_NAME='configure-jboss'
export LOG_DIR='$LOG_DIR' END_OF_JCLOUDS_SCRIPT
END_OF_SCRIPT cat >> $INSTANCE_HOME/configure-jboss.sh <<-END_OF_JCLOUDS_SCRIPT
export INSTANCE_NAME='$INSTANCE_NAME'
export INSTANCE_HOME='$INSTANCE_HOME'
export LOG_DIR='$LOG_DIR'
END_OF_JCLOUDS_SCRIPT
cat >> $INSTANCE_HOME/configure-jboss.sh <<-'END_OF_JCLOUDS_SCRIPT'
function abort {
echo "aborting: $@" 1>&2
exit 1
}
alias apt-get-install="apt-get install -f -y -qq --force-yes"
alias apt-get-upgrade="(apt-get update -qq&&apt-get upgrade -y -qq)"
function ensure_cmd_or_install_package_apt(){
local cmd=$1
local pkg=$2
hash $cmd 2>/dev/null || apt-get-install $pkg || ( apt-get-upgrade && apt-get-install $pkg )
}
function ensure_cmd_or_install_package_yum(){
local cmd=$1
local pkg=$2
hash $cmd 2>/dev/null || yum --nogpgcheck -y ensure $pkg
}
function ensure_netutils_apt() {
ensure_cmd_or_install_package_apt nslookup dnsutils
ensure_cmd_or_install_package_apt curl curl
}
function ensure_netutils_yum() {
ensure_cmd_or_install_package_yum nslookup bind-utils
ensure_cmd_or_install_package_yum curl curl
}
# most network services require that the hostname is in
# the /etc/hosts file, or they won't operate
function ensure_hostname_in_hosts() {
egrep -q `hostname` /etc/hosts || awk -v hostname=`hostname` 'END { print $1" "hostname }' /proc/net/arp >> /etc/hosts
}
# download locations for many services are at public dns
function ensure_can_resolve_public_dns() {
nslookup yahoo.com > /dev/null || echo nameserver 208.67.222.222 >> /etc/resolv.conf
}
function setupPublicCurl() {
ensure_hostname_in_hosts
if hash apt-get 2>/dev/null; then
ensure_netutils_apt
elif hash yum 2>/dev/null; then
ensure_netutils_yum
else
abort "we only support apt-get and yum right now... please contribute!"
return 1
fi
ensure_can_resolve_public_dns
return 0
}
END_OF_JCLOUDS_SCRIPT
# add desired commands from the user # add desired commands from the user
cat >> $INSTANCE_HOME/configure-jboss.sh <<'END_OF_SCRIPT' cat >> $INSTANCE_HOME/configure-jboss.sh <<-'END_OF_JCLOUDS_SCRIPT'
cd $INSTANCE_HOME cd $INSTANCE_HOME
rm /etc/sudoers rm -f $INSTANCE_HOME/rc
cat >> /etc/sudoers <<'END_OF_FILE' trap 'echo $?>$INSTANCE_HOME/rc' 0 1 2 3 15
root ALL = (ALL) ALL cat > /etc/sudoers <<-'END_OF_JCLOUDS_FILE'
%wheel ALL = (ALL) NOPASSWD:ALL root ALL = (ALL) ALL
END_OF_FILE %wheel ALL = (ALL) NOPASSWD:ALL
chmod 0440 /etc/sudoers END_OF_JCLOUDS_FILE
mkdir -p /home/users chmod 0440 /etc/sudoers
groupadd -f wheel mkdir -p /home/users
useradd -s /bin/bash -g wheel -m -d /home/users/web -p 'crypt(randompassword)' web groupadd -f wheel
mkdir -p /home/users/web/.ssh useradd -s /bin/bash -g wheel -m -d /home/users/web -p 'crypt(randompassword)' web
cat >> /home/users/web/.ssh/authorized_keys <<'END_OF_FILE' mkdir -p /home/users/web/.ssh
publicKey cat >> /home/users/web/.ssh/authorized_keys <<-'END_OF_JCLOUDS_FILE'
END_OF_FILE publicKey
chmod 600 /home/users/web/.ssh/authorized_keys END_OF_JCLOUDS_FILE
chown -R web /home/users/web chmod 600 /home/users/web/.ssh/authorized_keys
exec 3<> /etc/ssh/sshd_config && awk -v TEXT="PasswordAuthentication no chown -R web /home/users/web
PermitRootLogin no exec 3<> /etc/ssh/sshd_config && awk -v TEXT="PasswordAuthentication no
" 'BEGIN {print TEXT}{print}' /etc/ssh/sshd_config >&3 PermitRootLogin no
/etc/init.d/sshd reload||/etc/init.d/ssh reload " 'BEGIN {print TEXT}{print}' /etc/ssh/sshd_config >&3
awk -v user=^${SUDO_USER:=${USER}}: -v password='crypt(randompassword)' 'BEGIN { FS=OFS=":" } $0 ~ user { $2 = password } 1' /etc/shadow >/etc/shadow.${SUDO_USER:=${USER}} hash service 2>/dev/null && service ssh reload || /etc/init.d/ssh* reload
test -f /etc/shadow.${SUDO_USER:=${USER}} && mv /etc/shadow.${SUDO_USER:=${USER}} /etc/shadow awk -v user=^${SUDO_USER:=${USER}}: -v password='crypt(randompassword)' 'BEGIN { FS=OFS=":" } $0 ~ user { $2 = password } 1' /etc/shadow >/etc/shadow.${SUDO_USER:=${USER}}
which nslookup >&- 2>&-|| apt-get install -f -y -qq --force-yes dnsutils|| (apt-get update -qq&&apt-get upgrade -y -qq)&&apt-get install -f -y -qq --force-yes dnsutils test -f /etc/shadow.${SUDO_USER:=${USER}} && mv /etc/shadow.${SUDO_USER:=${USER}} /etc/shadow
grep `hostname` /etc/hosts >/dev/null || awk -v hostname=`hostname` 'END { print $1" "hostname }' /proc/net/arp >> /etc/hosts setupPublicCurl || return 1
nslookup yahoo.com >/dev/null || echo nameserver 208.67.222.222 >> /etc/resolv.conf curl -q -s -S -L --connect-timeout 10 --max-time 600 --retry 20 -X GET http://download.oracle.com/otn-pub/java/jdk/7/jdk-7-linux-x64.tar.gz |(mkdir -p /usr/local &&cd /usr/local &&tar -xpzf -)
which curl >&- 2>&-|| apt-get install -f -y -qq --force-yes curl|| (apt-get update -qq&&apt-get upgrade -y -qq)&&apt-get install -f -y -qq --force-yes curl mv /usr/local/jdk* /usr/local/jdk/
mkdir -p /usr/local/jdk test -n "$SUDO_USER" &&
curl -q -s -S -L --connect-timeout 10 --max-time 600 --retry 20 -X GET http://download.oracle.com/otn-pub/java/jdk/7u2-b13/jdk-7u2-linux-x64.tar.gz |(mkdir -p /usr/local &&cd /usr/local &&tar -xpzf -) cat >> /home/$SUDO_USER/.bashrc <<-'END_OF_JCLOUDS_FILE'
mv /usr/local/jdk1.7*/* /usr/local/jdk/ export JAVA_HOME=/usr/local/jdk
test -n "$SUDO_USER" && export PATH=$JAVA_HOME/bin:$PATH
cat >> /home/$SUDO_USER/.bashrc <<'END_OF_FILE' END_OF_JCLOUDS_FILE
export JAVA_HOME=/usr/local/jdk cat >> /etc/bashrc <<-'END_OF_JCLOUDS_FILE'
export PATH=$JAVA_HOME/bin:$PATH export JAVA_HOME=/usr/local/jdk
END_OF_FILE export PATH=$JAVA_HOME/bin:$PATH
cat >> /etc/bashrc <<'END_OF_FILE' END_OF_JCLOUDS_FILE
export JAVA_HOME=/usr/local/jdk cat >> $HOME/.bashrc <<-'END_OF_JCLOUDS_FILE'
export PATH=$JAVA_HOME/bin:$PATH export JAVA_HOME=/usr/local/jdk
END_OF_FILE export PATH=$JAVA_HOME/bin:$PATH
cat >> $HOME/.bashrc <<'END_OF_FILE' END_OF_JCLOUDS_FILE
export JAVA_HOME=/usr/local/jdk cat >> /etc/skel/.bashrc <<-'END_OF_JCLOUDS_FILE'
export PATH=$JAVA_HOME/bin:$PATH export JAVA_HOME=/usr/local/jdk
END_OF_FILE export PATH=$JAVA_HOME/bin:$PATH
cat >> /etc/skel/.bashrc <<'END_OF_FILE' END_OF_JCLOUDS_FILE
export JAVA_HOME=/usr/local/jdk ln -fs /usr/local/jdk/bin/java /usr/bin/java
export PATH=$JAVA_HOME/bin:$PATH iptables -I INPUT 1 -p tcp --dport 22 -j ACCEPT
END_OF_FILE iptables -I INPUT 1 -p tcp --dport 8080 -j ACCEPT
ln -fs /usr/local/jdk/bin/java /usr/bin/java iptables-save
iptables -I INPUT 1 -p tcp --dport 22 -j ACCEPT curl -q -s -S -L --connect-timeout 10 --max-time 600 --retry 20 -X GET http://download.jboss.org/jbossas/7.0/jboss-as-7.0.2.Final/jboss-as-web-7.0.2.Final.tar.gz |(mkdir -p /usr/local &&cd /usr/local &&tar -xpzf -)
iptables -I INPUT 1 -p tcp --dport 8080 -j ACCEPT mkdir -p /usr/local/jboss
iptables-save mv /usr/local/jboss-*/* /usr/local/jboss
curl -q -s -S -L --connect-timeout 10 --max-time 600 --retry 20 -X GET http://download.jboss.org/jbossas/7.0/jboss-as-7.0.2.Final/jboss-as-web-7.0.2.Final.tar.gz |(mkdir -p /usr/local &&cd /usr/local &&tar -xpzf -) (cd /usr/local/jboss/standalone/configuration && sed 's~inet-address value=.*/~any-address/~g' standalone.xml > standalone.xml.new && mv standalone.xml.new standalone.xml)
mkdir -p /usr/local/jboss chmod -R oug+r+w /usr/local/jboss
mv /usr/local/jboss-*/* /usr/local/jboss chown -R web /usr/local/jboss
(cd /usr/local/jboss/standalone/configuration && sed 's~inet-address value=.*/~any-address/~g' standalone.xml > standalone.xml.new && mv standalone.xml.new standalone.xml)
chmod -R oug+r+w /usr/local/jboss
chown -R web /usr/local/jboss
END_OF_SCRIPT END_OF_JCLOUDS_SCRIPT
# add runscript footer # add runscript footer
cat >> $INSTANCE_HOME/configure-jboss.sh <<'END_OF_SCRIPT' cat >> $INSTANCE_HOME/configure-jboss.sh <<-'END_OF_JCLOUDS_SCRIPT'
exit 0 exit $?
END_OF_SCRIPT
END_OF_JCLOUDS_SCRIPT
chmod u+x $INSTANCE_HOME/configure-jboss.sh chmod u+x $INSTANCE_HOME/configure-jboss.sh
;; ;;
@ -160,6 +219,17 @@ start)
default || exit 1 default || exit 1
forget $INSTANCE_NAME $INSTANCE_HOME/$INSTANCE_NAME.sh $LOG_DIR || exit 1 forget $INSTANCE_NAME $INSTANCE_HOME/$INSTANCE_NAME.sh $LOG_DIR || exit 1
;; ;;
stdout)
default || exit 1
cat $LOG_DIR/stdout.log
;;
stderr)
default || exit 1
cat $LOG_DIR/stderr.log
;;
exitstatus)
default || exit 1
[ -f $LOG_DIR/rc ] && cat $LOG_DIR/rc;;
tail) tail)
default || exit 1 default || exit 1
tail $LOG_DIR/stdout.log tail $LOG_DIR/stdout.log
@ -173,4 +243,4 @@ run)
$INSTANCE_HOME/$INSTANCE_NAME.sh $INSTANCE_HOME/$INSTANCE_NAME.sh
;; ;;
esac esac
exit 0 exit $?

View File

@ -10,11 +10,11 @@ function abort {
function default { function default {
export INSTANCE_NAME="runScriptWithCreds" export INSTANCE_NAME="runScriptWithCreds"
export INSTANCE_HOME="/tmp/runScriptWithCreds" export INSTANCE_HOME="/tmp/runScriptWithCreds"
export LOG_DIR="/tmp/runScriptWithCreds" export LOG_DIR="$INSTANCE_HOME"
return 0 return $?
} }
function runScriptWithCreds { function runScriptWithCreds {
return 0 return $?
} }
function findPid { function findPid {
unset FOUND_PID; unset FOUND_PID;
@ -62,54 +62,114 @@ init)
mkdir -p $INSTANCE_HOME mkdir -p $INSTANCE_HOME
# create runscript header # create runscript header
cat > $INSTANCE_HOME/runScriptWithCreds.sh <<END_OF_SCRIPT cat > $INSTANCE_HOME/runScriptWithCreds.sh <<-'END_OF_JCLOUDS_SCRIPT'
#!/bin/bash #!/bin/bash
set +u set +u
shopt -s xpg_echo shopt -s xpg_echo
shopt -s expand_aliases shopt -s expand_aliases
PROMPT_COMMAND='echo -ne "\033]0;runScriptWithCreds\007"'
export PATH=/usr/ucb/bin:/bin:/sbin:/usr/bin:/usr/sbin PROMPT_COMMAND='echo -ne \"\033]0;runScriptWithCreds\007\"'
export INSTANCE_NAME='runScriptWithCreds' export PATH=/usr/ucb/bin:/bin:/sbin:/usr/bin:/usr/sbin
export INSTANCE_NAME='$INSTANCE_NAME'
export INSTANCE_HOME='$INSTANCE_HOME' export INSTANCE_NAME='runScriptWithCreds'
export LOG_DIR='$LOG_DIR' END_OF_JCLOUDS_SCRIPT
END_OF_SCRIPT cat >> $INSTANCE_HOME/runScriptWithCreds.sh <<-END_OF_JCLOUDS_SCRIPT
export INSTANCE_NAME='$INSTANCE_NAME'
export INSTANCE_HOME='$INSTANCE_HOME'
export LOG_DIR='$LOG_DIR'
END_OF_JCLOUDS_SCRIPT
cat >> $INSTANCE_HOME/runScriptWithCreds.sh <<-'END_OF_JCLOUDS_SCRIPT'
function abort {
echo "aborting: $@" 1>&2
exit 1
}
alias apt-get-install="apt-get install -f -y -qq --force-yes"
alias apt-get-upgrade="(apt-get update -qq&&apt-get upgrade -y -qq)"
function ensure_cmd_or_install_package_apt(){
local cmd=$1
local pkg=$2
hash $cmd 2>/dev/null || apt-get-install $pkg || ( apt-get-upgrade && apt-get-install $pkg )
}
function ensure_cmd_or_install_package_yum(){
local cmd=$1
local pkg=$2
hash $cmd 2>/dev/null || yum --nogpgcheck -y ensure $pkg
}
function ensure_netutils_apt() {
ensure_cmd_or_install_package_apt nslookup dnsutils
ensure_cmd_or_install_package_apt curl curl
}
function ensure_netutils_yum() {
ensure_cmd_or_install_package_yum nslookup bind-utils
ensure_cmd_or_install_package_yum curl curl
}
# most network services require that the hostname is in
# the /etc/hosts file, or they won't operate
function ensure_hostname_in_hosts() {
egrep -q `hostname` /etc/hosts || awk -v hostname=`hostname` 'END { print $1" "hostname }' /proc/net/arp >> /etc/hosts
}
# download locations for many services are at public dns
function ensure_can_resolve_public_dns() {
nslookup yahoo.com > /dev/null || echo nameserver 208.67.222.222 >> /etc/resolv.conf
}
function setupPublicCurl() {
ensure_hostname_in_hosts
if hash apt-get 2>/dev/null; then
ensure_netutils_apt
elif hash yum 2>/dev/null; then
ensure_netutils_yum
else
abort "we only support apt-get and yum right now... please contribute!"
return 1
fi
ensure_can_resolve_public_dns
return 0
}
END_OF_JCLOUDS_SCRIPT
# add desired commands from the user # add desired commands from the user
cat >> $INSTANCE_HOME/runScriptWithCreds.sh <<'END_OF_SCRIPT' cat >> $INSTANCE_HOME/runScriptWithCreds.sh <<-'END_OF_JCLOUDS_SCRIPT'
cd $INSTANCE_HOME cd $INSTANCE_HOME
which nslookup >&- 2>&-|| apt-get install -f -y -qq --force-yes dnsutils|| (apt-get update -qq&&apt-get upgrade -y -qq)&&apt-get install -f -y -qq --force-yes dnsutils rm -f $INSTANCE_HOME/rc
grep `hostname` /etc/hosts >/dev/null || awk -v hostname=`hostname` 'END { print $1" "hostname }' /proc/net/arp >> /etc/hosts trap 'echo $?>$INSTANCE_HOME/rc' 0 1 2 3 15
nslookup yahoo.com >/dev/null || echo nameserver 208.67.222.222 >> /etc/resolv.conf setupPublicCurl || exit 1
which curl >&- 2>&-|| apt-get install -f -y -qq --force-yes curl|| (apt-get update -qq&&apt-get upgrade -y -qq)&&apt-get install -f -y -qq --force-yes curl curl -q -s -S -L --connect-timeout 10 --max-time 600 --retry 20 -X GET http://download.oracle.com/otn-pub/java/jdk/7/jdk-7-linux-x64.tar.gz |(mkdir -p /usr/local &&cd /usr/local &&tar -xpzf -)
mkdir -p /usr/local/jdk mv /usr/local/jdk* /usr/local/jdk/
curl -q -s -S -L --connect-timeout 10 --max-time 600 --retry 20 -X GET http://download.oracle.com/otn-pub/java/jdk/7u2-b13/jdk-7u2-linux-x64.tar.gz |(mkdir -p /usr/local &&cd /usr/local &&tar -xpzf -) test -n "$SUDO_USER" &&
mv /usr/local/jdk1.7*/* /usr/local/jdk/ cat >> /home/$SUDO_USER/.bashrc <<-'END_OF_JCLOUDS_FILE'
test -n "$SUDO_USER" && export JAVA_HOME=/usr/local/jdk
cat >> /home/$SUDO_USER/.bashrc <<'END_OF_FILE' export PATH=$JAVA_HOME/bin:$PATH
export JAVA_HOME=/usr/local/jdk END_OF_JCLOUDS_FILE
export PATH=$JAVA_HOME/bin:$PATH cat >> /etc/bashrc <<-'END_OF_JCLOUDS_FILE'
END_OF_FILE export JAVA_HOME=/usr/local/jdk
cat >> /etc/bashrc <<'END_OF_FILE' export PATH=$JAVA_HOME/bin:$PATH
export JAVA_HOME=/usr/local/jdk END_OF_JCLOUDS_FILE
export PATH=$JAVA_HOME/bin:$PATH cat >> $HOME/.bashrc <<-'END_OF_JCLOUDS_FILE'
END_OF_FILE export JAVA_HOME=/usr/local/jdk
cat >> $HOME/.bashrc <<'END_OF_FILE' export PATH=$JAVA_HOME/bin:$PATH
export JAVA_HOME=/usr/local/jdk END_OF_JCLOUDS_FILE
export PATH=$JAVA_HOME/bin:$PATH cat >> /etc/skel/.bashrc <<-'END_OF_JCLOUDS_FILE'
END_OF_FILE export JAVA_HOME=/usr/local/jdk
cat >> /etc/skel/.bashrc <<'END_OF_FILE' export PATH=$JAVA_HOME/bin:$PATH
export JAVA_HOME=/usr/local/jdk END_OF_JCLOUDS_FILE
export PATH=$JAVA_HOME/bin:$PATH ln -fs /usr/local/jdk/bin/java /usr/bin/java
END_OF_FILE
ln -fs /usr/local/jdk/bin/java /usr/bin/java
END_OF_SCRIPT END_OF_JCLOUDS_SCRIPT
# add runscript footer # add runscript footer
cat >> $INSTANCE_HOME/runScriptWithCreds.sh <<'END_OF_SCRIPT' cat >> $INSTANCE_HOME/runScriptWithCreds.sh <<-'END_OF_JCLOUDS_SCRIPT'
exit 0 exit $?
END_OF_SCRIPT
END_OF_JCLOUDS_SCRIPT
chmod u+x $INSTANCE_HOME/runScriptWithCreds.sh chmod u+x $INSTANCE_HOME/runScriptWithCreds.sh
;; ;;
@ -130,6 +190,17 @@ start)
default || exit 1 default || exit 1
forget $INSTANCE_NAME $INSTANCE_HOME/$INSTANCE_NAME.sh $LOG_DIR || exit 1 forget $INSTANCE_NAME $INSTANCE_HOME/$INSTANCE_NAME.sh $LOG_DIR || exit 1
;; ;;
stdout)
default || exit 1
cat $LOG_DIR/stdout.log
;;
stderr)
default || exit 1
cat $LOG_DIR/stderr.log
;;
exitstatus)
default || exit 1
[ -f $LOG_DIR/rc ] && cat $LOG_DIR/rc;;
tail) tail)
default || exit 1 default || exit 1
tail $LOG_DIR/stdout.log tail $LOG_DIR/stdout.log
@ -143,4 +214,4 @@ run)
$INSTANCE_HOME/$INSTANCE_NAME.sh $INSTANCE_HOME/$INSTANCE_NAME.sh
;; ;;
esac esac
exit 0 exit $?

View File

@ -10,11 +10,11 @@ function abort {
function default { function default {
export INSTANCE_NAME="adminUpdate" export INSTANCE_NAME="adminUpdate"
export INSTANCE_HOME="/tmp/adminUpdate" export INSTANCE_HOME="/tmp/adminUpdate"
export LOG_DIR="/tmp/adminUpdate" export LOG_DIR="$INSTANCE_HOME"
return 0 return $?
} }
function adminUpdate { function adminUpdate {
return 0 return $?
} }
function findPid { function findPid {
unset FOUND_PID; unset FOUND_PID;
@ -62,50 +62,56 @@ init)
mkdir -p $INSTANCE_HOME mkdir -p $INSTANCE_HOME
# create runscript header # create runscript header
cat > $INSTANCE_HOME/adminUpdate.sh <<END_OF_SCRIPT cat > $INSTANCE_HOME/adminUpdate.sh <<-'END_OF_JCLOUDS_SCRIPT'
#!/bin/bash #!/bin/bash
set +u set +u
shopt -s xpg_echo shopt -s xpg_echo
shopt -s expand_aliases shopt -s expand_aliases
PROMPT_COMMAND='echo -ne "\033]0;adminUpdate\007"'
export PATH=/usr/ucb/bin:/bin:/sbin:/usr/bin:/usr/sbin PROMPT_COMMAND='echo -ne \"\033]0;adminUpdate\007\"'
export INSTANCE_NAME='adminUpdate' export PATH=/usr/ucb/bin:/bin:/sbin:/usr/bin:/usr/sbin
export INSTANCE_NAME='$INSTANCE_NAME'
export INSTANCE_HOME='$INSTANCE_HOME' export INSTANCE_NAME='adminUpdate'
export LOG_DIR='$LOG_DIR' END_OF_JCLOUDS_SCRIPT
END_OF_SCRIPT cat >> $INSTANCE_HOME/adminUpdate.sh <<-END_OF_JCLOUDS_SCRIPT
export INSTANCE_NAME='$INSTANCE_NAME'
export INSTANCE_HOME='$INSTANCE_HOME'
export LOG_DIR='$LOG_DIR'
END_OF_JCLOUDS_SCRIPT
# add desired commands from the user # add desired commands from the user
cat >> $INSTANCE_HOME/adminUpdate.sh <<'END_OF_SCRIPT' cat >> $INSTANCE_HOME/adminUpdate.sh <<-'END_OF_JCLOUDS_SCRIPT'
cd $INSTANCE_HOME cd $INSTANCE_HOME
rm /etc/sudoers rm -f $INSTANCE_HOME/rc
cat >> /etc/sudoers <<'END_OF_FILE' trap 'echo $?>$INSTANCE_HOME/rc' 0 1 2 3 15
root ALL = (ALL) ALL cat > /etc/sudoers <<-'END_OF_JCLOUDS_FILE'
%wheel ALL = (ALL) NOPASSWD:ALL root ALL = (ALL) ALL
END_OF_FILE %wheel ALL = (ALL) NOPASSWD:ALL
chmod 0440 /etc/sudoers END_OF_JCLOUDS_FILE
mkdir -p /home/users chmod 0440 /etc/sudoers
groupadd -f wheel mkdir -p /home/users
useradd -s /bin/bash -g wheel -m -d /home/users/foo -p 'crypt(randompassword)' foo groupadd -f wheel
mkdir -p /home/users/foo/.ssh useradd -s /bin/bash -g wheel -m -d /home/users/foo -p 'crypt(randompassword)' foo
cat >> /home/users/foo/.ssh/authorized_keys <<'END_OF_FILE' mkdir -p /home/users/foo/.ssh
publicKey cat >> /home/users/foo/.ssh/authorized_keys <<-'END_OF_JCLOUDS_FILE'
END_OF_FILE publicKey
chmod 600 /home/users/foo/.ssh/authorized_keys END_OF_JCLOUDS_FILE
chown -R foo /home/users/foo chmod 600 /home/users/foo/.ssh/authorized_keys
exec 3<> /etc/ssh/sshd_config && awk -v TEXT="PasswordAuthentication no chown -R foo /home/users/foo
PermitRootLogin no exec 3<> /etc/ssh/sshd_config && awk -v TEXT="PasswordAuthentication no
" 'BEGIN {print TEXT}{print}' /etc/ssh/sshd_config >&3 PermitRootLogin no
/etc/init.d/sshd reload||/etc/init.d/ssh reload " 'BEGIN {print TEXT}{print}' /etc/ssh/sshd_config >&3
awk -v user=^${SUDO_USER:=${USER}}: -v password='crypt(randompassword)' 'BEGIN { FS=OFS=":" } $0 ~ user { $2 = password } 1' /etc/shadow >/etc/shadow.${SUDO_USER:=${USER}} hash service 2>/dev/null && service ssh reload || /etc/init.d/ssh* reload
test -f /etc/shadow.${SUDO_USER:=${USER}} && mv /etc/shadow.${SUDO_USER:=${USER}} /etc/shadow awk -v user=^${SUDO_USER:=${USER}}: -v password='crypt(randompassword)' 'BEGIN { FS=OFS=":" } $0 ~ user { $2 = password } 1' /etc/shadow >/etc/shadow.${SUDO_USER:=${USER}}
test -f /etc/shadow.${SUDO_USER:=${USER}} && mv /etc/shadow.${SUDO_USER:=${USER}} /etc/shadow
END_OF_SCRIPT END_OF_JCLOUDS_SCRIPT
# add runscript footer # add runscript footer
cat >> $INSTANCE_HOME/adminUpdate.sh <<'END_OF_SCRIPT' cat >> $INSTANCE_HOME/adminUpdate.sh <<-'END_OF_JCLOUDS_SCRIPT'
exit 0 exit $?
END_OF_SCRIPT
END_OF_JCLOUDS_SCRIPT
chmod u+x $INSTANCE_HOME/adminUpdate.sh chmod u+x $INSTANCE_HOME/adminUpdate.sh
;; ;;
@ -126,6 +132,17 @@ start)
default || exit 1 default || exit 1
forget $INSTANCE_NAME $INSTANCE_HOME/$INSTANCE_NAME.sh $LOG_DIR || exit 1 forget $INSTANCE_NAME $INSTANCE_HOME/$INSTANCE_NAME.sh $LOG_DIR || exit 1
;; ;;
stdout)
default || exit 1
cat $LOG_DIR/stdout.log
;;
stderr)
default || exit 1
cat $LOG_DIR/stderr.log
;;
exitstatus)
default || exit 1
[ -f $LOG_DIR/rc ] && cat $LOG_DIR/rc;;
tail) tail)
default || exit 1 default || exit 1
tail $LOG_DIR/stdout.log tail $LOG_DIR/stdout.log
@ -139,4 +156,4 @@ run)
$INSTANCE_HOME/$INSTANCE_NAME.sh $INSTANCE_HOME/$INSTANCE_NAME.sh
;; ;;
esac esac
exit 0 exit $?

View File

@ -10,12 +10,12 @@ function abort {
function default { function default {
export INSTANCE_NAME="jboss" export INSTANCE_NAME="jboss"
export INSTANCE_HOME="/usr/local/jboss" export INSTANCE_HOME="/usr/local/jboss"
export LOG_DIR="/usr/local/jboss" export LOG_DIR="$INSTANCE_HOME"
return 0 return $?
} }
function jboss { function jboss {
export JBOSS_HOME="/usr/local/jboss" export JBOSS_HOME="/usr/local/jboss"
return 0 return $?
} }
function findPid { function findPid {
unset FOUND_PID; unset FOUND_PID;
@ -60,10 +60,10 @@ case $1 in
init) init)
default || exit 1 default || exit 1
jboss || exit 1 jboss || exit 1
cat >> /usr/local/jboss/standalone/configuration/standalone-custom.xml <<'END_OF_FILE' cat >> /usr/local/jboss/standalone/configuration/standalone-custom.xml <<-'END_OF_JCLOUDS_FILE'
<?xml version='1.0' encoding='UTF-8'?> <?xml version='1.0' encoding='UTF-8'?>
<server name="basic" xmlns="urn:jboss:domain:1.0"> <server name="basic" xmlns="urn:jboss:domain:1.0">
<extensions> <extensions>
<extension module="org.jboss.as.connector"/> <extension module="org.jboss.as.connector"/>
<extension module="org.jboss.as.deployment-scanner"/> <extension module="org.jboss.as.deployment-scanner"/>
@ -163,36 +163,43 @@ init)
<socket-binding name="txn-recovery-environment" port="4712"/> <socket-binding name="txn-recovery-environment" port="4712"/>
<socket-binding name="txn-status-manager" port="4713"/> <socket-binding name="txn-status-manager" port="4713"/>
</socket-binding-group> </socket-binding-group>
</server> </server>
END_OF_FILE END_OF_JCLOUDS_FILE
mkdir -p $INSTANCE_HOME mkdir -p $INSTANCE_HOME
# create runscript header # create runscript header
cat > $INSTANCE_HOME/jboss.sh <<END_OF_SCRIPT cat > $INSTANCE_HOME/jboss.sh <<-'END_OF_JCLOUDS_SCRIPT'
#!/bin/bash #!/bin/bash
set +u set +u
shopt -s xpg_echo shopt -s xpg_echo
shopt -s expand_aliases shopt -s expand_aliases
PROMPT_COMMAND='echo -ne "\033]0;jboss\007"'
export PATH=/usr/ucb/bin:/bin:/sbin:/usr/bin:/usr/sbin PROMPT_COMMAND='echo -ne \"\033]0;jboss\007\"'
export INSTANCE_NAME='jboss' export PATH=/usr/ucb/bin:/bin:/sbin:/usr/bin:/usr/sbin
export JBOSS_HOME='$JBOSS_HOME'
export INSTANCE_NAME='$INSTANCE_NAME' export INSTANCE_NAME='jboss'
export INSTANCE_HOME='$INSTANCE_HOME' END_OF_JCLOUDS_SCRIPT
export LOG_DIR='$LOG_DIR' cat >> $INSTANCE_HOME/jboss.sh <<-END_OF_JCLOUDS_SCRIPT
END_OF_SCRIPT export JBOSS_HOME='$JBOSS_HOME'
export INSTANCE_NAME='$INSTANCE_NAME'
export INSTANCE_HOME='$INSTANCE_HOME'
export LOG_DIR='$LOG_DIR'
END_OF_JCLOUDS_SCRIPT
# add desired commands from the user # add desired commands from the user
cat >> $INSTANCE_HOME/jboss.sh <<'END_OF_SCRIPT' cat >> $INSTANCE_HOME/jboss.sh <<-'END_OF_JCLOUDS_SCRIPT'
cd $INSTANCE_HOME cd $INSTANCE_HOME
java -server -Xms128m -Xmx128m -XX:MaxPermSize=128m -Djava.net.preferIPv4Stack=true -XX:+UseFastAccessorMethods -XX:+TieredCompilation -Xverify:none -Dorg.jboss.resolver.warning=true -Dsun.rmi.dgc.client.gcInterval=3600000 -Dsun.rmi.dgc.server.gcInterval=3600000 -Djboss.modules.system.pkgs=org.jboss.byteman -Dorg.jboss.boot.log.file=$JBOSS_HOME/standalone/log/boot.log -Dlogging.configuration=file:$JBOSS_HOME/standalone/configuration/logging.properties -jar $JBOSS_HOME/jboss-modules.jar -mp $JBOSS_HOME/modules -logmodule org.jboss.logmanager -jaxpmodule javax.xml.jaxp-provider org.jboss.as.standalone -Djboss.home.dir=$JBOSS_HOME --server-config=standalone-custom.xml rm -f $INSTANCE_HOME/rc
END_OF_SCRIPT trap 'echo $?>$INSTANCE_HOME/rc' 0 1 2 3 15
java -server -Xms128m -Xmx128m -XX:MaxPermSize=128m -Djava.net.preferIPv4Stack=true -XX:+UseFastAccessorMethods -XX:+TieredCompilation -Xverify:none -Dorg.jboss.resolver.warning=true -Dsun.rmi.dgc.client.gcInterval=3600000 -Dsun.rmi.dgc.server.gcInterval=3600000 -Djboss.modules.system.pkgs=org.jboss.byteman -Dorg.jboss.boot.log.file=$JBOSS_HOME/standalone/log/boot.log -Dlogging.configuration=file:$JBOSS_HOME/standalone/configuration/logging.properties -jar $JBOSS_HOME/jboss-modules.jar -mp $JBOSS_HOME/modules -logmodule org.jboss.logmanager -jaxpmodule javax.xml.jaxp-provider org.jboss.as.standalone -Djboss.home.dir=$JBOSS_HOME --server-config=standalone-custom.xml
END_OF_JCLOUDS_SCRIPT
# add runscript footer # add runscript footer
cat >> $INSTANCE_HOME/jboss.sh <<'END_OF_SCRIPT' cat >> $INSTANCE_HOME/jboss.sh <<-'END_OF_JCLOUDS_SCRIPT'
exit 0 exit $?
END_OF_SCRIPT
END_OF_JCLOUDS_SCRIPT
chmod u+x $INSTANCE_HOME/jboss.sh chmod u+x $INSTANCE_HOME/jboss.sh
;; ;;
@ -213,6 +220,17 @@ start)
default || exit 1 default || exit 1
forget $INSTANCE_NAME $INSTANCE_HOME/$INSTANCE_NAME.sh $LOG_DIR || exit 1 forget $INSTANCE_NAME $INSTANCE_HOME/$INSTANCE_NAME.sh $LOG_DIR || exit 1
;; ;;
stdout)
default || exit 1
cat $LOG_DIR/stdout.log
;;
stderr)
default || exit 1
cat $LOG_DIR/stderr.log
;;
exitstatus)
default || exit 1
[ -f $LOG_DIR/rc ] && cat $LOG_DIR/rc;;
tail) tail)
default || exit 1 default || exit 1
tail $LOG_DIR/stdout.log tail $LOG_DIR/stdout.log
@ -226,4 +244,4 @@ run)
$INSTANCE_HOME/$INSTANCE_NAME.sh $INSTANCE_HOME/$INSTANCE_NAME.sh
;; ;;
esac esac
exit 0 exit $?

View File

@ -132,7 +132,7 @@
<configuration> <configuration>
<instructions> <instructions>
<Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName> <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
<Export-Package>org.jclouds.*;version=${project.version}</Export-Package> <Export-Package>org.jclouds*;version=${project.version}</Export-Package>
<DynamicImport-Package>org.jclouds.*</DynamicImport-Package> <DynamicImport-Package>org.jclouds.*</DynamicImport-Package>
</instructions> </instructions>
</configuration> </configuration>

View File

@ -45,6 +45,8 @@ import org.jclouds.lifecycle.Closer;
import org.jclouds.logging.Logger; import org.jclouds.logging.Logger;
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
import com.google.common.eventbus.AsyncEventBus;
import com.google.common.eventbus.EventBus;
import com.google.common.util.concurrent.ThreadFactoryBuilder; import com.google.common.util.concurrent.ThreadFactoryBuilder;
import com.google.inject.AbstractModule; import com.google.inject.AbstractModule;
import com.google.inject.Provides; import com.google.inject.Provides;
@ -321,6 +323,12 @@ public class ExecutorServiceModule extends AbstractModule {
} }
@Provides
@Singleton
EventBus provideEventBus(@Named(Constants.PROPERTY_USER_THREADS) ExecutorService userThreads){
return new AsyncEventBus(userThreads);
}
@Provides @Provides
@Singleton @Singleton
@Named(Constants.PROPERTY_USER_THREADS) @Named(Constants.PROPERTY_USER_THREADS)

View File

@ -21,6 +21,7 @@ package org.jclouds.predicates;
import static org.jclouds.util.Throwables2.getFirstThrowableOfType; import static org.jclouds.util.Throwables2.getFirstThrowableOfType;
import java.util.Date; import java.util.Date;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeoutException;
@ -88,6 +89,9 @@ public class RetryablePredicate<T> implements Predicate<T> {
} else if (getFirstThrowableOfType(e, IllegalStateException.class) != null) { } else if (getFirstThrowableOfType(e, IllegalStateException.class) != null) {
logger.warn(e, "predicate %s on %s illegal state [%s], returning false", input, predicate, e.getMessage()); logger.warn(e, "predicate %s on %s illegal state [%s], returning false", input, predicate, e.getMessage());
return false; return false;
} else if (getFirstThrowableOfType(e, CancellationException.class) != null) {
logger.warn(e, "predicate %s on %s cancelled [%s], returning false", input, predicate, e.getMessage());
return false;
} else if (getFirstThrowableOfType(e, TimeoutException.class) != null) { } else if (getFirstThrowableOfType(e, TimeoutException.class) != null) {
logger.warn(e, "predicate %s on %s timed out [%s], returning false", input, predicate, e.getMessage()); logger.warn(e, "predicate %s on %s timed out [%s], returning false", input, predicate, e.getMessage());
return false; return false;

View File

@ -21,6 +21,7 @@ package org.jclouds.rest;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import com.google.common.annotations.Beta; import com.google.common.annotations.Beta;
import com.google.common.eventbus.EventBus;
import com.google.inject.Injector; import com.google.inject.Injector;
import org.jclouds.crypto.Crypto; import org.jclouds.crypto.Crypto;
import org.jclouds.date.DateService; import org.jclouds.date.DateService;
@ -88,6 +89,11 @@ public interface Utils {
*/ */
ExecutorService ioExecutor(); ExecutorService ioExecutor();
@Beta
EventBus getEventBus();
EventBus eventBus();
LoggerFactory getLoggerFactory(); LoggerFactory getLoggerFactory();
/** /**
@ -104,4 +110,5 @@ public interface Utils {
*/ */
@Beta @Beta
Injector injector(); Injector injector();
} }

View File

@ -24,6 +24,7 @@ import javax.inject.Inject;
import javax.inject.Named; import javax.inject.Named;
import com.google.common.annotations.Beta; import com.google.common.annotations.Beta;
import com.google.common.eventbus.EventBus;
import com.google.inject.Injector; import com.google.inject.Injector;
import org.jclouds.Constants; import org.jclouds.Constants;
import org.jclouds.crypto.Crypto; import org.jclouds.crypto.Crypto;
@ -49,14 +50,15 @@ public class UtilsImpl implements Utils {
private final DateService date; private final DateService date;
private final ExecutorService userExecutor; private final ExecutorService userExecutor;
private final ExecutorService ioExecutor; private final ExecutorService ioExecutor;
private final EventBus eventBus;
private final LoggerFactory loggerFactory; private final LoggerFactory loggerFactory;
private Injector injector; private Injector injector;
@Inject @Inject
protected UtilsImpl(Injector injector, Json json, HttpClient simpleClient, HttpAsyncClient simpleAsyncClient, protected UtilsImpl(Injector injector, Json json, HttpClient simpleClient, HttpAsyncClient simpleAsyncClient,
Crypto encryption, DateService date, Crypto encryption, DateService date, @Named(Constants.PROPERTY_USER_THREADS) ExecutorService userThreads,
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService userThreads, @Named(Constants.PROPERTY_IO_WORKER_THREADS) ExecutorService ioThreads, EventBus eventBus,
@Named(Constants.PROPERTY_IO_WORKER_THREADS) ExecutorService ioThreads, LoggerFactory loggerFactory) { LoggerFactory loggerFactory) {
this.injector = injector; this.injector = injector;
this.json = json; this.json = json;
this.simpleClient = simpleClient; this.simpleClient = simpleClient;
@ -65,6 +67,7 @@ public class UtilsImpl implements Utils {
this.date = date; this.date = date;
this.userExecutor = userThreads; this.userExecutor = userThreads;
this.ioExecutor = ioThreads; this.ioExecutor = ioThreads;
this.eventBus = eventBus;
this.loggerFactory = loggerFactory; this.loggerFactory = loggerFactory;
} }
@ -128,6 +131,16 @@ public class UtilsImpl implements Utils {
return userExecutor; return userExecutor;
} }
@Override
public EventBus getEventBus() {
return eventBus;
}
@Override
public EventBus eventBus() {
return eventBus;
}
@Override @Override
public LoggerFactory getLoggerFactory() { public LoggerFactory getLoggerFactory() {
return loggerFactory; return loggerFactory;

View File

@ -28,6 +28,7 @@ import java.util.concurrent.TimeUnit;
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function; import com.google.common.base.Function;
import com.google.common.base.Objects;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import com.google.common.base.Supplier; import com.google.common.base.Supplier;
import com.google.common.base.Suppliers; import com.google.common.base.Suppliers;
@ -144,5 +145,28 @@ public class Suppliers2 {
} }
private static final long serialVersionUID = 0; private static final long serialVersionUID = 0;
@Override
public int hashCode() {
return Objects.hashCode(delegate, durationNanos);
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
ExpiringMemoizingSupplier<?> that = ExpiringMemoizingSupplier.class.cast(obj);
return Objects.equal(delegate, that.delegate) && Objects.equal(durationNanos, that.durationNanos);
}
@Override
public String toString() {
return Objects.toStringHelper(this).add("delegate", delegate).add("durationNanos", durationNanos).toString();
}
} }
} }

View File

@ -19,6 +19,7 @@
package org.jclouds.demo.tweetstore.integration; package org.jclouds.demo.tweetstore.integration;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.io.Closeables.closeQuietly;
import static java.lang.String.format; import static java.lang.String.format;
import java.io.File; import java.io.File;
@ -45,7 +46,7 @@ public class GoogleDevServer {
String filename = String.format( String filename = String.format(
"%1$s/WEB-INF/jclouds.properties", warfile); "%1$s/WEB-INF/jclouds.properties", warfile);
System.err.println("file: " + filename); System.err.println("file: " + filename);
props.store(new FileOutputStream(filename), "test"); storeProperties(filename, props);
assert new File(filename).exists(); assert new File(filename).exists();
this.server = new Thread(new Runnable() { this.server = new Thread(new Runnable() {
public void run() { public void run() {
@ -64,6 +65,15 @@ public class GoogleDevServer {
TimeUnit.SECONDS.sleep(30); TimeUnit.SECONDS.sleep(30);
} }
private static void storeProperties(String filename, Properties props) throws IOException {
FileOutputStream targetFile = new FileOutputStream(filename);
try {
props.store(targetFile, "test");
} finally {
closeQuietly(targetFile);
}
}
public void stop() throws Exception { public void stop() throws Exception {
// KickStart.main opens a process and calls process.waitFor(), which is interruptable // KickStart.main opens a process and calls process.waitFor(), which is interruptable
server.interrupt(); server.interrupt();

View File

@ -19,6 +19,7 @@
package org.jclouds.demo.tweetstore.integration; package org.jclouds.demo.tweetstore.integration;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.io.Closeables.closeQuietly;
import static java.lang.String.format; import static java.lang.String.format;
import java.io.File; import java.io.File;
@ -45,7 +46,7 @@ public class GoogleDevServer {
String filename = String.format( String filename = String.format(
"%1$s/WEB-INF/jclouds.properties", warfile); "%1$s/WEB-INF/jclouds.properties", warfile);
System.err.println("file: " + filename); System.err.println("file: " + filename);
props.store(new FileOutputStream(filename), "test"); storeProperties(filename, props);
assert new File(filename).exists(); assert new File(filename).exists();
this.server = new Thread(new Runnable() { this.server = new Thread(new Runnable() {
public void run() { public void run() {
@ -64,6 +65,15 @@ public class GoogleDevServer {
TimeUnit.SECONDS.sleep(30); TimeUnit.SECONDS.sleep(30);
} }
private static void storeProperties(String filename, Properties props) throws IOException {
FileOutputStream targetFile = new FileOutputStream(filename);
try {
props.store(targetFile, "test");
} finally {
closeQuietly(targetFile);
}
}
public void stop() throws Exception { public void stop() throws Exception {
// KickStart.main opens a process and calls process.waitFor(), which is interruptable // KickStart.main opens a process and calls process.waitFor(), which is interruptable
server.interrupt(); server.interrupt();

View File

@ -0,0 +1,41 @@
====
Licensed to jclouds, Inc. (jclouds) under one or more
contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. jclouds licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
====
A guide to generating Twitter consumer keys and access tokens is at http://tinyurl.com/2fhebgb
Please modify your maven settings.xml like below before attempting to run 'mvn -Plive install'
<profile>
<id>keys</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<test.aws-s3.identity>YOUR_ACCESS_KEY_ID</test.aws-s3.identity>
<test.aws-s3.credential>YOUR_SECRET_KEY</test.aws-s3.credential>
<test.cloudfiles-us.identity>YOUR_USER</test.cloudfiles-us.identity>
<test.cloudfiles-us.credential>YOUR_HEX_KEY</test.cloudfiles-us.credential>
<test.azureblob.identity>YOUR_ACCOUNT</test.azureblob.identity>
<test.azureblob.credential>YOUR_BASE64_ENCODED_KEY</test.azureblob.credential>
<test.twitter.rhcloud-tweetstore.consumer.identity>YOUR_TWITTER_CONSUMER_KEY</test.twitter.rhcloud-tweetstore.consumer.identity>
<test.twitter.rhcloud-tweetstore.consumer.credential>YOUR_TWITTER_CONSUMER_SECRET</test.twitter.rhcloud-tweetstore.consumer.credential>
<test.twitter.rhcloud-tweetstore.access.identity>YOUR_TWITTER_ACCESSTOKEN</test.twitter.rhcloud-tweetstore.access.identity>
<test.twitter.rhcloud-tweetstore.access.credential>YOUR_TWITTER_ACCESSTOKEN_SECRET</test.twitter.rhcloud-tweetstore.access.credential>
</properties>
</profile>

View File

@ -0,0 +1,124 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to jclouds, Inc. (jclouds) under one or more
contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. jclouds licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.jclouds</groupId>
<artifactId>jclouds-demos-tweetstore-project</artifactId>
<version>1.5.0-SNAPSHOT</version>
</parent>
<artifactId>jclouds-demo-rhcloud-tweetstore</artifactId>
<packaging>war</packaging>
<name>jclouds TweetStore for OpenShift Express</name>
<description>jclouds TweetStore for RedHat's OpenShift Express using Guice for Dependency Injection</description>
<properties>
<rhcloud.jboss.version>7.0.2.Final</rhcloud.jboss.version>
<rhcloud.jboss.address>localhost</rhcloud.jboss.address>
<rhcloud.jboss.port>8088</rhcloud.jboss.port>
<jclouds.tweetstore.container>jclouds-rhcloud-tweetstore</jclouds.tweetstore.container>
</properties>
<dependencies>
<dependency>
<groupId>com.google.inject.extensions</groupId>
<artifactId>guice-servlet</artifactId>
<version>3.0</version>
</dependency>
<!-- OpenShift Express uses JBoss AS 7 -->
<dependency>
<groupId>org.jboss.as</groupId>
<artifactId>jboss-as-embedded</artifactId>
<version>${rhcloud.jboss.version}</version>
<scope>test</scope>
<exclusions>
<!-- loading the LogManager here leads to ClassCastExceptions because
the server uses a different classloader -->
<exclusion>
<artifactId>jboss-logmanager</artifactId>
<groupId>org.jboss.logmanager</groupId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<profiles>
<profile>
<id>live</id>
<build>
<plugins>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<executions>
<execution>
<id>integration</id>
<phase>integration-test</phase>
<goals>
<goal>test</goal>
</goals>
<configuration>
<systemPropertyVariables>
<test.twitter.consumer.identity>${test.twitter.runatcloud-tweetstore.consumer.identity}</test.twitter.consumer.identity>
<test.twitter.consumer.credential>${test.twitter.runatcloud-tweetstore.consumer.credential}</test.twitter.consumer.credential>
<test.twitter.access.identity>${test.twitter.runatcloud-tweetstore.access.identity}</test.twitter.access.identity>
<test.twitter.access.credential>${test.twitter.runatcloud-tweetstore.access.credential}</test.twitter.access.credential>
<test.azureblob.identity>${test.azureblob.identity}</test.azureblob.identity>
<test.azureblob.credential>${test.azureblob.credential}</test.azureblob.credential>
<test.cloudfiles-us.identity>${test.cloudfiles-us.identity}</test.cloudfiles-us.identity>
<test.cloudfiles-us.credential>${test.cloudfiles-us.credential}</test.cloudfiles-us.credential>
<test.aws-s3.identity>${test.aws-s3.identity}</test.aws-s3.identity>
<test.aws-s3.credential>${test.aws-s3.credential}</test.aws-s3.credential>
<test.cloudonestorage.identity>${test.cloudonestorage.identity}</test.cloudonestorage.identity>
<test.cloudonestorage.credential>${test.cloudonestorage.credential}</test.cloudonestorage.credential>
<test.ninefold-storage.identity>${test.ninefold-storage.identity}</test.ninefold-storage.identity>
<test.ninefold-storage.credential>${test.ninefold-storage.credential}</test.ninefold-storage.credential>
<rhcloud.jboss.home>${rhcloud.jboss.home}</rhcloud.jboss.home>
<rhcloud.jboss.address>${rhcloud.jboss.address}</rhcloud.jboss.address>
<rhcloud.jboss.port>${rhcloud.jboss.port}</rhcloud.jboss.port>
<jclouds.tweetstore.blobstores>${jclouds.tweetstore.blobstores}</jclouds.tweetstore.blobstores>
<jclouds.tweetstore.container>test.${jclouds.tweetstore.container}</jclouds.tweetstore.container>
<jboss.embedded.root>${project.build.directory}/rhcloud-jboss</jboss.embedded.root>
<jboss.server.config.dir>${project.basedir}/src/test/resources/jbossas7/configuration</jboss.server.config.dir>
<warfile>${project.build.directory}/${project.build.finalName}</warfile>
</systemPropertyVariables>
<environmentVariables>
<OPENSHIFT_INTERNAL_IP>${rhcloud.jboss.address}</OPENSHIFT_INTERNAL_IP>
<OPENSHIFT_INTERNAL_PORT>${rhcloud.jboss.port}</OPENSHIFT_INTERNAL_PORT>
</environmentVariables>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>deploy</id>
<properties>
<!-- classifier to choose the correct jclouds.properties file -->
<tweetstore.instance>rhcloud-tweetstore</tweetstore.instance>
</properties>
</profile>
</profiles>
</project>

View File

@ -0,0 +1,57 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.demo.paas;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.jclouds.demo.paas.config.PlatformServicesInitializer.PLATFORM_SERVICES_ATTRIBUTE_NAME;
import java.util.Map;
import javax.servlet.ServletContext;
import org.jclouds.demo.paas.service.taskqueue.TaskQueue;
import org.jclouds.javax.annotation.Nullable;
import com.google.common.collect.ImmutableMap;
/**
* @author Andrew Phillips
*/
public class PlatformServices {
protected final String baseUrl;
private ImmutableMap<String, TaskQueue> taskQueues;
public PlatformServices(String baseUrl, Map<String, TaskQueue> taskQueues) {
this.baseUrl = baseUrl;
this.taskQueues = ImmutableMap.copyOf(taskQueues);
}
public String getBaseUrl() {
return baseUrl;
}
public @Nullable TaskQueue getTaskQueue(String name) {
return taskQueues.get(name);
}
public static PlatformServices get(ServletContext context) {
return (PlatformServices) checkNotNull(context.getAttribute(
PLATFORM_SERVICES_ATTRIBUTE_NAME), PLATFORM_SERVICES_ATTRIBUTE_NAME);
}
}

View File

@ -0,0 +1,126 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.demo.paas;
import static java.lang.String.format;
import org.jclouds.http.HttpCommand;
import org.jclouds.http.HttpCommandExecutorService;
import org.jclouds.http.HttpRequest;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.Multimap;
public class RunnableHttpRequest implements Runnable {
public static final String PLATFORM_REQUEST_ORIGINATOR_HEADER = "X-Platform-Originator";
public static Factory factory(HttpCommandExecutorService httpClient) {
return factory(httpClient, format("%s@%d", Factory.class.getName(), System.currentTimeMillis()));
}
public static Factory factory(HttpCommandExecutorService httpClient, String originator) {
return new Factory(httpClient, originator);
}
public static class Factory {
protected final HttpCommandExecutorService httpClient;
protected final String originator;
private Factory(HttpCommandExecutorService httpClient, String originator) {
this.httpClient = httpClient;
this.originator = originator;
}
public RunnableHttpRequest create(HttpRequest request) {
HttpRequest requestWithSubmitter = request.toBuilder()
.headers(copyOfWithEntry(request.getHeaders(),
PLATFORM_REQUEST_ORIGINATOR_HEADER, originator)).build();
return new RunnableHttpRequest(httpClient, requestWithSubmitter);
}
private static <K, V> Multimap<K, V> copyOfWithEntry(
Multimap<? extends K, ? extends V> multimap, K k1, V v1) {
return ImmutableMultimap.<K, V>builder().putAll(multimap).put(k1, v1).build();
}
}
private final HttpCommandExecutorService httpClient;
private final HttpRequest request;
private RunnableHttpRequest(HttpCommandExecutorService httpClient, HttpRequest request) {
this.httpClient = httpClient;
this.request = request;
}
@Override
public void run() {
httpClient.submit(new ImmutableHttpCommand(request));
}
private class ImmutableHttpCommand implements HttpCommand {
private final HttpRequest request;
public ImmutableHttpCommand(HttpRequest request) {
this.request = request;
}
@Override
public void setException(Exception exception) {
}
@Override
public void setCurrentRequest(HttpRequest request) {
}
@Override
public boolean isReplayable() {
return false;
}
@Override
public int incrementRedirectCount() {
return 0;
}
@Override
public int incrementFailureCount() {
return 0;
}
@Override
public int getRedirectCount() {
return 0;
}
@Override
public int getFailureCount() {
return 0;
}
@Override
public Exception getException() {
return null;
}
@Override
public HttpRequest getCurrentRequest() {
return request;
}
}
}

Some files were not shown because too many files have changed in this diff Show More