mirror of https://github.com/apache/jclouds.git
Merge branch 'master' of git://github.com/jclouds/jclouds into jclouds-vbox
This commit is contained in:
commit
77122c4bc8
|
@ -47,7 +47,7 @@ import org.apache.tools.ant.types.Environment;
|
|||
import org.apache.tools.ant.types.FileSet;
|
||||
import org.apache.tools.ant.types.Path;
|
||||
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.ShellToken;
|
||||
import org.jclouds.scriptbuilder.domain.Statement;
|
||||
|
@ -237,13 +237,13 @@ public class SSHJava extends Java {
|
|||
private int sshexecRedirectStreams(Statement statement) throws IOException {
|
||||
exec.setStreamHandler(redirector.createHandler());
|
||||
log("starting java as:\n" + statement.render(osFamily), Project.MSG_VERBOSE);
|
||||
int rc;
|
||||
int exitStatus;
|
||||
try {
|
||||
rc = sshexec(statement.render(osFamily));
|
||||
exitStatus = sshexec(statement.render(osFamily));
|
||||
} finally {
|
||||
redirector.complete();
|
||||
}
|
||||
return rc;
|
||||
return exitStatus;
|
||||
}
|
||||
|
||||
private void mkdirAndCopyTo(String destination, Iterable<FileSet> sets) {
|
||||
|
@ -373,8 +373,8 @@ public class SSHJava extends Java {
|
|||
Joiner.on(' ').join(commandLine.getJavaCommand().getArguments()));
|
||||
}
|
||||
|
||||
InitBuilder testInitBuilder = new InitBuilder(id, basedir, basedir, envVariables,
|
||||
ImmutableList.<Statement> of(Statements.interpret( commandBuilder.toString())));
|
||||
InitScript testInitBuilder = InitScript.builder().name(id).home(basedir).exportVariables(envVariables)
|
||||
.run(Statements.interpret( commandBuilder.toString())).build();
|
||||
return testInitBuilder.render(osFamily);
|
||||
}
|
||||
|
||||
|
|
|
@ -118,8 +118,8 @@
|
|||
<configuration>
|
||||
<instructions>
|
||||
<Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
|
||||
<Export-Package>org.jclouds.atmos.*;version="${project.version}"</Export-Package>
|
||||
<Import-Package>org.jclouds.*;version="${project.version}",*</Import-Package>
|
||||
<Export-Package>org.jclouds.atmos*;version="${project.version}"</Export-Package>
|
||||
<Import-Package>org.jclouds*;version="${project.version}",*</Import-Package>
|
||||
</instructions>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
|
|
@ -113,11 +113,11 @@
|
|||
<configuration>
|
||||
<instructions>
|
||||
<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>
|
||||
org.jclouds.compute.internal;version="${project.version}",
|
||||
org.jclouds.rest.internal;version="${project.version}",
|
||||
org.jclouds.*;version="${project.version}",
|
||||
org.jclouds*;version="${project.version}",
|
||||
*
|
||||
</Import-Package>
|
||||
</instructions>
|
||||
|
|
|
@ -133,8 +133,12 @@
|
|||
<configuration>
|
||||
<instructions>
|
||||
<Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
|
||||
<Export-Package>org.jclouds.cloudfiles.*;version="${project.version}"</Export-Package>
|
||||
<Import-Package>org.jclouds.*;version="${project.version}",*</Import-Package>
|
||||
<Export-Package>org.jclouds.cloudfiles*;version="${project.version}"</Export-Package>
|
||||
<Import-Package>
|
||||
org.jclouds*;version="${project.version}",
|
||||
org.jclouds.openstack.swift.options;version="${project.version}",
|
||||
*
|
||||
</Import-Package>
|
||||
</instructions>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
|
|
@ -119,8 +119,8 @@
|
|||
<configuration>
|
||||
<instructions>
|
||||
<Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
|
||||
<Export-Package>org.jclouds.cloudloadbalancers.*;version="${project.version}"</Export-Package>
|
||||
<Import-Package>org.jclouds.*;version="${project.version}",*</Import-Package>
|
||||
<Export-Package>org.jclouds.cloudloadbalancers*;version="${project.version}"</Export-Package>
|
||||
<Import-Package>org.jclouds*;version="${project.version}",*</Import-Package>
|
||||
</instructions>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
|
|
@ -134,11 +134,11 @@
|
|||
<configuration>
|
||||
<instructions>
|
||||
<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>
|
||||
org.jclouds.compute.internal;version="${project.version}",
|
||||
org.jclouds.rest.internal;version="${project.version}",
|
||||
org.jclouds.*;version="${project.version}",
|
||||
org.jclouds*;version="${project.version}",
|
||||
*
|
||||
</Import-Package>
|
||||
</instructions>
|
||||
|
|
|
@ -132,7 +132,7 @@ public class ServerToNodeMetadata implements Function<Server, NodeMetadata> {
|
|||
try {
|
||||
return Iterables.find(images.get(), new FindImageForServer(from)).getOperatingSystem();
|
||||
} 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;
|
||||
}
|
||||
|
|
|
@ -120,11 +120,11 @@
|
|||
<configuration>
|
||||
<instructions>
|
||||
<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>
|
||||
org.jclouds.compute.internal;version="${project.version}",
|
||||
org.jclouds.rest.internal;version="${project.version}",
|
||||
org.jclouds.*;version="${project.version}",
|
||||
org.jclouds*;version="${project.version}",
|
||||
*
|
||||
</Import-Package>
|
||||
</instructions>
|
||||
|
|
|
@ -144,11 +144,11 @@
|
|||
<configuration>
|
||||
<instructions>
|
||||
<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>
|
||||
org.jclouds.compute.internal;version="${project.version}",
|
||||
org.jclouds.rest.internal;version="${project.version}",
|
||||
org.jclouds.*;version="${project.version}",
|
||||
org.jclouds*;version="${project.version}",
|
||||
*
|
||||
</Import-Package>
|
||||
</instructions>
|
||||
|
|
|
@ -109,8 +109,8 @@
|
|||
<configuration>
|
||||
<instructions>
|
||||
<Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
|
||||
<Export-Package>org.jclouds.cloudwatch.*;version="${project.version}"</Export-Package>
|
||||
<Import-Package>org.jclouds.*;version="${project.version}",*</Import-Package>
|
||||
<Export-Package>org.jclouds.cloudwatch*;version="${project.version}"</Export-Package>
|
||||
<Import-Package>org.jclouds*;version="${project.version}",*</Import-Package>
|
||||
</instructions>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
|
|
@ -133,11 +133,11 @@
|
|||
<configuration>
|
||||
<instructions>
|
||||
<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>
|
||||
org.jclouds.compute.internal;version="${project.version}",
|
||||
org.jclouds.rest.internal;version="${project.version}",
|
||||
org.jclouds.*;version="${project.version}",
|
||||
org.jclouds*;version="${project.version}",
|
||||
*
|
||||
</Import-Package>
|
||||
</instructions>
|
||||
|
|
|
@ -134,11 +134,11 @@
|
|||
<configuration>
|
||||
<instructions>
|
||||
<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>
|
||||
org.jclouds.compute.internal;version="${project.version}",
|
||||
org.jclouds.rest.internal;version="${project.version}",
|
||||
org.jclouds.*;version="${project.version}",
|
||||
org.jclouds*;version="${project.version}",
|
||||
*
|
||||
</Import-Package>
|
||||
</instructions>
|
||||
|
|
|
@ -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)))
|
|
@ -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)))
|
|
@ -24,10 +24,11 @@ import static com.google.common.collect.Iterables.transform;
|
|||
import static org.jclouds.util.Preconditions2.checkNotEmpty;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
|
@ -71,8 +72,8 @@ import com.google.common.base.Predicate;
|
|||
import com.google.common.base.Supplier;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
import com.google.common.collect.ImmutableMultimap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.ImmutableMultimap.Builder;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
|
||||
/**
|
||||
* @author Adrian Cole
|
||||
|
@ -91,9 +92,9 @@ public class EC2ComputeService extends BaseComputeService {
|
|||
RebootNodeStrategy rebootNodeStrategy, DestroyNodeStrategy destroyNodeStrategy,
|
||||
ResumeNodeStrategy startNodeStrategy, SuspendNodeStrategy stopNodeStrategy,
|
||||
Provider<TemplateBuilder> templateBuilderProvider, Provider<TemplateOptions> templateOptionsProvider,
|
||||
@Named("NODE_RUNNING") Predicate<NodeMetadata> nodeRunning,
|
||||
@Named("NODE_TERMINATED") Predicate<NodeMetadata> nodeTerminated,
|
||||
@Named("NODE_SUSPENDED") Predicate<NodeMetadata> nodeSuspended,
|
||||
@Named("NODE_RUNNING") Predicate<AtomicReference<NodeMetadata>> nodeRunning,
|
||||
@Named("NODE_TERMINATED") Predicate<AtomicReference<NodeMetadata>> nodeTerminated,
|
||||
@Named("NODE_SUSPENDED") Predicate<AtomicReference<NodeMetadata>> nodeSuspended,
|
||||
InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory,
|
||||
RunScriptOnNode.Factory runScriptOnNodeFactory, InitAdminAccess initAdminAccess,
|
||||
PersistNodeCredentials persistNodeCredentials, Timeouts timeouts,
|
||||
|
|
|
@ -26,6 +26,7 @@ import static org.jclouds.ec2.compute.util.EC2ComputeUtils.getZoneFromLocationOr
|
|||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.inject.Inject;
|
||||
|
@ -80,7 +81,7 @@ public class EC2CreateNodesInGroupThenAddToSet implements CreateNodesInGroupThen
|
|||
@VisibleForTesting
|
||||
final EC2Client client;
|
||||
@VisibleForTesting
|
||||
final Predicate<NodeMetadata> nodeRunning;
|
||||
final Predicate<AtomicReference<NodeMetadata>> nodeRunning;
|
||||
@VisibleForTesting
|
||||
final LoadingCache<RegionAndName, String> elasticIpCache;
|
||||
@VisibleForTesting
|
||||
|
@ -101,7 +102,7 @@ public class EC2CreateNodesInGroupThenAddToSet implements CreateNodesInGroupThen
|
|||
EC2Client client,
|
||||
@Named("ELASTICIP")
|
||||
LoadingCache<RegionAndName, String> elasticIpCache,
|
||||
@Named("NODE_RUNNING") Predicate<NodeMetadata> nodeRunning,
|
||||
@Named("NODE_RUNNING") Predicate<AtomicReference<NodeMetadata>> nodeRunning,
|
||||
Provider<TemplateBuilder> templateBuilderProvider,
|
||||
CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions createKeyPairAndSecurityGroupsAsNeededAndReturncustomize,
|
||||
InstancePresent instancePresent, Function<RunningInstance, NodeMetadata> runningInstanceToNodeMetadata,
|
||||
|
@ -197,7 +198,8 @@ public class EC2CreateNodesInGroupThenAddToSet implements CreateNodesInGroupThen
|
|||
|
||||
// block until instance is running
|
||||
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.debug(">> associating elastic IP %s to instance %s", ip, coordinates);
|
||||
client.getElasticIPAddressServices().associateAddressInRegion(region, ip, id);
|
||||
|
|
|
@ -40,6 +40,8 @@ import org.jclouds.domain.LoginCredentials;
|
|||
import org.jclouds.ec2.domain.Attachment;
|
||||
import org.jclouds.ec2.domain.BlockDevice;
|
||||
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.InstanceType;
|
||||
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.Snapshot;
|
||||
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.predicates.InstanceStateRunning;
|
||||
import org.jclouds.ec2.predicates.InstanceStateStopped;
|
||||
|
@ -65,9 +65,8 @@ import org.jclouds.net.IPSocket;
|
|||
import org.jclouds.predicates.RetryablePredicate;
|
||||
import org.jclouds.predicates.SocketOpen;
|
||||
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.Statement;
|
||||
import org.jclouds.scriptbuilder.domain.Statements;
|
||||
import org.jclouds.ssh.SshClient;
|
||||
import org.jclouds.ssh.SshException;
|
||||
|
@ -77,7 +76,6 @@ import org.testng.annotations.BeforeTest;
|
|||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Iterables;
|
||||
|
@ -256,12 +254,12 @@ public class EBSBootEC2ClientLiveTest extends BaseVersionedServiceLiveTest {
|
|||
@BeforeTest
|
||||
void makeScript() {
|
||||
|
||||
mkEbsBoot = new InitBuilder(
|
||||
"mkebsboot",// name of the script
|
||||
"/tmp",// working directory
|
||||
"/tmp/logs",// location of stdout.log and stderr.log
|
||||
ImmutableMap.of("imageDir", "/mnt/tmp", "ebsDevice", "/dev/sdh", "ebsMountPoint", "/mnt/ebs"),
|
||||
ImmutableList.<Statement> of(Statements
|
||||
mkEbsBoot = InitScript.builder()
|
||||
.name("mkebsboot")
|
||||
.home("/tmp")
|
||||
.logDir("/tmp/logs")
|
||||
.exportVariables(ImmutableMap.of("imageDir", "/mnt/tmp", "ebsDevice", "/dev/sdh", "ebsMountPoint", "/mnt/ebs"))
|
||||
.run(Statements
|
||||
.interpret(
|
||||
"echo creating a filesystem and mounting the ebs volume",
|
||||
"{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}",
|
||||
"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}",
|
||||
"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);
|
||||
}
|
||||
|
||||
|
|
|
@ -18,12 +18,12 @@
|
|||
*/
|
||||
package org.jclouds.ec2.compute.strategy;
|
||||
|
||||
import static org.easymock.EasyMock.createMock;
|
||||
import static org.easymock.EasyMock.eq;
|
||||
import static org.easymock.EasyMock.expect;
|
||||
import static org.easymock.EasyMock.replay;
|
||||
import static org.easymock.EasyMock.reportMatcher;
|
||||
import static org.easymock.classextension.EasyMock.createMock;
|
||||
import static org.easymock.classextension.EasyMock.replay;
|
||||
import static org.easymock.classextension.EasyMock.verify;
|
||||
import static org.easymock.EasyMock.verify;
|
||||
|
||||
import java.util.Map;
|
||||
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.Image;
|
||||
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.TemplateBuilder;
|
||||
import org.jclouds.compute.predicates.AtomicNodeRunning;
|
||||
import org.jclouds.compute.strategy.GetNodeMetadataStrategy;
|
||||
import org.jclouds.compute.util.ComputeUtils;
|
||||
import org.jclouds.domain.Credentials;
|
||||
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.services.ElasticIPAddressClient;
|
||||
import org.jclouds.ec2.services.InstanceClient;
|
||||
import org.testng.Assert;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Iterables;
|
||||
|
@ -73,17 +77,19 @@ public class EC2CreateNodesInGroupThenAddToSetTest {
|
|||
|
||||
String imageId = "ami1";
|
||||
String instanceCreatedId = "instance1";
|
||||
NodeMetadata nodeMetadata = new NodeMetadataBuilder().id(region + "/" + instanceCreatedId)
|
||||
.providerId(instanceCreatedId).state(NodeState.RUNNING).build();
|
||||
// setup mocks
|
||||
TemplateBuilder templateBuilder = createMock(TemplateBuilder.class);
|
||||
EC2CreateNodesInGroupThenAddToSet strategy = setupStrategy(templateBuilder);
|
||||
EC2CreateNodesInGroupThenAddToSet strategy = setupStrategy(templateBuilder, nodeMetadata);
|
||||
InputParams input = new InputParams(location);
|
||||
InstanceClient instanceClient = createMock(InstanceClient.class);
|
||||
ElasticIPAddressClient ipClient = createMock(ElasticIPAddressClient.class);
|
||||
RunInstancesOptions ec2Options = createMock(RunInstancesOptions.class);
|
||||
RunningInstance instance = createMock(RunningInstance.class);
|
||||
Reservation<? extends RunningInstance> reservation = new Reservation<RunningInstance>(region, ImmutableSet
|
||||
.<String> of(), ImmutableSet.<RunningInstance> of(instance), "ownerId", "requesterId", "reservationId");
|
||||
NodeMetadata nodeMetadata = createMock(NodeMetadata.class);
|
||||
Reservation<? extends RunningInstance> reservation = new Reservation<RunningInstance>(region,
|
||||
ImmutableSet.<String> of(), ImmutableSet.<RunningInstance> of(instance), "ownerId", "requesterId",
|
||||
"reservationId");
|
||||
|
||||
// enable auto-allocation
|
||||
strategy.autoAllocateElasticIps = true;
|
||||
|
@ -93,8 +99,8 @@ public class EC2CreateNodesInGroupThenAddToSetTest {
|
|||
expect(templateBuilder.build()).andReturn(input.template);
|
||||
expect(strategy.client.getInstanceServices()).andReturn(instanceClient).atLeastOnce();
|
||||
expect(
|
||||
strategy.createKeyPairAndSecurityGroupsAsNeededAndReturncustomize.execute(region, input.tag,
|
||||
input.template)).andReturn(ec2Options);
|
||||
strategy.createKeyPairAndSecurityGroupsAsNeededAndReturncustomize
|
||||
.execute(region, input.tag, input.template)).andReturn(ec2Options);
|
||||
expect(strategy.client.getElasticIPAddressServices()).andReturn(ipClient).atLeastOnce();
|
||||
|
||||
expect(input.template.getLocation()).andReturn(input.location).atLeastOnce();
|
||||
|
@ -104,7 +110,6 @@ public class EC2CreateNodesInGroupThenAddToSetTest {
|
|||
// differences when ip allocation
|
||||
expect(ipClient.allocateAddressInRegion(region)).andReturn("1.1.1.1");
|
||||
expect(strategy.runningInstanceToNodeMetadata.apply(instance)).andReturn(nodeMetadata).atLeastOnce();
|
||||
expect(strategy.nodeRunning.apply(nodeMetadata)).andReturn(true);
|
||||
ipClient.associateAddressInRegion(region, "1.1.1.1", instanceCreatedId);
|
||||
strategy.elasticIpCache.put(new RegionAndName(region, instanceCreatedId), "1.1.1.1");
|
||||
|
||||
|
@ -122,8 +127,8 @@ public class EC2CreateNodesInGroupThenAddToSetTest {
|
|||
|
||||
expect(
|
||||
strategy.utils.customizeNodesAndAddToGoodMapOrPutExceptionIntoBadMap(eq(input.options),
|
||||
containsNodeMetadata(nodeMetadata), eq(input.nodes), eq(input.badNodes),
|
||||
eq(input.customization))).andReturn(null);
|
||||
containsNodeMetadata(nodeMetadata), eq(input.nodes), eq(input.badNodes), eq(input.customization)))
|
||||
.andReturn(null);
|
||||
|
||||
// replay mocks
|
||||
replay(templateBuilder);
|
||||
|
@ -131,7 +136,6 @@ public class EC2CreateNodesInGroupThenAddToSetTest {
|
|||
replay(ipClient);
|
||||
replay(ec2Options);
|
||||
replay(instance);
|
||||
replay(nodeMetadata);
|
||||
input.replayMe();
|
||||
replayStrategy(strategy);
|
||||
|
||||
|
@ -144,7 +148,6 @@ public class EC2CreateNodesInGroupThenAddToSetTest {
|
|||
verify(ipClient);
|
||||
verify(ec2Options);
|
||||
verify(instance);
|
||||
verify(nodeMetadata);
|
||||
input.verifyMe();
|
||||
verifyStrategy(strategy);
|
||||
}
|
||||
|
@ -184,24 +187,27 @@ public class EC2CreateNodesInGroupThenAddToSetTest {
|
|||
private void assertRegionAndZoneForLocation(Location location, String region, String zone) {
|
||||
String imageId = "ami1";
|
||||
String instanceCreatedId = "instance1";
|
||||
NodeMetadata nodeMetadata = new NodeMetadataBuilder().id(region + "/" + instanceCreatedId)
|
||||
.providerId(instanceCreatedId).state(NodeState.RUNNING).build();
|
||||
|
||||
// setup mocks
|
||||
TemplateBuilder templateBuilder = createMock(TemplateBuilder.class);
|
||||
EC2CreateNodesInGroupThenAddToSet strategy = setupStrategy(templateBuilder);
|
||||
EC2CreateNodesInGroupThenAddToSet strategy = setupStrategy(templateBuilder, nodeMetadata);
|
||||
InputParams input = new InputParams(location);
|
||||
InstanceClient instanceClient = createMock(InstanceClient.class);
|
||||
RunInstancesOptions ec2Options = createMock(RunInstancesOptions.class);
|
||||
RunningInstance instance = createMock(RunningInstance.class);
|
||||
Reservation<? extends RunningInstance> reservation = new Reservation<RunningInstance>(region, ImmutableSet
|
||||
.<String> of(), ImmutableSet.<RunningInstance> of(instance), "ownerId", "requesterId", "reservationId");
|
||||
NodeMetadata nodeMetadata = createMock(NodeMetadata.class);
|
||||
Reservation<? extends RunningInstance> reservation = new Reservation<RunningInstance>(region,
|
||||
ImmutableSet.<String> of(), ImmutableSet.<RunningInstance> of(instance), "ownerId", "requesterId",
|
||||
"reservationId");
|
||||
|
||||
// setup expectations
|
||||
expect(templateBuilder.fromTemplate(input.template)).andReturn(templateBuilder);
|
||||
expect(templateBuilder.build()).andReturn(input.template);
|
||||
expect(strategy.client.getInstanceServices()).andReturn(instanceClient).atLeastOnce();
|
||||
expect(
|
||||
strategy.createKeyPairAndSecurityGroupsAsNeededAndReturncustomize.execute(region, input.tag,
|
||||
input.template)).andReturn(ec2Options);
|
||||
strategy.createKeyPairAndSecurityGroupsAsNeededAndReturncustomize
|
||||
.execute(region, input.tag, input.template)).andReturn(ec2Options);
|
||||
expect(input.template.getLocation()).andReturn(input.location).atLeastOnce();
|
||||
expect(input.template.getImage()).andReturn(input.image).atLeastOnce();
|
||||
expect(input.image.getProviderId()).andReturn(imageId).atLeastOnce();
|
||||
|
@ -220,15 +226,14 @@ public class EC2CreateNodesInGroupThenAddToSetTest {
|
|||
expect(strategy.runningInstanceToNodeMetadata.apply(instance)).andReturn(nodeMetadata);
|
||||
expect(
|
||||
strategy.utils.customizeNodesAndAddToGoodMapOrPutExceptionIntoBadMap(eq(input.options),
|
||||
containsNodeMetadata(nodeMetadata), eq(input.nodes), eq(input.badNodes),
|
||||
eq(input.customization))).andReturn(null);
|
||||
containsNodeMetadata(nodeMetadata), eq(input.nodes), eq(input.badNodes), eq(input.customization)))
|
||||
.andReturn(null);
|
||||
|
||||
// replay mocks
|
||||
replay(templateBuilder);
|
||||
replay(instanceClient);
|
||||
replay(ec2Options);
|
||||
replay(instance);
|
||||
replay(nodeMetadata);
|
||||
input.replayMe();
|
||||
replayStrategy(strategy);
|
||||
|
||||
|
@ -240,16 +245,16 @@ public class EC2CreateNodesInGroupThenAddToSetTest {
|
|||
verify(instanceClient);
|
||||
verify(ec2Options);
|
||||
verify(instance);
|
||||
verify(nodeMetadata);
|
||||
input.verifyMe();
|
||||
verifyStrategy(strategy);
|
||||
}
|
||||
|
||||
private static final Location REGION_AP_SOUTHEAST_1 = new LocationBuilder().scope(LocationScope.REGION).id(
|
||||
"ap-southeast-1").description("ap-southeast-1").parent(
|
||||
new LocationBuilder().scope(LocationScope.PROVIDER).id("aws-ec2").description("aws-ec2").build()).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();
|
||||
private static final Location REGION_AP_SOUTHEAST_1 = new LocationBuilder().scope(LocationScope.REGION)
|
||||
.id("ap-southeast-1").description("ap-southeast-1")
|
||||
.parent(new LocationBuilder().scope(LocationScope.PROVIDER).id("aws-ec2").description("aws-ec2").build())
|
||||
.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")
|
||||
|
@ -293,7 +298,6 @@ public class EC2CreateNodesInGroupThenAddToSetTest {
|
|||
private void verifyStrategy(EC2CreateNodesInGroupThenAddToSet strategy) {
|
||||
verify(strategy.createKeyPairAndSecurityGroupsAsNeededAndReturncustomize);
|
||||
verify(strategy.client);
|
||||
verify(strategy.nodeRunning);
|
||||
verify(strategy.elasticIpCache);
|
||||
verify(strategy.instancePresent);
|
||||
verify(strategy.runningInstanceToNodeMetadata);
|
||||
|
@ -303,18 +307,26 @@ public class EC2CreateNodesInGroupThenAddToSetTest {
|
|||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private EC2CreateNodesInGroupThenAddToSet setupStrategy(TemplateBuilder template) {
|
||||
private EC2CreateNodesInGroupThenAddToSet setupStrategy(TemplateBuilder template, final NodeMetadata node) {
|
||||
EC2Client client = createMock(EC2Client.class);
|
||||
CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions createKeyPairAndSecurityGroupsAsNeededAndReturncustomize = createMock(CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions.class);
|
||||
InstancePresent instancePresent = createMock(InstancePresent.class);
|
||||
RunningInstanceToNodeMetadata runningInstanceToNodeMetadata = createMock(RunningInstanceToNodeMetadata.class);
|
||||
LoadingCache<RunningInstance, Credentials> instanceToCredentials = 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);
|
||||
ComputeUtils utils = createMock(ComputeUtils.class);
|
||||
return new EC2CreateNodesInGroupThenAddToSet(client, elasticIpCache, nodeRunning, Providers
|
||||
.<TemplateBuilder> of(template), createKeyPairAndSecurityGroupsAsNeededAndReturncustomize,
|
||||
return new EC2CreateNodesInGroupThenAddToSet(client, elasticIpCache, new AtomicNodeRunning(nodeRunning),
|
||||
Providers.<TemplateBuilder> of(template), createKeyPairAndSecurityGroupsAsNeededAndReturncustomize,
|
||||
instancePresent, runningInstanceToNodeMetadata, instanceToCredentials, credentialStore, utils);
|
||||
}
|
||||
|
||||
|
@ -322,7 +334,6 @@ public class EC2CreateNodesInGroupThenAddToSetTest {
|
|||
replay(strategy.createKeyPairAndSecurityGroupsAsNeededAndReturncustomize);
|
||||
replay(strategy.client);
|
||||
replay(strategy.elasticIpCache);
|
||||
replay(strategy.nodeRunning);
|
||||
replay(strategy.instancePresent);
|
||||
replay(strategy.runningInstanceToNodeMetadata);
|
||||
replay(strategy.instanceToCredentials);
|
||||
|
|
|
@ -133,11 +133,11 @@
|
|||
<configuration>
|
||||
<instructions>
|
||||
<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>
|
||||
org.jclouds.compute.internal;version="${project.version}",
|
||||
org.jclouds.rest.internal;version="${project.version}",
|
||||
org.jclouds.*;version="${project.version}",
|
||||
org.jclouds*;version="${project.version}",
|
||||
*
|
||||
</Import-Package>
|
||||
</instructions>
|
||||
|
|
|
@ -128,11 +128,11 @@
|
|||
<configuration>
|
||||
<instructions>
|
||||
<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>
|
||||
org.jclouds.compute.internal;version="${project.version}",
|
||||
org.jclouds.rest.internal;version="${project.version}",
|
||||
org.jclouds.*;version="${project.version}",
|
||||
org.jclouds*;version="${project.version}",
|
||||
*
|
||||
</Import-Package>
|
||||
</instructions>
|
||||
|
|
|
@ -106,8 +106,8 @@
|
|||
<configuration>
|
||||
<instructions>
|
||||
<Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
|
||||
<Export-Package>org.jclouds.filesystem.*;version="${project.version}"</Export-Package>
|
||||
<Import-Package>org.jclouds.*;version="${project.version}",*</Import-Package>
|
||||
<Export-Package>org.jclouds.filesystem*;version="${project.version}"</Export-Package>
|
||||
<Import-Package>org.jclouds*;version="${project.version}",*</Import-Package>
|
||||
</instructions>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
|
|
@ -137,11 +137,11 @@
|
|||
<configuration>
|
||||
<instructions>
|
||||
<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>
|
||||
org.jclouds.compute.internal;version="${project.version}",
|
||||
org.jclouds.rest.internal;version="${project.version}",
|
||||
org.jclouds.*;version="${project.version}",
|
||||
org.jclouds*;version="${project.version}",
|
||||
*
|
||||
</Import-Package>
|
||||
</instructions>
|
||||
|
|
|
@ -135,7 +135,7 @@ public class ServerToNodeMetadata implements Function<Server, NodeMetadata> {
|
|||
try {
|
||||
return Iterables.find(images.get(), new FindImageForServer(from));
|
||||
} 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;
|
||||
}
|
||||
|
|
|
@ -131,8 +131,8 @@
|
|||
<configuration>
|
||||
<instructions>
|
||||
<Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
|
||||
<Export-Package>org.jclouds.s3.*;version="${project.version}"</Export-Package>
|
||||
<Import-Package>org.jclouds.*;version="${project.version}",*</Import-Package>
|
||||
<Export-Package>org.jclouds.s3*;version="${project.version}"</Export-Package>
|
||||
<Import-Package>org.jclouds*;version="${project.version}",*</Import-Package>
|
||||
</instructions>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
|
|
@ -131,8 +131,8 @@
|
|||
<configuration>
|
||||
<instructions>
|
||||
<Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
|
||||
<Export-Package>org.jclouds.openstack.swift.*;version="${project.version}"</Export-Package>
|
||||
<Import-Package>org.jclouds.*;version="${project.version}",*</Import-Package>
|
||||
<Export-Package>org.jclouds.openstack.swift*;version="${project.version}"</Export-Package>
|
||||
<Import-Package>org.jclouds*;version="${project.version}",*</Import-Package>
|
||||
</instructions>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
|
|
@ -131,11 +131,11 @@
|
|||
<configuration>
|
||||
<instructions>
|
||||
<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>
|
||||
org.jclouds.compute.internal;version="${project.version}",
|
||||
org.jclouds.rest.internal;version="${project.version}",
|
||||
org.jclouds.*;version="${project.version}",
|
||||
org.jclouds*;version="${project.version}",
|
||||
*
|
||||
</Import-Package>
|
||||
</instructions>
|
||||
|
|
|
@ -127,8 +127,8 @@
|
|||
<configuration>
|
||||
<instructions>
|
||||
<Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
|
||||
<Export-Package>org.jclouds.walrus.*;version="${project.version}"</Export-Package>
|
||||
<Import-Package>org.jclouds.*;version="${project.version}",*</Import-Package>
|
||||
<Export-Package>org.jclouds.walrus*;version="${project.version}"</Export-Package>
|
||||
<Import-Package>org.jclouds*;version="${project.version}",*</Import-Package>
|
||||
</instructions>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
|
|
@ -97,8 +97,8 @@
|
|||
<configuration>
|
||||
<instructions>
|
||||
<Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
|
||||
<Export-Package>org.jclouds.blobstore.*;version="${project.version}"</Export-Package>
|
||||
<Import-Package>org.jclouds.*;version="${project.version}",*</Import-Package>
|
||||
<Export-Package>org.jclouds.blobstore*;version="${project.version}"</Export-Package>
|
||||
<Import-Package>org.jclouds*;version="${project.version}",*</Import-Package>
|
||||
<Fragment-Host>jclouds-core;bundle-version="[1.3,2)"</Fragment-Host>
|
||||
</instructions>
|
||||
</configuration>
|
||||
|
|
|
@ -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))
|
|
@ -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)))))))
|
|
@ -56,8 +56,8 @@
|
|||
<configuration>
|
||||
<instructions>
|
||||
<Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
|
||||
<Export-Package>org.jclouds.aws.*;version="${project.version}"</Export-Package>
|
||||
<Import-Package>org.jclouds.*;version="${project.version}",*</Import-Package>
|
||||
<Export-Package>org.jclouds.aws*;version="${project.version}"</Export-Package>
|
||||
<Import-Package>org.jclouds*;version="${project.version}",*</Import-Package>
|
||||
</instructions>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
|
|
@ -56,8 +56,8 @@
|
|||
<configuration>
|
||||
<instructions>
|
||||
<Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
|
||||
<Export-Package>org.jclouds.azure.*;version="${project.version}"</Export-Package>
|
||||
<Import-Package>org.jclouds.*;version="${project.version}",*</Import-Package>
|
||||
<Export-Package>org.jclouds.azure*;version="${project.version}"</Export-Package>
|
||||
<Import-Package>org.jclouds*;version="${project.version}",*</Import-Package>
|
||||
</instructions>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
|
|
@ -57,8 +57,8 @@
|
|||
<configuration>
|
||||
<instructions>
|
||||
<Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
|
||||
<Export-Package>org.jclouds.openstack.*;version="${project.version}"</Export-Package>
|
||||
<Import-Package>org.jclouds.*;version="${project.version}",*</Import-Package>
|
||||
<Export-Package>org.jclouds.openstack*;version="${project.version}"</Export-Package>
|
||||
<Import-Package>org.jclouds*;version="${project.version}",*</Import-Package>
|
||||
</instructions>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
|
|
@ -81,8 +81,8 @@
|
|||
<configuration>
|
||||
<instructions>
|
||||
<Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
|
||||
<Export-Package>org.jclouds.trmk.vcloud_0_8.*;version="${project.version}"</Export-Package>
|
||||
<Import-Package>org.jclouds.*;version="${project.version}",*</Import-Package>
|
||||
<Export-Package>org.jclouds.trmk.vcloud_0_8*;version="${project.version}"</Export-Package>
|
||||
<Import-Package>org.jclouds*;version="${project.version}",*</Import-Package>
|
||||
</instructions>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
|
|
@ -21,6 +21,7 @@ package org.jclouds.trmk.vcloud_0_8.compute;
|
|||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
|
@ -71,9 +72,9 @@ public class TerremarkVCloudComputeService extends BaseComputeService {
|
|||
RebootNodeStrategy rebootNodeStrategy, DestroyNodeStrategy destroyNodeStrategy,
|
||||
ResumeNodeStrategy resumeNodeStrategy, SuspendNodeStrategy suspendNodeStrategy,
|
||||
Provider<TemplateBuilder> templateBuilderProvider, Provider<TemplateOptions> templateOptionsProvider,
|
||||
@Named("NODE_RUNNING") Predicate<NodeMetadata> nodeRunning,
|
||||
@Named("NODE_TERMINATED") Predicate<NodeMetadata> nodeTerminated,
|
||||
@Named("NODE_SUSPENDED") Predicate<NodeMetadata> nodeSuspended,
|
||||
@Named("NODE_RUNNING") Predicate<AtomicReference<NodeMetadata>> nodeRunning,
|
||||
@Named("NODE_TERMINATED") Predicate<AtomicReference<NodeMetadata>> nodeTerminated,
|
||||
@Named("NODE_SUSPENDED") Predicate<AtomicReference<NodeMetadata>> nodeSuspended,
|
||||
InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory,
|
||||
RunScriptOnNode.Factory runScriptOnNodeFactory, InitAdminAccess initAdminAccess,
|
||||
PersistNodeCredentials persistNodeCredentials, Timeouts timeouts,
|
||||
|
|
|
@ -73,8 +73,8 @@
|
|||
<configuration>
|
||||
<instructions>
|
||||
<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>
|
||||
<Import-Package>!org.jclouds.compute.*;org.jclouds.*;version="${project.version}",*</Import-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>
|
||||
<Fragment-Host>jclouds-core;bundle-version="[1.3,2)"</Fragment-Host>
|
||||
</instructions>
|
||||
</configuration>
|
||||
|
|
|
@ -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)))
|
|
@ -326,7 +326,7 @@ Here's an example of creating and running a small linux node in the group webser
|
|||
(make-option-map
|
||||
kw-memfn-1arg
|
||||
[: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-arch-matches :os-64-bit :image-name-matches
|
||||
:image-version-matches :image-description-matches :image-matches
|
||||
|
|
|
@ -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.exec;
|
||||
import static org.jclouds.scriptbuilder.domain.Statements.interpret;
|
||||
import static org.jclouds.scriptbuilder.domain.Statements.newStatementList;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
|
||||
import org.jclouds.compute.domain.OperatingSystem;
|
||||
import org.jclouds.compute.predicates.OperatingSystemPredicates;
|
||||
import org.jclouds.scriptbuilder.InitBuilder;
|
||||
import org.jclouds.scriptbuilder.InitScript;
|
||||
import org.jclouds.scriptbuilder.domain.Statement;
|
||||
import org.jclouds.scriptbuilder.domain.StatementList;
|
||||
import org.jclouds.scriptbuilder.statements.java.InstallJDK;
|
||||
import org.jclouds.scriptbuilder.statements.login.AdminAccess;
|
||||
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableList.Builder;
|
||||
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 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",//
|
||||
"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 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) {
|
||||
Builder<Statement> builder = ImmutableList.<Statement> builder();
|
||||
for (int port : ports)
|
||||
|
@ -76,7 +61,7 @@ public class RunScriptData {
|
|||
public static StatementList installAdminUserJBossAndOpenPorts(OperatingSystem os) throws IOException {
|
||||
return new StatementList(//
|
||||
AdminAccess.builder().adminUsername("web").build(),//
|
||||
installJavaAndCurl(os),//
|
||||
InstallJDK.fromURL(),//
|
||||
authorizePortsInIpTables(22, 8080),//
|
||||
extractTargzIntoDirectory(JBOSS7_URL, "/usr/local"),//
|
||||
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!
|
||||
public static InitBuilder startJBoss(String configuration) {
|
||||
return new InitBuilder(
|
||||
"jboss",
|
||||
JBOSS_HOME,
|
||||
JBOSS_HOME,
|
||||
ImmutableMap.of("jbossHome", JBOSS_HOME),
|
||||
ImmutableList.<Statement>of(appendFile(JBOSS_HOME + "/standalone/configuration/standalone-custom.xml", Splitter.on('\n').split(configuration))),
|
||||
ImmutableList
|
||||
.<Statement> of(interpret(new StringBuilder().append("java ").append(' ')
|
||||
public static InitScript startJBoss(String configuration) {
|
||||
return InitScript.builder()
|
||||
.name("jboss")
|
||||
.home(JBOSS_HOME)
|
||||
.exportVariables(ImmutableMap.of("jbossHome", JBOSS_HOME))
|
||||
.init(appendFile(JBOSS_HOME + "/standalone/configuration/standalone-custom.xml", Splitter.on('\n').split(configuration)))
|
||||
.run(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("-Djboss.modules.system.pkgs=org.jboss.byteman").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("-Djboss.home.dir=$JBOSS_HOME").append(' ')
|
||||
.append("--server-config=standalone-custom.xml")
|
||||
.toString())));
|
||||
}
|
||||
|
||||
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");
|
||||
.toString())).build();
|
||||
}
|
||||
|
||||
// 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)",
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ package org.jclouds.compute.callables;
|
|||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.concurrent.CancellationException;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
@ -30,22 +31,28 @@ import javax.annotation.Resource;
|
|||
|
||||
import org.jclouds.Constants;
|
||||
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.reference.ComputeServiceConstants;
|
||||
import org.jclouds.logging.Logger;
|
||||
import org.jclouds.predicates.RetryablePredicate;
|
||||
import org.jclouds.scriptbuilder.InitBuilder;
|
||||
import org.jclouds.scriptbuilder.InitScript;
|
||||
import org.jclouds.ssh.SshClient;
|
||||
|
||||
import com.google.common.base.Objects;
|
||||
import com.google.common.base.Predicate;
|
||||
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.inject.Inject;
|
||||
import com.google.inject.assistedinject.Assisted;
|
||||
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
|
||||
*/
|
||||
|
@ -60,23 +67,31 @@ public class BlockUntilInitScriptStatusIsZeroThenReturnOutput extends AbstractFu
|
|||
protected Logger logger = Logger.NULL;
|
||||
|
||||
private final ExecutorService userThreads;
|
||||
private final EventBus eventBus;
|
||||
private final SudoAwareInitManager commandRunner;
|
||||
private final RetryablePredicate<String> notRunningAnymore;
|
||||
|
||||
private boolean shouldCancel;
|
||||
public SudoAwareInitManager getCommandRunner() {
|
||||
return commandRunner;
|
||||
}
|
||||
|
||||
private final RetryablePredicate<String> notRunningAnymore;
|
||||
|
||||
@Inject
|
||||
public BlockUntilInitScriptStatusIsZeroThenReturnOutput(
|
||||
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService userThreads,
|
||||
ComputeServiceConstants.InitStatusProperties properties,
|
||||
final ScriptStatusReturnsZero stateRunning, @Assisted final SudoAwareInitManager commandRunner) {
|
||||
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService userThreads, EventBus eventBus,
|
||||
ComputeServiceConstants.InitStatusProperties properties, final ScriptStatusReturnsZero stateRunning,
|
||||
@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 retryMaxPeriod = properties.initStatusMaxPeriod;
|
||||
|
||||
this.commandRunner = checkNotNull(commandRunner, "commandRunner");
|
||||
this.userThreads = checkNotNull(userThreads, "userThreads");
|
||||
this.eventBus = checkNotNull(eventBus, "eventBus");
|
||||
this.notRunningAnymore = new RetryablePredicate<String>(new Predicate<String>() {
|
||||
|
||||
@Override
|
||||
|
@ -85,13 +100,13 @@ public class BlockUntilInitScriptStatusIsZeroThenReturnOutput extends AbstractFu
|
|||
}
|
||||
}, retryMaxWait, retryInitialPeriod, retryMaxPeriod, TimeUnit.MILLISECONDS) {
|
||||
/**
|
||||
* make sure we stop the retry loop if someone cancelled the future, this keeps threads
|
||||
* from being consumed on dead tasks
|
||||
* make sure we stop the retry loop if someone cancelled the future,
|
||||
* this keeps threads from being consumed on dead tasks
|
||||
*/
|
||||
@Override
|
||||
protected boolean atOrAfter(Date end) {
|
||||
if (shouldCancel)
|
||||
Throwables.propagate(new TimeoutException("cancelled"));
|
||||
if (isCancelled())
|
||||
Throwables.propagate(new CancellationException("cancelled"));
|
||||
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
|
||||
* place
|
||||
* Submits a thread that will either set the result of the future or the
|
||||
* exception that took place
|
||||
*/
|
||||
public BlockUntilInitScriptStatusIsZeroThenReturnOutput init() {
|
||||
userThreads.submit(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
boolean complete = notRunningAnymore.apply("status");
|
||||
String stdout = commandRunner.runAction("tail").getOutput();
|
||||
String stderr = commandRunner.runAction("tailerr").getOutput();
|
||||
// TODO make ScriptBuilder save exit status on nuhup
|
||||
logger.debug("<< complete(%s) status(%s)", commandRunner.getStatement().getInstanceName(), complete);
|
||||
set(new ExecResponse(stdout, stderr, complete && !shouldCancel ? 0 : -1));
|
||||
notRunningAnymore.apply("status");
|
||||
String stdout = commandRunner.runAction("stdout").getOutput();
|
||||
String stderr = commandRunner.runAction("stderr").getOutput();
|
||||
Integer exitStatus = Ints.tryParse(commandRunner.runAction("exitstatus").getOutput().trim());
|
||||
ExecResponse exec = new ExecResponse(stdout, stderr, exitStatus == null ? -1 : exitStatus);
|
||||
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) {
|
||||
setException(e);
|
||||
}
|
||||
|
@ -127,63 +150,43 @@ public class BlockUntilInitScriptStatusIsZeroThenReturnOutput extends AbstractFu
|
|||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean set(ExecResponse value) {
|
||||
eventBus.post(new StatementOnNodeCompletion(getCommandRunner().getStatement(), getCommandRunner().getNode(),
|
||||
value));
|
||||
return super.set(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void interruptTask() {
|
||||
logger.debug("<< cancelled(%s)", commandRunner.getStatement().getInstanceName());
|
||||
commandRunner.refreshAndRunAction("stop");
|
||||
shouldCancel = true;
|
||||
ExecResponse returnVal = commandRunner.refreshAndRunAction("stop");
|
||||
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();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("running task[%s]", commandRunner);
|
||||
return Objects.toStringHelper(this).add("commandRunner", commandRunner).toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
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;
|
||||
return Objects.hashCode(commandRunner);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
public boolean equals(Object o) {
|
||||
if (o == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
if (!o.getClass().equals(getClass()))
|
||||
return false;
|
||||
BlockUntilInitScriptStatusIsZeroThenReturnOutput other = (BlockUntilInitScriptStatusIsZeroThenReturnOutput) obj;
|
||||
if (commandRunner == null) {
|
||||
if (other.commandRunner != null)
|
||||
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;
|
||||
BlockUntilInitScriptStatusIsZeroThenReturnOutput that = BlockUntilInitScriptStatusIsZeroThenReturnOutput.class
|
||||
.cast(o);
|
||||
return Objects.equal(this.commandRunner, that.commandRunner);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -192,7 +195,9 @@ public class BlockUntilInitScriptStatusIsZeroThenReturnOutput extends AbstractFu
|
|||
try {
|
||||
return super.get(timeout, unit);
|
||||
} catch (TimeoutException e) {
|
||||
throw new ScriptStillRunningException(timeout, unit, this);
|
||||
ScriptStillRunningException exception = new ScriptStillRunningException(timeout, unit, this);
|
||||
exception.initCause(e);
|
||||
throw exception;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||
import javax.inject.Named;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.jclouds.scriptbuilder.InitBuilder;
|
||||
import org.jclouds.scriptbuilder.InitScript;
|
||||
|
||||
import com.google.common.base.Supplier;
|
||||
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
|
||||
* the basedir/%s where %s is the taskName
|
||||
* @see InitBuilder#getHomeDir
|
||||
* @see InitBuilder#getLogDir
|
||||
* @see InitScript#getHomeDir
|
||||
* @see InitScript#getLogDir
|
||||
*/
|
||||
public String getInitScriptPattern() {
|
||||
return initScriptPattern;
|
||||
|
|
|
@ -21,19 +21,15 @@ package org.jclouds.compute.callables;
|
|||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
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.NodeMetadata;
|
||||
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.reference.ComputeServiceConstants;
|
||||
import org.jclouds.domain.LoginCredentials;
|
||||
import org.jclouds.logging.Logger;
|
||||
import org.jclouds.scriptbuilder.InitBuilder;
|
||||
import org.jclouds.scriptbuilder.InitScript;
|
||||
import org.jclouds.scriptbuilder.domain.AdminAccessVisitor;
|
||||
import org.jclouds.scriptbuilder.domain.AppendFile;
|
||||
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.Splitter;
|
||||
import com.google.common.base.Throwables;
|
||||
import com.google.common.eventbus.EventBus;
|
||||
import com.google.inject.assistedinject.Assisted;
|
||||
import com.google.inject.assistedinject.AssistedInject;
|
||||
|
||||
|
@ -53,28 +51,18 @@ import com.google.inject.assistedinject.AssistedInject;
|
|||
* @author Adrian Cole
|
||||
*/
|
||||
public class RunScriptOnNodeAsInitScriptUsingSsh extends SudoAwareInitManager implements RunScriptOnNode {
|
||||
@Resource
|
||||
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
|
||||
protected Logger logger = Logger.NULL;
|
||||
|
||||
protected final String initFile;
|
||||
|
||||
/**
|
||||
* @return the absolute path to the file on disk relating to this task.
|
||||
*/
|
||||
public String getInitFile() {
|
||||
return initFile;
|
||||
}
|
||||
protected final EventBus eventBus;
|
||||
|
||||
@AssistedInject
|
||||
public RunScriptOnNodeAsInitScriptUsingSsh(Function<NodeMetadata, SshClient> sshFactory,
|
||||
public RunScriptOnNodeAsInitScriptUsingSsh(Function<NodeMetadata, SshClient> sshFactory, EventBus eventBus,
|
||||
InitScriptConfigurationForTasks initScriptConfiguration, @Assisted NodeMetadata node,
|
||||
@Assisted Statement script, @Assisted RunScriptOptions options) {
|
||||
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
|
||||
.getTaskName(), script));
|
||||
this.initFile = String.format(initScriptConfiguration.getInitScriptPattern(), init.getInstanceName());
|
||||
this.eventBus = checkNotNull(eventBus, "eventBus");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -88,19 +76,20 @@ public class RunScriptOnNodeAsInitScriptUsingSsh extends SudoAwareInitManager im
|
|||
checkState(ssh != null, "please call init() before invoking call");
|
||||
try {
|
||||
ssh.connect();
|
||||
return doCall();
|
||||
ExecResponse returnVal = doCall();
|
||||
eventBus.post(new StatementOnNodeCompletion(init, node, returnVal));
|
||||
return returnVal;
|
||||
} finally {
|
||||
if (ssh != null)
|
||||
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) {
|
||||
name = "jclouds-script-" + config.getAnonymousTaskSuffixSupplier().get();
|
||||
}
|
||||
return new InitBuilder(name, config.getBasedir() + "/" + name, config.getBasedir() + "/" + name, Collections
|
||||
.<String, String> emptyMap(), Collections.singleton(script));
|
||||
return InitScript.builder().name(name).home(config.getBasedir() + "/" + name).run(script).build();
|
||||
}
|
||||
|
||||
protected void refreshSshIfNewAdminCredentialsConfigured(AdminAccess input) {
|
||||
|
@ -115,10 +104,13 @@ public class RunScriptOnNodeAsInitScriptUsingSsh extends SudoAwareInitManager im
|
|||
}
|
||||
|
||||
protected ExecResponse doCall() {
|
||||
eventBus.post(new InitScriptOnNodeSubmission(init, node));
|
||||
try {
|
||||
try {
|
||||
ssh.put(initFile, init.render(OsFamily.UNIX));
|
||||
} 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())
|
||||
logger.warn(e, "<< (%s) problem using sftp [%s], attempting via sshexec", ssh.toString(), e.getMessage());
|
||||
else
|
||||
|
@ -127,7 +119,7 @@ public class RunScriptOnNodeAsInitScriptUsingSsh extends SudoAwareInitManager im
|
|||
ssh.connect();
|
||||
ssh.exec("rm " + initFile);
|
||||
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);
|
||||
|
@ -143,6 +135,10 @@ public class RunScriptOnNodeAsInitScriptUsingSsh extends SudoAwareInitManager im
|
|||
|
||||
});
|
||||
return runAction("start");
|
||||
} catch (Throwable e) {
|
||||
eventBus.post(new StatementOnNodeFailure(init, node, e));
|
||||
throw Throwables.propagate(e);
|
||||
}
|
||||
}
|
||||
|
||||
protected void setupLinkToInitFile() {
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
package org.jclouds.compute.callables;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
|
@ -27,6 +26,7 @@ import javax.inject.Inject;
|
|||
|
||||
import org.jclouds.compute.domain.ExecResponse;
|
||||
import org.jclouds.compute.domain.NodeMetadata;
|
||||
import org.jclouds.compute.events.StatementOnNodeFailure;
|
||||
import org.jclouds.compute.options.RunScriptOptions;
|
||||
import org.jclouds.compute.reference.ComputeServiceConstants.Timeouts;
|
||||
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.Throwables;
|
||||
import com.google.common.eventbus.EventBus;
|
||||
import com.google.inject.assistedinject.Assisted;
|
||||
|
||||
/**
|
||||
|
@ -47,9 +48,10 @@ public class RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilComplete extends Ru
|
|||
@Inject
|
||||
public RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilComplete(
|
||||
BlockUntilInitScriptStatusIsZeroThenReturnOutput.Factory statusFactory, Timeouts timeouts,
|
||||
Function<NodeMetadata, SshClient> sshFactory, InitScriptConfigurationForTasks initScriptConfiguration,
|
||||
@Assisted NodeMetadata node, @Assisted Statement script, @Assisted RunScriptOptions options) {
|
||||
super(sshFactory, initScriptConfiguration, node, script, options);
|
||||
Function<NodeMetadata, SshClient> sshFactory, EventBus eventBus,
|
||||
InitScriptConfigurationForTasks initScriptConfiguration, @Assisted NodeMetadata node,
|
||||
@Assisted Statement script, @Assisted RunScriptOptions options) {
|
||||
super(sshFactory, eventBus, initScriptConfiguration, node, script, options);
|
||||
this.statusFactory = checkNotNull(statusFactory, "statusFactory");
|
||||
this.timeouts = checkNotNull(timeouts, "timeouts");
|
||||
}
|
||||
|
@ -58,16 +60,21 @@ public class RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilComplete extends Ru
|
|||
public ExecResponse doCall() {
|
||||
try {
|
||||
return future().get(timeouts.scriptComplete, TimeUnit.MILLISECONDS);
|
||||
} catch (Exception e) {
|
||||
Throwables.propagate(e);
|
||||
return null;
|
||||
} catch (Throwable e) {
|
||||
eventBus.post(new StatementOnNodeFailure(init, node, e));
|
||||
throw Throwables.propagate(e);
|
||||
}
|
||||
}
|
||||
|
||||
public BlockUntilInitScriptStatusIsZeroThenReturnOutput future() {
|
||||
ExecResponse returnVal = super.doCall();
|
||||
checkState(returnVal.getExitCode() == 0, String.format("task: %s had non-zero exit status: %s", init
|
||||
.getInstanceName(), returnVal));
|
||||
if (returnVal.getExitStatus() != 0) {
|
||||
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();
|
||||
}
|
||||
|
||||
|
|
|
@ -26,6 +26,9 @@ import javax.inject.Named;
|
|||
|
||||
import org.jclouds.compute.domain.ExecResponse;
|
||||
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.reference.ComputeServiceConstants;
|
||||
import org.jclouds.logging.Logger;
|
||||
|
@ -36,6 +39,8 @@ import org.jclouds.ssh.SshClient;
|
|||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Function;
|
||||
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.AssistedInject;
|
||||
|
||||
|
@ -51,6 +56,7 @@ public class RunScriptOnNodeUsingSsh implements RunScriptOnNode {
|
|||
protected Logger logger = Logger.NULL;
|
||||
|
||||
protected final Function<NodeMetadata, SshClient> sshFactory;
|
||||
protected final EventBus eventBus;
|
||||
protected final NodeMetadata node;
|
||||
protected final Statement statement;
|
||||
protected final boolean runAsRoot;
|
||||
|
@ -58,9 +64,10 @@ public class RunScriptOnNodeUsingSsh implements RunScriptOnNode {
|
|||
protected SshClient ssh;
|
||||
|
||||
@AssistedInject
|
||||
public RunScriptOnNodeUsingSsh(Function<NodeMetadata, SshClient> sshFactory, @Assisted NodeMetadata node,
|
||||
@Assisted Statement statement, @Assisted RunScriptOptions options) {
|
||||
public RunScriptOnNodeUsingSsh(Function<NodeMetadata, SshClient> sshFactory, EventBus eventBus,
|
||||
@Assisted NodeMetadata node, @Assisted Statement statement, @Assisted RunScriptOptions options) {
|
||||
this.sshFactory = checkNotNull(sshFactory, "sshFactory");
|
||||
this.eventBus = checkNotNull(eventBus, "eventBus");
|
||||
this.node = checkNotNull(node, "node");
|
||||
this.statement = checkNotNull(statement, "statement");
|
||||
this.runAsRoot = options.shouldRunAsRoot();
|
||||
|
@ -72,13 +79,20 @@ public class RunScriptOnNodeUsingSsh implements RunScriptOnNode {
|
|||
try {
|
||||
ssh.connect();
|
||||
ExecResponse returnVal;
|
||||
eventBus.post(new StatementOnNodeSubmission(statement, node));
|
||||
String command = (runAsRoot) ? execAsRoot(statement.render(OsFamily.UNIX)) : execScriptAsDefaultUser(statement
|
||||
.render(OsFamily.UNIX));
|
||||
try {
|
||||
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())
|
||||
logger.trace("<< %s[%s]", statement, returnVal);
|
||||
else
|
||||
logger.debug("<< %s(%d)", statement, returnVal.getExitCode());
|
||||
logger.debug("<< %s(%d)", statement, returnVal.getExitStatus());
|
||||
return returnVal;
|
||||
} finally {
|
||||
if (ssh != null)
|
||||
|
|
|
@ -28,7 +28,7 @@ import org.jclouds.compute.domain.ExecResponse;
|
|||
import org.jclouds.compute.domain.NodeMetadata;
|
||||
import org.jclouds.compute.reference.ComputeServiceConstants;
|
||||
import org.jclouds.logging.Logger;
|
||||
import org.jclouds.scriptbuilder.InitBuilder;
|
||||
import org.jclouds.scriptbuilder.InitScript;
|
||||
import org.jclouds.ssh.SshClient;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
|
@ -47,16 +47,25 @@ public class SudoAwareInitManager {
|
|||
protected Logger computeLogger = Logger.NULL;
|
||||
protected Logger logger = Logger.NULL;
|
||||
protected NodeMetadata node;
|
||||
protected final InitBuilder init;
|
||||
protected final String initFile;
|
||||
protected final InitScript init;
|
||||
protected final boolean runAsRoot;
|
||||
protected final Function<NodeMetadata, SshClient> sshFactory;
|
||||
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,
|
||||
InitBuilder init) {
|
||||
InitScriptConfigurationForTasks initScriptConfiguration, InitScript init) {
|
||||
this.sshFactory = checkNotNull(sshFactory, "sshFactory");
|
||||
this.runAsRoot = runAsRoot;
|
||||
this.node = checkNotNull(node, "node");
|
||||
this.initFile = String.format(initScriptConfiguration.getInitScriptPattern(), init.getInstanceName());
|
||||
this.init = checkNotNull(init, "init");
|
||||
}
|
||||
|
||||
|
@ -82,41 +91,44 @@ public class SudoAwareInitManager {
|
|||
: execScriptAsDefaultUser(action);
|
||||
returnVal = runCommand(command);
|
||||
if ("status".equals(action))
|
||||
logger.trace("<< %s(%d)", action, returnVal.getExitCode());
|
||||
logger.trace("<< %s(%d)", action, returnVal.getExitStatus());
|
||||
else if (computeLogger.isTraceEnabled())
|
||||
computeLogger.trace("<< %s[%s]", action, returnVal);
|
||||
else
|
||||
computeLogger.debug("<< %s(%d)", action, returnVal.getExitCode());
|
||||
computeLogger.debug("<< %s(%d)", action, returnVal.getExitStatus());
|
||||
return returnVal;
|
||||
}
|
||||
|
||||
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
|
||||
.getUsername(), ssh.getHostAddress());
|
||||
if (command.endsWith("status"))
|
||||
logger.trace(statement);
|
||||
logger.trace(">> running " + statement);
|
||||
else
|
||||
computeLogger.debug(statement);
|
||||
return ssh.exec(command);
|
||||
computeLogger.debug(">> running " + statement);
|
||||
ExecResponse returnVal = ssh.exec(command);
|
||||
if (!command.endsWith("status"))
|
||||
checkState(returnVal.getExitStatus() == 0, "error running %s; returnVal !=0: %s", statement, returnVal);
|
||||
return returnVal;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
String execScriptAsRoot(String action) {
|
||||
String command;
|
||||
if (node.getCredentials().identity.equals("root")) {
|
||||
command = "./" + init.getInstanceName() + " " + action;
|
||||
command = initFile + " " + action;
|
||||
} else if (node.getCredentials().shouldAuthenticateSudo()) {
|
||||
command = String.format("echo '%s'|sudo -S ./%s %s", node.getCredentials().getPassword(),
|
||||
init.getInstanceName(), action);
|
||||
command = String.format("echo '%s'|sudo -S %s %s", node.getCredentials().getPassword(),
|
||||
initFile, action);
|
||||
} else {
|
||||
command = "sudo ./" + init.getInstanceName() + " " + action;
|
||||
command = "sudo " + initFile + " " + action;
|
||||
}
|
||||
return command;
|
||||
}
|
||||
|
||||
protected String execScriptAsDefaultUser(String action) {
|
||||
return "./" + init.getInstanceName() + " " + action;
|
||||
return initFile + " " + action;
|
||||
}
|
||||
|
||||
public NodeMetadata getNode() {
|
||||
|
@ -125,11 +137,11 @@ public class SudoAwareInitManager {
|
|||
|
||||
@Override
|
||||
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();
|
||||
}
|
||||
|
||||
public InitBuilder getStatement() {
|
||||
public InitScript getStatement() {
|
||||
return init;
|
||||
}
|
||||
}
|
|
@ -103,7 +103,7 @@ public abstract class BaseComputeServiceContextModule extends AbstractModule {
|
|||
|
||||
install(new FactoryModuleBuilder().implement(new TypeLiteral<Callable<Void>>() {
|
||||
}, CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap.class)
|
||||
.implement(new TypeLiteral<Function<NodeMetadata, Void>>() {
|
||||
.implement(new TypeLiteral<Function<AtomicReference<NodeMetadata>, Void>>() {
|
||||
}, CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap.class)
|
||||
.build(CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap.Factory.class));
|
||||
|
||||
|
|
|
@ -20,10 +20,13 @@ package org.jclouds.compute.config;
|
|||
|
||||
import static com.google.common.base.Predicates.not;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.jclouds.compute.domain.NodeMetadata;
|
||||
import org.jclouds.compute.predicates.AtomicNodeRunning;
|
||||
import org.jclouds.compute.predicates.NodeRunning;
|
||||
import org.jclouds.compute.predicates.NodeSuspended;
|
||||
import org.jclouds.compute.predicates.NodeTerminated;
|
||||
|
@ -46,6 +49,32 @@ public class ComputeServiceTimeoutsModule extends AbstractModule {
|
|||
@Provides
|
||||
@Singleton
|
||||
@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) {
|
||||
return timeouts.nodeRunning == 0 ? stateRunning : new RetryablePredicate<NodeMetadata>(stateRunning,
|
||||
timeouts.nodeRunning);
|
||||
|
@ -54,6 +83,7 @@ public class ComputeServiceTimeoutsModule extends AbstractModule {
|
|||
@Provides
|
||||
@Singleton
|
||||
@Named("NODE_TERMINATED")
|
||||
@Deprecated
|
||||
protected Predicate<NodeMetadata> serverTerminated(NodeTerminated stateTerminated, Timeouts timeouts) {
|
||||
return timeouts.nodeTerminated == 0 ? stateTerminated : new RetryablePredicate<NodeMetadata>(stateTerminated,
|
||||
timeouts.nodeTerminated);
|
||||
|
@ -63,6 +93,7 @@ public class ComputeServiceTimeoutsModule extends AbstractModule {
|
|||
@Provides
|
||||
@Singleton
|
||||
@Named("NODE_SUSPENDED")
|
||||
@Deprecated
|
||||
protected Predicate<NodeMetadata> serverSuspended(NodeSuspended stateSuspended, Timeouts timeouts) {
|
||||
return timeouts.nodeSuspended == 0 ? stateSuspended : new RetryablePredicate<NodeMetadata>(stateSuspended,
|
||||
timeouts.nodeSuspended);
|
||||
|
|
|
@ -20,19 +20,21 @@ package org.jclouds.compute.domain;
|
|||
|
||||
import org.jclouds.compute.config.CustomizationResponse;
|
||||
|
||||
import com.google.common.base.Objects;
|
||||
|
||||
/**
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class ExecResponse implements CustomizationResponse {
|
||||
|
||||
private final String error;
|
||||
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.error = error;
|
||||
this.exitCode = exitCode;
|
||||
this.exitStatus = exitStatus;
|
||||
}
|
||||
|
||||
public String getError() {
|
||||
|
@ -43,47 +45,38 @@ public class ExecResponse implements CustomizationResponse {
|
|||
return output;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[output=" + output + ", error=" + error + ", exitCode=" + exitCode + "]";
|
||||
/**
|
||||
* @see #getExitStatus
|
||||
*/
|
||||
@Deprecated
|
||||
public int getExitCode() {
|
||||
return exitStatus;
|
||||
}
|
||||
|
||||
public int getExitStatus() {
|
||||
return exitStatus;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
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;
|
||||
return Objects.hashCode(output, error, exitStatus);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
public boolean equals(Object o) {
|
||||
if (o == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
if (!o.getClass().equals(getClass()))
|
||||
return false;
|
||||
ExecResponse other = (ExecResponse) obj;
|
||||
if (error == null) {
|
||||
if (other.error != null)
|
||||
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;
|
||||
ExecResponse that = ExecResponse.class.cast(o);
|
||||
return Objects.equal(this.output, that.output) && Objects.equal(this.error, that.error)
|
||||
&& Objects.equal(this.exitStatus, that.exitStatus);
|
||||
}
|
||||
|
||||
public int getExitCode() {
|
||||
return exitCode;
|
||||
@Override
|
||||
public String toString() {
|
||||
return Objects.toStringHelper("").add("output", output).add("error", error).add("exitStatus", exitStatus)
|
||||
.toString();
|
||||
}
|
||||
|
||||
}
|
|
@ -69,6 +69,11 @@ public interface TemplateBuilder {
|
|||
*/
|
||||
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.
|
||||
*/
|
||||
|
|
|
@ -220,7 +220,6 @@ public class NodeMetadataImpl extends ComputeMetadataImpl implements NodeMetadat
|
|||
result = prime * result + ((imageId == null) ? 0 : imageId.hashCode());
|
||||
result = prime * result + ((hardware == null) ? 0 : hardware.hashCode());
|
||||
result = prime * result + ((os == null) ? 0 : os.hashCode());
|
||||
result = prime * result + ((credentials == null) ? 0 : credentials.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -270,11 +269,6 @@ public class NodeMetadataImpl extends ComputeMetadataImpl implements NodeMetadat
|
|||
return false;
|
||||
} else if (!os.equals(other.os))
|
||||
return false;
|
||||
if (credentials == null) {
|
||||
if (other.credentials != null)
|
||||
return false;
|
||||
} else if (!credentials.equals(other.credentials))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -89,6 +89,8 @@ public class TemplateBuilderImpl implements TemplateBuilder {
|
|||
@VisibleForTesting
|
||||
protected String hardwareId;
|
||||
@VisibleForTesting
|
||||
protected String hypervisor;
|
||||
@VisibleForTesting
|
||||
protected String imageVersion;
|
||||
@VisibleForTesting
|
||||
protected OsFamily osFamily;
|
||||
|
@ -347,12 +349,17 @@ public class TemplateBuilderImpl implements TemplateBuilder {
|
|||
return "imageDescription(" + imageDescription + ")";
|
||||
}
|
||||
};
|
||||
|
||||
private final Predicate<Hardware> hardwareIdPredicate = new Predicate<Hardware>() {
|
||||
@Override
|
||||
public boolean apply(Hardware input) {
|
||||
boolean returnVal = true;
|
||||
if (hardwareId != null) {
|
||||
returnVal = hardwareId.equals(input.getId());
|
||||
// match our input params so that the later predicates pass.
|
||||
if (returnVal) {
|
||||
fromHardware(input);
|
||||
}
|
||||
}
|
||||
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>() {
|
||||
@Override
|
||||
public boolean apply(Hardware input) {
|
||||
|
@ -406,6 +433,8 @@ public class TemplateBuilderImpl implements TemplateBuilder {
|
|||
return locationPredicate.toString();
|
||||
}
|
||||
});
|
||||
if (hypervisor != null)
|
||||
predicates.add(hypervisorPredicate);
|
||||
predicates.add(hardwareCoresPredicate);
|
||||
predicates.add(hardwareRamPredicate);
|
||||
}
|
||||
|
@ -466,6 +495,7 @@ public class TemplateBuilderImpl implements TemplateBuilder {
|
|||
this.location = hardware.getLocation();
|
||||
this.minCores = getCores(hardware);
|
||||
this.minRam = hardware.getRam();
|
||||
this.hypervisor = hardware.getHypervisor();
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -901,6 +931,16 @@ public class TemplateBuilderImpl implements TemplateBuilder {
|
|||
@Override
|
||||
public TemplateBuilder hardwareId(String hardwareId) {
|
||||
this.hardwareId = hardwareId;
|
||||
this.hypervisor = null;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public TemplateBuilder hypervisorMatches(String hypervisor) {
|
||||
this.hypervisor = hypervisor;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -916,10 +956,10 @@ public class TemplateBuilderImpl implements TemplateBuilder {
|
|||
|
||||
@VisibleForTesting
|
||||
boolean nothingChangedExceptOptions() {
|
||||
return osFamily == null && location == null && imageId == null && hardwareId == null && osName == null
|
||||
&& imagePredicate == null && osDescription == null && imageVersion == null && osVersion == null
|
||||
&& osArch == null && os64Bit == null && imageName == null && imageDescription == null && minCores == 0
|
||||
&& minRam == 0 && !biggest && !fastest;
|
||||
return osFamily == null && location == null && imageId == null && hardwareId == null && hypervisor == null
|
||||
&& osName == null && imagePredicate == null && osDescription == null && imageVersion == null
|
||||
&& osVersion == null && osArch == null && os64Bit == null && imageName == null && imageDescription == null
|
||||
&& minCores == 0 && minRam == 0 && !biggest && !fastest;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -936,7 +976,7 @@ public class TemplateBuilderImpl implements TemplateBuilder {
|
|||
+ imageDescription + ", imageId=" + imageId + ", imagePredicate=" + imagePredicate + ", imageVersion=" + imageVersion + ", location=" + location
|
||||
+ ", minCores=" + minCores + ", minRam=" + minRam + ", osFamily=" + osFamily + ", osName=" + osName
|
||||
+ ", osDescription=" + osDescription + ", osVersion=" + osVersion + ", osArch=" + osArch + ", os64Bit="
|
||||
+ os64Bit + ", hardwareId=" + hardwareId + "]";
|
||||
+ os64Bit + ", hardwareId=" + hardwareId + ", hypervisor=" + hypervisor + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -25,7 +25,7 @@ import java.util.List;
|
|||
import javax.inject.Singleton;
|
||||
|
||||
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.StatementList;
|
||||
import org.jclouds.scriptbuilder.statements.ssh.AuthorizeRSAPublicKeys;
|
||||
|
@ -51,7 +51,7 @@ public class TemplateOptionsToStatement implements Function<TemplateOptions, Sta
|
|||
if (options.getPrivateKey() != null)
|
||||
bootstrap.add(new InstallRSAPrivateKey(options.getPrivateKey()));
|
||||
if (bootstrap.size() >= 1) {
|
||||
if (options.getTaskName() == null && !(options.getRunScript() instanceof InitBuilder))
|
||||
if (options.getTaskName() == null && !(options.getRunScript() instanceof InitScript))
|
||||
options.nameTask("bootstrap");
|
||||
return bootstrap.size() == 1 ? bootstrap.get(0) : new StatementList(bootstrap);
|
||||
}
|
||||
|
|
|
@ -125,9 +125,9 @@ public class BaseComputeService implements ComputeService {
|
|||
private final SuspendNodeStrategy suspendNodeStrategy;
|
||||
private final Provider<TemplateBuilder> templateBuilderProvider;
|
||||
private final Provider<TemplateOptions> templateOptionsProvider;
|
||||
private final Predicate<NodeMetadata> nodeRunning;
|
||||
private final Predicate<NodeMetadata> nodeTerminated;
|
||||
private final Predicate<NodeMetadata> nodeSuspended;
|
||||
private final Predicate<AtomicReference<NodeMetadata>> nodeRunning;
|
||||
private final Predicate<AtomicReference<NodeMetadata>> nodeTerminated;
|
||||
private final Predicate<AtomicReference<NodeMetadata>> nodeSuspended;
|
||||
private final InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory;
|
||||
private final Timeouts timeouts;
|
||||
private final InitAdminAccess initAdminAccess;
|
||||
|
@ -143,9 +143,9 @@ public class BaseComputeService implements ComputeService {
|
|||
RebootNodeStrategy rebootNodeStrategy, DestroyNodeStrategy destroyNodeStrategy,
|
||||
ResumeNodeStrategy resumeNodeStrategy, SuspendNodeStrategy suspendNodeStrategy,
|
||||
Provider<TemplateBuilder> templateBuilderProvider, Provider<TemplateOptions> templateOptionsProvider,
|
||||
@Named("NODE_RUNNING") Predicate<NodeMetadata> nodeRunning,
|
||||
@Named("NODE_TERMINATED") Predicate<NodeMetadata> nodeTerminated,
|
||||
@Named("NODE_SUSPENDED") Predicate<NodeMetadata> nodeSuspended,
|
||||
@Named("NODE_RUNNING") Predicate<AtomicReference<NodeMetadata>> nodeRunning,
|
||||
@Named("NODE_TERMINATED") Predicate<AtomicReference<NodeMetadata>> nodeTerminated,
|
||||
@Named("NODE_SUSPENDED") Predicate<AtomicReference<NodeMetadata>> nodeSuspended,
|
||||
InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory, InitAdminAccess initAdminAccess,
|
||||
RunScriptOnNode.Factory runScriptOnNodeFactory, PersistNodeCredentials persistNodeCredentials,
|
||||
Timeouts timeouts, @Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor) {
|
||||
|
@ -285,7 +285,7 @@ public class BaseComputeService implements ComputeService {
|
|||
|
||||
}, 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)
|
||||
credentialStore.remove("node#" + id);
|
||||
logger.debug("<< destroyed node(%s) success(%s)", id, successful);
|
||||
|
@ -383,7 +383,7 @@ public class BaseComputeService implements ComputeService {
|
|||
public void rebootNode(String id) {
|
||||
checkNotNull(id, "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);
|
||||
logger.debug("<< rebooted node(%s) success(%s)", id, successful);
|
||||
}
|
||||
|
@ -414,7 +414,7 @@ public class BaseComputeService implements ComputeService {
|
|||
public void resumeNode(String id) {
|
||||
checkNotNull(id, "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);
|
||||
logger.debug("<< resumed node(%s) success(%s)", id, successful);
|
||||
}
|
||||
|
@ -445,7 +445,7 @@ public class BaseComputeService implements ComputeService {
|
|||
public void suspendNode(String id) {
|
||||
checkNotNull(id, "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);
|
||||
logger.debug("<< suspended node(%s) success(%s)", id, successful);
|
||||
}
|
||||
|
|
|
@ -37,6 +37,7 @@ import org.jclouds.ssh.SshClient;
|
|||
import org.jclouds.ssh.SshClient.Factory;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.eventbus.EventBus;
|
||||
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;
|
||||
|
||||
@Inject
|
||||
UtilsImpl(Injector injector, Json json, HttpClient simpleClient, HttpAsyncClient simpleAsyncClient, Crypto encryption,
|
||||
DateService date, @Named(Constants.PROPERTY_USER_THREADS) ExecutorService userThreads,
|
||||
@Named(Constants.PROPERTY_IO_WORKER_THREADS) ExecutorService ioThreads, LoggerFactory loggerFactory,
|
||||
Function<NodeMetadata, SshClient> sshForNode) {
|
||||
super(injector, json, simpleClient, simpleAsyncClient, encryption, date, userThreads, ioThreads, loggerFactory);
|
||||
UtilsImpl(Injector injector, Json json, HttpClient simpleClient, HttpAsyncClient simpleAsyncClient,
|
||||
Crypto encryption, DateService date, @Named(Constants.PROPERTY_USER_THREADS) ExecutorService userThreads,
|
||||
@Named(Constants.PROPERTY_IO_WORKER_THREADS) ExecutorService ioThreads, EventBus eventBus,
|
||||
LoggerFactory loggerFactory, Function<NodeMetadata, SshClient> sshForNode) {
|
||||
super(injector, json, simpleClient, simpleAsyncClient, encryption, date, userThreads, ioThreads, eventBus,
|
||||
loggerFactory);
|
||||
this.sshForNode = sshForNode;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -39,7 +39,9 @@ import com.google.inject.Inject;
|
|||
* Tests to see if a node is active.
|
||||
*
|
||||
* @author Adrian Cole
|
||||
* @see RefreshAndDoubleCheckOnFailUnlessStateInvalid
|
||||
*/
|
||||
@Deprecated
|
||||
@Singleton
|
||||
public class NodePresentAndInIntendedState implements Predicate<NodeMetadata> {
|
||||
|
||||
|
|
|
@ -31,8 +31,10 @@ import com.google.inject.Inject;
|
|||
* Tests to see if a node is running.
|
||||
*
|
||||
* @author Adrian Cole
|
||||
* @see AtomicNodeRunning
|
||||
*/
|
||||
@Singleton
|
||||
@Deprecated
|
||||
public class NodeRunning extends NodePresentAndInIntendedState {
|
||||
|
||||
@Inject
|
||||
|
|
|
@ -30,8 +30,10 @@ import com.google.inject.Inject;
|
|||
* Tests to see if a node is suspended.
|
||||
*
|
||||
* @author Adrian Cole
|
||||
* @see AtomicNodeSuspended
|
||||
*/
|
||||
@Singleton
|
||||
@Deprecated
|
||||
public class NodeSuspended extends NodePresentAndInIntendedState {
|
||||
|
||||
@Inject
|
||||
|
|
|
@ -36,8 +36,10 @@ import com.google.inject.Inject;
|
|||
* Tests to see if a node is deleted
|
||||
*
|
||||
* @author Adrian Cole
|
||||
* @see TrueIfNullOrTerminatedRefreshAndDoubleCheckOnFalse
|
||||
*/
|
||||
@Singleton
|
||||
@Deprecated
|
||||
public class NodeTerminated implements Predicate<NodeMetadata> {
|
||||
|
||||
private final GetNodeMetadataStrategy client;
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -44,11 +44,11 @@ public class ScriptStatusReturnsZero implements Predicate<ScriptStatusReturnsZer
|
|||
logger.trace("looking for [%s] state on %s@%s", commandUsingClient.command, commandUsingClient.client
|
||||
.getUsername(), commandUsingClient.client.getHostAddress());
|
||||
ExecResponse response = refresh(commandUsingClient);
|
||||
while (response.getExitCode() == -1)
|
||||
while (response.getExitStatus() == -1)
|
||||
response = refresh(commandUsingClient);
|
||||
logger.trace("%s@%s: looking for exit code 0: currently: %s", commandUsingClient.client.getUsername(),
|
||||
commandUsingClient.client.getHostAddress(), response.getExitCode());
|
||||
return 0 == response.getExitCode();
|
||||
commandUsingClient.client.getHostAddress(), response.getExitStatus());
|
||||
return 0 == response.getExitStatus();
|
||||
}
|
||||
|
||||
private ExecResponse refresh(CommandUsingClient commandUsingClient) {
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -27,8 +27,8 @@ import static org.jclouds.compute.util.ComputeServiceUtils.findReachableSocketOn
|
|||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import org.jclouds.javax.annotation.Nullable;
|
||||
import javax.annotation.Resource;
|
||||
import javax.inject.Named;
|
||||
|
||||
|
@ -41,6 +41,7 @@ import org.jclouds.compute.options.TemplateOptions;
|
|||
import org.jclouds.compute.predicates.RetryIfSocketNotYetOpen;
|
||||
import org.jclouds.compute.reference.ComputeServiceConstants;
|
||||
import org.jclouds.compute.reference.ComputeServiceConstants.Timeouts;
|
||||
import org.jclouds.javax.annotation.Nullable;
|
||||
import org.jclouds.logging.Logger;
|
||||
import org.jclouds.scriptbuilder.domain.Statement;
|
||||
|
||||
|
@ -55,31 +56,28 @@ import com.google.inject.assistedinject.AssistedInject;
|
|||
* @author Adrian Cole
|
||||
*/
|
||||
public class CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap implements Callable<Void>,
|
||||
Function<NodeMetadata, Void> {
|
||||
Function<AtomicReference<NodeMetadata>, Void> {
|
||||
public static interface Factory {
|
||||
Callable<Void> create(TemplateOptions options, NodeMetadata node, Set<NodeMetadata> goodNodes,
|
||||
Map<NodeMetadata, Exception> badNodes,
|
||||
Multimap<NodeMetadata, CustomizationResponse> customizationResponses);
|
||||
Callable<Void> create(TemplateOptions options, AtomicReference<NodeMetadata> node, Set<NodeMetadata> goodNodes,
|
||||
Map<NodeMetadata, Exception> badNodes, Multimap<NodeMetadata, CustomizationResponse> customizationResponses);
|
||||
|
||||
Function<NodeMetadata, Void> create(TemplateOptions options, Set<NodeMetadata> goodNodes,
|
||||
Map<NodeMetadata, Exception> badNodes,
|
||||
Multimap<NodeMetadata, CustomizationResponse> customizationResponses);
|
||||
Function<AtomicReference<NodeMetadata>, Void> create(TemplateOptions options, Set<NodeMetadata> goodNodes,
|
||||
Map<NodeMetadata, Exception> badNodes, Multimap<NodeMetadata, CustomizationResponse> customizationResponses);
|
||||
}
|
||||
|
||||
@Resource
|
||||
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
|
||||
protected Logger logger = Logger.NULL;
|
||||
|
||||
private final Predicate<NodeMetadata> nodeRunning;
|
||||
private final Predicate<AtomicReference<NodeMetadata>> nodeRunning;
|
||||
private final InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory;
|
||||
private final GetNodeMetadataStrategy getNode;
|
||||
private final RetryIfSocketNotYetOpen socketTester;
|
||||
private final Timeouts timeouts;
|
||||
|
||||
@Nullable
|
||||
private final Statement statement;
|
||||
private final TemplateOptions options;
|
||||
private NodeMetadata node;
|
||||
private AtomicReference<NodeMetadata> node;
|
||||
private final Set<NodeMetadata> goodNodes;
|
||||
private final Map<NodeMetadata, Exception> badNodes;
|
||||
private final Multimap<NodeMetadata, CustomizationResponse> customizationResponses;
|
||||
|
@ -88,18 +86,17 @@ public class CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap implements Cal
|
|||
|
||||
@AssistedInject
|
||||
public CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap(
|
||||
@Named("NODE_RUNNING") Predicate<NodeMetadata> nodeRunning, GetNodeMetadataStrategy getNode,
|
||||
@Named("NODE_RUNNING") Predicate<AtomicReference<NodeMetadata>> nodeRunning,
|
||||
RetryIfSocketNotYetOpen socketTester, Timeouts timeouts,
|
||||
Function<TemplateOptions, Statement> templateOptionsToStatement,
|
||||
InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory,
|
||||
@Assisted TemplateOptions options, @Assisted @Nullable NodeMetadata node,
|
||||
@Assisted Set<NodeMetadata> goodNodes, @Assisted Map<NodeMetadata, Exception> badNodes,
|
||||
InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory, @Assisted TemplateOptions options,
|
||||
@Assisted AtomicReference<NodeMetadata> node, @Assisted Set<NodeMetadata> goodNodes,
|
||||
@Assisted Map<NodeMetadata, Exception> badNodes,
|
||||
@Assisted Multimap<NodeMetadata, CustomizationResponse> customizationResponses) {
|
||||
this.statement = checkNotNull(templateOptionsToStatement, "templateOptionsToStatement").apply(
|
||||
checkNotNull(options, "options"));
|
||||
this.nodeRunning = checkNotNull(nodeRunning, "nodeRunning");
|
||||
this.initScriptRunnerFactory = checkNotNull(initScriptRunnerFactory, "initScriptRunnerFactory");
|
||||
this.getNode = checkNotNull(getNode, "getNode");
|
||||
this.socketTester = checkNotNull(socketTester, "socketTester");
|
||||
this.timeouts = checkNotNull(timeouts, "timeouts");
|
||||
this.node = node;
|
||||
|
@ -111,61 +108,65 @@ public class CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap implements Cal
|
|||
|
||||
@AssistedInject
|
||||
public CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap(
|
||||
@Named("NODE_RUNNING") Predicate<NodeMetadata> nodeRunning, GetNodeMetadataStrategy getNode,
|
||||
@Named("NODE_RUNNING") Predicate<AtomicReference<NodeMetadata>> nodeRunning, GetNodeMetadataStrategy getNode,
|
||||
RetryIfSocketNotYetOpen socketTester, Timeouts timeouts,
|
||||
Function<TemplateOptions, Statement> templateOptionsToStatement,
|
||||
InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory,
|
||||
@Assisted TemplateOptions options, @Assisted Set<NodeMetadata> goodNodes,
|
||||
@Assisted Map<NodeMetadata, Exception> badNodes,
|
||||
InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory, @Assisted TemplateOptions options,
|
||||
@Assisted Set<NodeMetadata> goodNodes, @Assisted Map<NodeMetadata, Exception> badNodes,
|
||||
@Assisted Multimap<NodeMetadata, CustomizationResponse> customizationResponses) {
|
||||
this(nodeRunning, getNode, socketTester, timeouts, templateOptionsToStatement, initScriptRunnerFactory, options,
|
||||
null, goodNodes, badNodes, customizationResponses);
|
||||
this(nodeRunning, socketTester, timeouts, templateOptionsToStatement, initScriptRunnerFactory, options,
|
||||
new AtomicReference<NodeMetadata>(null), goodNodes, badNodes, customizationResponses);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void call() {
|
||||
checkState(!tainted, "this object is not designed to be reused: %s", toString());
|
||||
tainted = true;
|
||||
String originalId = node.getId();
|
||||
NodeMetadata originalNode = node;
|
||||
String originalId = node.get().getId();
|
||||
NodeMetadata originalNode = node.get();
|
||||
try {
|
||||
if (options.shouldBlockUntilRunning()) {
|
||||
if (nodeRunning.apply(node)) {
|
||||
node = getNode.getNode(originalId);
|
||||
} else {
|
||||
NodeMetadata nodeForState = getNode.getNode(originalId);
|
||||
NodeState state = nodeForState == null ? NodeState.TERMINATED : nodeForState.getState();
|
||||
if (state == NodeState.TERMINATED)
|
||||
throw new IllegalStateException(format("node(%s) terminated before we could customize", originalId));
|
||||
else
|
||||
throw new IllegalStateException(format(
|
||||
"node(%s) didn't achieve the state running within %d seconds, final state: %s", originalId,
|
||||
timeouts.nodeRunning / 1000, state));
|
||||
try {
|
||||
if (!nodeRunning.apply(node)) {
|
||||
if (node.get() == null) {
|
||||
node.set(originalNode);
|
||||
throw new IllegalStateException(format("api response for node(%s) was null, so we can't customize",
|
||||
originalId));
|
||||
}
|
||||
throw new IllegalStateException(
|
||||
format(
|
||||
"node(%s) didn't achieve the state running within %d seconds, so we couldn't customize; final state: %s",
|
||||
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) {
|
||||
RunScriptOnNode runner = initScriptRunnerFactory.create(node, statement, options, badNodes).call();
|
||||
RunScriptOnNode runner = initScriptRunnerFactory.create(node.get(), statement, options, badNodes).call();
|
||||
if (runner != null) {
|
||||
ExecResponse exec = runner.call();
|
||||
customizationResponses.put(node, exec);
|
||||
customizationResponses.put(node.get(), exec);
|
||||
}
|
||||
}
|
||||
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);
|
||||
goodNodes.add(node);
|
||||
logger.debug("<< customized node(%s)", originalId);
|
||||
goodNodes.add(node.get());
|
||||
} catch (Exception e) {
|
||||
logger.error(e, "<< problem applying options to node(%s): ", originalId, getRootCause(e).getMessage());
|
||||
badNodes.put(node == null ? originalNode : node, e);
|
||||
logger.error(e, "<< problem customizing node(%s): ", originalId, getRootCause(e).getMessage());
|
||||
badNodes.put(node.get(), e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void apply(NodeMetadata input) {
|
||||
public Void apply(AtomicReference<NodeMetadata> input) {
|
||||
this.node = input;
|
||||
call();
|
||||
return null;
|
||||
|
|
|
@ -67,8 +67,8 @@ public class RunScriptOnNodeAndAddToGoodMapOrPutExceptionIntoBadMap implements C
|
|||
tainted = true;
|
||||
try {
|
||||
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.trace("<< script output for node(%s): %s", runScriptOnNode.getNode().getId(), exec);
|
||||
goodNodes.put(runScriptOnNode.getNode(), exec);
|
||||
return exec;
|
||||
} catch (Exception e) {
|
||||
|
|
|
@ -31,6 +31,7 @@ import java.util.Set;
|
|||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.inject.Inject;
|
||||
|
@ -60,7 +61,7 @@ import com.google.common.collect.Multimap;
|
|||
@Singleton
|
||||
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 group;
|
||||
private final Template template;
|
||||
|
@ -72,14 +73,14 @@ public class CreateNodesWithGroupEncodedIntoNameThenAddToSet implements CreateNo
|
|||
}
|
||||
|
||||
@Override
|
||||
public NodeMetadata call() throws Exception {
|
||||
public AtomicReference<NodeMetadata> call() throws Exception {
|
||||
NodeMetadata node = null;
|
||||
logger.debug(">> adding node location(%s) name(%s) image(%s) hardware(%s)",
|
||||
template.getLocation().getId(), name, template.getImage().getProviderId(), template.getHardware()
|
||||
.getProviderId());
|
||||
node = addNodeWithGroupStrategy.createNodeWithGroupEncodedIntoName(group, name, template);
|
||||
logger.debug("<< %s node(%s)", node.getState(), node.getId());
|
||||
return node;
|
||||
return new AtomicReference<NodeMetadata>(node);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
|
|
|
@ -24,6 +24,7 @@ import java.util.Map;
|
|||
import java.util.Set;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
|
@ -60,7 +61,7 @@ public class ComputeUtils {
|
|||
Map<NodeMetadata, Future<Void>> responses = newLinkedHashMap();
|
||||
for (NodeMetadata node : runningNodes) {
|
||||
responses.put(node, executor.submit(customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory.create(
|
||||
options, node, goodNodes, badNodes, customizationResponses)));
|
||||
options, new AtomicReference<NodeMetadata>(node), goodNodes, badNodes, customizationResponses)));
|
||||
}
|
||||
return responses;
|
||||
}
|
||||
|
|
|
@ -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}))))))
|
|
@ -50,7 +50,7 @@
|
|||
(merge
|
||||
{:exit 0 :err "stderr" :out "stdout"}
|
||||
(condp = cmd
|
||||
"./bootstrap status" {:exit 1 :out "[]"}
|
||||
"/tmp/init-bootstrap status" {:exit 1 :out "[]"}
|
||||
{})))
|
||||
|
||||
|
||||
|
|
|
@ -31,10 +31,8 @@ import static com.google.common.collect.Sets.newTreeSet;
|
|||
import static java.lang.String.format;
|
||||
import static java.lang.System.currentTimeMillis;
|
||||
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.JBOSS_HOME;
|
||||
import static org.jclouds.compute.RunScriptData.JDK7_URL;
|
||||
import static org.jclouds.compute.RunScriptData.installAdminUserJBossAndOpenPorts;
|
||||
import static org.jclouds.compute.RunScriptData.startJBoss;
|
||||
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.NodeState;
|
||||
import org.jclouds.compute.domain.OperatingSystem;
|
||||
import org.jclouds.compute.domain.OsFamily;
|
||||
import org.jclouds.compute.domain.Template;
|
||||
import org.jclouds.compute.domain.TemplateBuilder;
|
||||
import org.jclouds.compute.options.TemplateOptions;
|
||||
|
@ -93,6 +90,7 @@ import org.jclouds.predicates.SocketOpen;
|
|||
import org.jclouds.rest.AuthorizationException;
|
||||
import org.jclouds.scriptbuilder.domain.SaveHttpResponseTo;
|
||||
import org.jclouds.scriptbuilder.domain.Statements;
|
||||
import org.jclouds.scriptbuilder.statements.java.InstallJDK;
|
||||
import org.jclouds.scriptbuilder.statements.login.AdminAccess;
|
||||
import org.jclouds.ssh.SshClient;
|
||||
import org.jclouds.ssh.SshException;
|
||||
|
@ -210,8 +208,7 @@ public abstract class BaseComputeServiceLiveTest extends BaseVersionedServiceLiv
|
|||
|
||||
@Test(enabled = true, expectedExceptions = NoSuchElementException.class)
|
||||
public void testCorrectExceptionRunningNodesNotFound() throws Exception {
|
||||
client.runScriptOnNodesMatching(runningInGroup("zebras-are-awesome"), buildScript(new OperatingSystem.Builder()
|
||||
.family(OsFamily.UBUNTU).description("ffoo").build()));
|
||||
client.runScriptOnNodesMatching(runningInGroup("zebras-are-awesome"), InstallJDK.fromURL());
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
||||
assert response.getExitCode() == 0 : node.getId() + ": " + response;
|
||||
assert response.getExitStatus() == 0 : node.getId() + ": " + response;
|
||||
|
||||
node = client.getNodeMetadata(node.getId());
|
||||
// test that the node updated to the correct admin user!
|
||||
|
@ -268,7 +265,7 @@ public abstract class BaseComputeServiceLiveTest extends BaseVersionedServiceLiv
|
|||
|
||||
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));
|
||||
|
||||
|
@ -307,11 +304,11 @@ public abstract class BaseComputeServiceLiveTest extends BaseVersionedServiceLiv
|
|||
assert false : node.getId() + ": " + response;
|
||||
} catch (TimeoutException e) {
|
||||
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));
|
||||
assert !response.getOutput().trim().equals("") : node.getId() + ": " + response;
|
||||
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));
|
||||
assert response.getOutput().trim().equals("") : node.getId() + ": " + response;
|
||||
try {
|
||||
|
@ -373,7 +370,7 @@ public abstract class BaseComputeServiceLiveTest extends BaseVersionedServiceLiv
|
|||
|
||||
protected static Template addRunScriptToTemplate(Template template) {
|
||||
template.getOptions().runScript(
|
||||
Statements.newStatementList(AdminAccess.standard(), buildScript(template.getImage().getOperatingSystem())));
|
||||
Statements.newStatementList(AdminAccess.standard(), InstallJDK.fromURL()));
|
||||
return template;
|
||||
}
|
||||
|
||||
|
@ -437,7 +434,7 @@ public abstract class BaseComputeServiceLiveTest extends BaseVersionedServiceLiv
|
|||
|
||||
protected Map<? extends NodeMetadata, ExecResponse> runScriptWithCreds(final String group, OperatingSystem os,
|
||||
LoginCredentials creds) throws RunScriptOnNodesException {
|
||||
return client.runScriptOnNodesMatching(runningInGroup(group), buildScript(os), overrideLoginCredentials(creds)
|
||||
return client.runScriptOnNodesMatching(runningInGroup(group), InstallJDK.fromURL(), overrideLoginCredentials(creds)
|
||||
.nameTask("runScriptWithCreds"));
|
||||
}
|
||||
|
||||
|
@ -595,10 +592,10 @@ public abstract class BaseComputeServiceLiveTest extends BaseVersionedServiceLiv
|
|||
|
||||
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,
|
||||
node, init(node, processName, "tail"), init(node, processName, "tailerr"));
|
||||
node, init(node, processName, "stdout"), init(node, processName, "stderr"));
|
||||
stats.socketOpenMilliseconds = watch.elapsedTime(TimeUnit.MILLISECONDS);
|
||||
|
||||
exec = init(node, processName, "tail");
|
||||
exec = init(node, processName, "stdout");
|
||||
|
||||
Matcher matcher = parseReported.matcher(exec.getOutput());
|
||||
if (matcher.find())
|
||||
|
@ -609,7 +606,7 @@ public abstract class BaseComputeServiceLiveTest extends BaseVersionedServiceLiv
|
|||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
|
@ -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'",
|
||||
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()) {
|
||||
// note we cannot use nslookup until we've configured the system, as
|
||||
// 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);
|
||||
|
||||
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>() {
|
||||
|
||||
@Override
|
||||
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
|
||||
|
|
|
@ -31,9 +31,7 @@ import java.util.Map;
|
|||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import org.jclouds.compute.domain.NodeMetadata;
|
||||
import org.jclouds.compute.domain.OperatingSystem;
|
||||
import org.jclouds.rest.HttpClient;
|
||||
import org.jclouds.scriptbuilder.domain.Statement;
|
||||
import org.jclouds.util.Preconditions2;
|
||||
|
||||
import com.google.common.base.Charsets;
|
||||
|
@ -46,9 +44,6 @@ import com.google.common.io.Files;
|
|||
* @author Adrian Cole
|
||||
*/
|
||||
public class ComputeTestUtils {
|
||||
public static Statement buildScript(OperatingSystem os) {
|
||||
return RunScriptData.installJavaAndCurl(os);
|
||||
}
|
||||
|
||||
public static Map<String, String> setupKeyPair() throws FileNotFoundException, IOException {
|
||||
String secretKeyFile;
|
||||
|
|
|
@ -70,6 +70,7 @@ public class StubComputeServiceIntegrationTest extends BaseComputeServiceLiveTes
|
|||
|
||||
private static final ExecResponse EXEC_GOOD = new ExecResponse("", "", 0);
|
||||
private static final ExecResponse EXEC_BAD = new ExecResponse("", "", 1);
|
||||
private static final ExecResponse EXEC_RC_GOOD = new ExecResponse("0", "", 0);
|
||||
|
||||
public StubComputeServiceIntegrationTest() {
|
||||
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.getUsername()).andReturn("root").atLeastOnce();
|
||||
expect(client.getHostAddress()).andReturn("localhost").atLeastOnce();
|
||||
expect(client.exec("./" + scriptName + " init")).andReturn(EXEC_GOOD);
|
||||
expect(client.exec("./" + scriptName + " start")).andReturn(EXEC_GOOD);
|
||||
expect(client.exec("./" + scriptName + " status")).andReturn(EXEC_GOOD);
|
||||
expect(client.exec("/tmp/init-" + scriptName + " init")).andReturn(EXEC_GOOD);
|
||||
expect(client.exec("/tmp/init-" + scriptName + " start")).andReturn(EXEC_GOOD);
|
||||
expect(client.exec("/tmp/init-" + scriptName + " status")).andReturn(EXEC_GOOD);
|
||||
// next status says the script is done, since not found.
|
||||
expect(client.exec("./" + scriptName + " status")).andReturn(EXEC_BAD);
|
||||
expect(client.exec("./" + scriptName + " tail")).andReturn(EXEC_GOOD);
|
||||
expect(client.exec("./" + scriptName + " tailerr")).andReturn(EXEC_GOOD);
|
||||
expect(client.exec("/tmp/init-" + scriptName + " status")).andReturn(EXEC_BAD);
|
||||
expect(client.exec("/tmp/init-" + scriptName + " stdout")).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.
|
||||
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.getUsername()).andReturn("web").atLeastOnce();
|
||||
expect(clientNew.getHostAddress()).andReturn("localhost").atLeastOnce();
|
||||
expect(clientNew.exec("./" + scriptName + " init")).andReturn(EXEC_GOOD);
|
||||
expect(clientNew.exec("./" + scriptName + " start")).andReturn(EXEC_GOOD);
|
||||
expect(clientNew.exec("/tmp/init-" + scriptName + " init")).andReturn(EXEC_GOOD);
|
||||
expect(clientNew.exec("/tmp/init-" + scriptName + " start")).andReturn(EXEC_GOOD);
|
||||
clientNew.disconnect();
|
||||
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.connect();
|
||||
expect(clientNew.exec("./" + scriptName + " stop\n")).andReturn(EXEC_GOOD);
|
||||
expect(clientNew.exec("/tmp/init-" + scriptName + " stop\n")).andReturn(EXEC_GOOD);
|
||||
clientNew.disconnect();
|
||||
|
||||
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.connect();
|
||||
expect(clientNew.exec("./" + scriptName + " tail\n")).andReturn(EXEC_GOOD);
|
||||
expect(clientNew.exec("/tmp/init-" + scriptName + " stdout\n")).andReturn(EXEC_GOOD);
|
||||
clientNew.disconnect();
|
||||
} catch (IOException 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.getUsername()).andReturn("root").atLeastOnce();
|
||||
expect(client.getHostAddress()).andReturn(nodeId + "").atLeastOnce();
|
||||
expect(client.exec("./" + scriptName + " init")).andReturn(EXEC_GOOD);
|
||||
expect(client.exec("./" + scriptName + " start")).andReturn(EXEC_GOOD);
|
||||
expect(client.exec("./" + scriptName + " status")).andReturn(EXEC_GOOD);
|
||||
expect(client.exec("/tmp/init-" + scriptName + " init")).andReturn(EXEC_GOOD);
|
||||
expect(client.exec("/tmp/init-" + scriptName + " start")).andReturn(EXEC_GOOD);
|
||||
expect(client.exec("/tmp/init-" + scriptName + " status")).andReturn(EXEC_GOOD);
|
||||
// next status says the script is done, since not found.
|
||||
expect(client.exec("./" + scriptName + " status")).andReturn(EXEC_BAD);
|
||||
expect(client.exec("./" + scriptName + " tail")).andReturn(EXEC_GOOD);
|
||||
expect(client.exec("./" + scriptName + " tailerr")).andReturn(EXEC_GOOD);
|
||||
expect(client.exec("/tmp/init-" + scriptName + " status")).andReturn(EXEC_BAD);
|
||||
expect(client.exec("/tmp/init-" + scriptName + " stdout")).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) {
|
||||
|
|
|
@ -41,7 +41,7 @@ import org.jclouds.concurrent.MoreExecutors;
|
|||
import org.jclouds.concurrent.config.ExecutorServiceModule;
|
||||
import org.jclouds.domain.LoginCredentials;
|
||||
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.Statement;
|
||||
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.Stopwatch;
|
||||
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.Guice;
|
||||
import com.google.inject.assistedinject.FactoryModuleBuilder;
|
||||
|
@ -62,6 +62,8 @@ import com.google.inject.name.Names;
|
|||
@Test(groups = "unit", singleThreaded = true, testName = "RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilCompleteTest")
|
||||
public class RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilCompleteTest {
|
||||
|
||||
EventBus eventBus = new EventBus();
|
||||
|
||||
BlockUntilInitScriptStatusIsZeroThenReturnOutput.Factory statusFactory = Guice.createInjector(
|
||||
new ExecutorServiceModule(MoreExecutors.sameThreadExecutor(), MoreExecutors.sameThreadExecutor()),
|
||||
new AbstractModule() {
|
||||
|
@ -98,7 +100,7 @@ public class RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilCompleteTest {
|
|||
|
||||
RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilComplete testMe = new RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilComplete(
|
||||
statusFactory, timeouts, Functions.forMap(ImmutableMap.of(node, sshClient)),
|
||||
InitScriptConfigurationForTasks.create().appendIncrementingNumberToAnonymousTaskNames(), node, command,
|
||||
eventBus, InitScriptConfigurationForTasks.create().appendIncrementingNumberToAnonymousTaskNames(), node, command,
|
||||
new RunScriptOptions());
|
||||
|
||||
testMe.call();
|
||||
|
@ -137,13 +139,13 @@ public class RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilCompleteTest {
|
|||
*/
|
||||
private void runDefaults(IAnswer<ExecResponse> answerForScriptStatus, int timesForScriptStatus) {
|
||||
Statement command = exec("doFoo");
|
||||
NodeMetadata node = new NodeMetadataBuilder().ids("id").state(NodeState.RUNNING).credentials(
|
||||
new LoginCredentials("tester", "testpassword!", null, false)).build();
|
||||
NodeMetadata node = new NodeMetadataBuilder().ids("id").state(NodeState.RUNNING)
|
||||
.credentials(LoginCredentials.builder().user("tester").password("testpassword!").build()).build();
|
||||
|
||||
SshClient sshClient = createMock(SshClient.class);
|
||||
|
||||
InitBuilder init = new InitBuilder("jclouds-script-0", "/tmp/jclouds-script-0", "/tmp/jclouds-script-0",
|
||||
ImmutableMap.<String, String> of(), ImmutableSet.of(command));
|
||||
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));
|
||||
|
@ -154,27 +156,28 @@ public class RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilCompleteTest {
|
|||
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("./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
|
||||
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
|
||||
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 {
|
||||
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("./jclouds-script-0 tailerr")).andReturn(new ExecResponse("err", "", 0));
|
||||
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("0", "", 0));
|
||||
|
||||
sshClient.disconnect();
|
||||
replay(sshClient);
|
||||
|
||||
RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilComplete testMe = new RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilComplete(
|
||||
statusFactory, timeouts, Functions.forMap(ImmutableMap.of(node, sshClient)),
|
||||
InitScriptConfigurationForTasks.create().appendIncrementingNumberToAnonymousTaskNames(), node, command,
|
||||
eventBus, InitScriptConfigurationForTasks.create().appendIncrementingNumberToAnonymousTaskNames(), node, command,
|
||||
new RunScriptOptions());
|
||||
|
||||
assertEquals(testMe.getInitFile(), "/tmp/init-jclouds-script-0");
|
||||
|
@ -195,8 +198,8 @@ public class RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilCompleteTest {
|
|||
|
||||
SshClient sshClient = createMock(SshClient.class);
|
||||
|
||||
InitBuilder init = new InitBuilder("jclouds-script-0", "/tmp/jclouds-script-0", "/tmp/jclouds-script-0",
|
||||
ImmutableMap.<String, String> of(), ImmutableSet.of(command));
|
||||
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));
|
||||
|
@ -207,22 +210,23 @@ public class RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilCompleteTest {
|
|||
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("./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
|
||||
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
|
||||
expect(sshClient.exec("./jclouds-script-0 status")).andReturn(new ExecResponse("", "", 1));
|
||||
expect(sshClient.exec("./jclouds-script-0 tail")).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 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("0", "", 0));
|
||||
|
||||
sshClient.disconnect();
|
||||
replay(sshClient);
|
||||
|
||||
RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilComplete testMe = new RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilComplete(
|
||||
statusFactory, timeouts, Functions.forMap(ImmutableMap.of(node, sshClient)),
|
||||
InitScriptConfigurationForTasks.create().appendIncrementingNumberToAnonymousTaskNames(), node, command,
|
||||
eventBus, InitScriptConfigurationForTasks.create().appendIncrementingNumberToAnonymousTaskNames(), node, command,
|
||||
new RunScriptOptions());
|
||||
|
||||
assertEquals(testMe.getInitFile(), "/tmp/init-jclouds-script-0");
|
||||
|
@ -243,8 +247,8 @@ public class RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilCompleteTest {
|
|||
|
||||
SshClient sshClient = createMock(SshClient.class);
|
||||
|
||||
InitBuilder init = new InitBuilder("jclouds-script-0", "/tmp/jclouds-script-0", "/tmp/jclouds-script-0",
|
||||
ImmutableMap.<String, String> of(), ImmutableSet.of(command));
|
||||
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));
|
||||
|
@ -255,22 +259,23 @@ public class RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilCompleteTest {
|
|||
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("./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
|
||||
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
|
||||
expect(sshClient.exec("./jclouds-script-0 status")).andReturn(new ExecResponse("", "", 1));
|
||||
expect(sshClient.exec("./jclouds-script-0 tail")).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 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("0", "", 0));
|
||||
|
||||
sshClient.disconnect();
|
||||
replay(sshClient);
|
||||
|
||||
RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilComplete testMe = new RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilComplete(
|
||||
statusFactory, timeouts, Functions.forMap(ImmutableMap.of(node, sshClient)),
|
||||
InitScriptConfigurationForTasks.create().appendIncrementingNumberToAnonymousTaskNames(), node, command,
|
||||
eventBus, InitScriptConfigurationForTasks.create().appendIncrementingNumberToAnonymousTaskNames(), node, command,
|
||||
new RunScriptOptions().runAsRoot(false));
|
||||
|
||||
assertEquals(testMe.getInitFile(), "/tmp/init-jclouds-script-0");
|
||||
|
@ -284,4 +289,53 @@ public class RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilCompleteTest {
|
|||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ import org.jclouds.compute.domain.NodeMetadataBuilder;
|
|||
import org.jclouds.compute.domain.NodeState;
|
||||
import org.jclouds.compute.options.RunScriptOptions;
|
||||
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.Statement;
|
||||
import org.jclouds.ssh.SshClient;
|
||||
|
@ -39,13 +39,14 @@ import org.testng.annotations.Test;
|
|||
|
||||
import com.google.common.base.Functions;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.eventbus.EventBus;
|
||||
|
||||
/**
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Test(groups = "unit", singleThreaded = true, testName = "RunScriptOnNodeAsInitScriptUsingSshTest")
|
||||
public class RunScriptOnNodeAsInitScriptUsingSshTest {
|
||||
EventBus eventBus = new EventBus();
|
||||
|
||||
@Test(expectedExceptions = IllegalStateException.class)
|
||||
public void testWithoutInitThrowsIllegalStateException() {
|
||||
|
@ -58,7 +59,7 @@ public class RunScriptOnNodeAsInitScriptUsingSshTest {
|
|||
replay(sshClient);
|
||||
|
||||
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());
|
||||
|
||||
testMe.call();
|
||||
|
@ -71,8 +72,8 @@ public class RunScriptOnNodeAsInitScriptUsingSshTest {
|
|||
|
||||
SshClient sshClient = createMock(SshClient.class);
|
||||
|
||||
InitBuilder init = new InitBuilder("jclouds-script-0", "/tmp/jclouds-script-0", "/tmp/jclouds-script-0",
|
||||
ImmutableMap.<String, String> of(), ImmutableSet.of(command));
|
||||
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));
|
||||
|
@ -82,17 +83,17 @@ public class RunScriptOnNodeAsInitScriptUsingSshTest {
|
|||
// 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("./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
|
||||
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();
|
||||
replay(sshClient);
|
||||
|
||||
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());
|
||||
|
||||
assertEquals(testMe.getInitFile(), "/tmp/init-jclouds-script-0");
|
||||
|
@ -112,8 +113,8 @@ public class RunScriptOnNodeAsInitScriptUsingSshTest {
|
|||
|
||||
SshClient sshClient = createMock(SshClient.class);
|
||||
|
||||
InitBuilder init = new InitBuilder("jclouds-script-0", "/tmp/jclouds-script-0", "/tmp/jclouds-script-0",
|
||||
ImmutableMap.<String, String> of(), ImmutableSet.of(command));
|
||||
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));
|
||||
|
@ -123,17 +124,17 @@ public class RunScriptOnNodeAsInitScriptUsingSshTest {
|
|||
// 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("./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
|
||||
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();
|
||||
replay(sshClient);
|
||||
|
||||
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());
|
||||
|
||||
assertEquals(testMe.getInitFile(), "/tmp/init-jclouds-script-0");
|
||||
|
@ -154,8 +155,8 @@ public class RunScriptOnNodeAsInitScriptUsingSshTest {
|
|||
|
||||
SshClient sshClient = createMock(SshClient.class);
|
||||
|
||||
InitBuilder init = new InitBuilder("jclouds-script-0", "/tmp/jclouds-script-0", "/tmp/jclouds-script-0",
|
||||
ImmutableMap.<String, String> of(), ImmutableSet.of(command));
|
||||
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));
|
||||
|
@ -165,16 +166,16 @@ public class RunScriptOnNodeAsInitScriptUsingSshTest {
|
|||
// 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("./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
|
||||
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();
|
||||
replay(sshClient);
|
||||
|
||||
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));
|
||||
|
||||
assertEquals(testMe.getInitFile(), "/tmp/init-jclouds-script-0");
|
||||
|
|
|
@ -34,12 +34,15 @@ import org.testng.annotations.BeforeMethod;
|
|||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.eventbus.EventBus;
|
||||
|
||||
/**
|
||||
* @author Adam Lowe
|
||||
*/
|
||||
@Test(groups = { "unit" }, singleThreaded = true)
|
||||
public class RunScriptOnNodeUsingSshTest {
|
||||
EventBus eventBus = new EventBus();
|
||||
|
||||
private SshClient sshClient;
|
||||
private NodeMetadata node;
|
||||
private Function<NodeMetadata, SshClient> sshFactory;
|
||||
|
@ -59,7 +62,7 @@ public class RunScriptOnNodeUsingSshTest {
|
|||
}
|
||||
|
||||
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));
|
||||
|
||||
testMe.init();
|
||||
|
@ -75,7 +78,7 @@ public class RunScriptOnNodeUsingSshTest {
|
|||
}
|
||||
|
||||
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));
|
||||
|
||||
testMe.init();
|
||||
|
@ -97,7 +100,7 @@ public class RunScriptOnNodeUsingSshTest {
|
|||
expect(node.getCredentials()).andReturn(new LoginCredentials("tester", "testpassword!", null, true))
|
||||
.atLeastOnce();
|
||||
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));
|
||||
testMe.init();
|
||||
|
||||
|
@ -114,7 +117,7 @@ public class RunScriptOnNodeUsingSshTest {
|
|||
}
|
||||
|
||||
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"));
|
||||
|
||||
testMe.init();
|
||||
|
|
|
@ -32,9 +32,13 @@ import javax.inject.Provider;
|
|||
import org.jclouds.compute.domain.Hardware;
|
||||
import org.jclouds.compute.domain.HardwareBuilder;
|
||||
import org.jclouds.compute.domain.Image;
|
||||
import org.jclouds.compute.domain.ImageBuilder;
|
||||
import org.jclouds.compute.domain.OperatingSystem;
|
||||
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.Volume;
|
||||
import org.jclouds.compute.options.TemplateOptions;
|
||||
import org.jclouds.compute.predicates.ImagePredicates;
|
||||
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.Suppliers;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
|
||||
/**
|
||||
|
@ -385,7 +390,7 @@ public class TemplateBuilderImplTest {
|
|||
// make sure big data is not in the exception message
|
||||
assertEquals(
|
||||
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(os);
|
||||
verify(defaultTemplate);
|
||||
|
@ -772,4 +777,110 @@ public class TemplateBuilderImplTest {
|
|||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -18,14 +18,14 @@
|
|||
*/
|
||||
package org.jclouds.compute.strategy;
|
||||
|
||||
import static org.easymock.EasyMock.expect;
|
||||
import static org.easymock.classextension.EasyMock.createMock;
|
||||
import static org.easymock.classextension.EasyMock.replay;
|
||||
import static org.easymock.classextension.EasyMock.verify;
|
||||
import static org.easymock.EasyMock.createMock;
|
||||
import static org.easymock.EasyMock.replay;
|
||||
import static org.easymock.EasyMock.verify;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import org.jclouds.compute.config.CustomizationResponse;
|
||||
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.functions.TemplateOptionsToStatement;
|
||||
import org.jclouds.compute.options.TemplateOptions;
|
||||
import org.jclouds.compute.predicates.AtomicNodeRunning;
|
||||
import org.jclouds.compute.predicates.RetryIfSocketNotYetOpen;
|
||||
import org.jclouds.compute.reference.ComputeServiceConstants.Timeouts;
|
||||
import org.jclouds.scriptbuilder.domain.Statement;
|
||||
import org.testng.Assert;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.LinkedHashMultimap;
|
||||
import com.google.common.collect.Maps;
|
||||
|
@ -52,11 +53,8 @@ import com.google.common.collect.Sets;
|
|||
@Test(groups = "unit")
|
||||
public class CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapTest {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void testBreakWhenNodeStillPending() {
|
||||
Predicate<NodeMetadata> nodeRunning = createMock(Predicate.class);
|
||||
InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory = createMock(InitializeRunScriptOnNodeOrPlaceInBadMap.Factory.class);
|
||||
GetNodeMetadataStrategy getNode = createMock(GetNodeMetadataStrategy.class);
|
||||
RetryIfSocketNotYetOpen socketTester = createMock(RetryIfSocketNotYetOpen.class);
|
||||
Timeouts timeouts = new Timeouts();
|
||||
Function<TemplateOptions, Statement> templateOptionsToStatement = new TemplateOptionsToStatement();
|
||||
|
@ -67,41 +65,39 @@ public class CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapTest {
|
|||
Map<NodeMetadata, Exception> badNodes = Maps.newLinkedHashMap();
|
||||
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
|
||||
expect(nodeRunning.apply(node)).andReturn(false);
|
||||
expect(getNode.getNode(node.getId())).andReturn(node);
|
||||
// node always stays pending
|
||||
GetNodeMetadataStrategy nodeRunning = new GetNodeMetadataStrategy(){
|
||||
|
||||
@Override
|
||||
public NodeMetadata getNode(String input) {
|
||||
Assert.assertEquals(input, node.getId());
|
||||
return node;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// replay mocks
|
||||
replay(nodeRunning);
|
||||
replay(initScriptRunnerFactory);
|
||||
replay(getNode);
|
||||
replay(socketTester);
|
||||
|
||||
replay(initScriptRunnerFactory, socketTester);
|
||||
// run
|
||||
new CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap(nodeRunning, getNode, socketTester, timeouts,
|
||||
templateOptionsToStatement, initScriptRunnerFactory, options, node, goodNodes, badNodes,
|
||||
customizationResponses).apply(node);
|
||||
AtomicReference<NodeMetadata> atomicNode = new AtomicReference<NodeMetadata>(node);
|
||||
new CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap( new AtomicNodeRunning(nodeRunning), socketTester, timeouts,
|
||||
templateOptionsToStatement, initScriptRunnerFactory, options, atomicNode, goodNodes, badNodes,
|
||||
customizationResponses).apply(atomicNode);
|
||||
|
||||
assertEquals(goodNodes.size(), 0);
|
||||
assertEquals(badNodes.keySet(), ImmutableSet.of(node));
|
||||
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);
|
||||
|
||||
// verify mocks
|
||||
verify(nodeRunning);
|
||||
verify(initScriptRunnerFactory);
|
||||
verify(getNode);
|
||||
verify(socketTester);
|
||||
verify(initScriptRunnerFactory, socketTester);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void testBreakGraceFullyWhenNodeDied() {
|
||||
Predicate<NodeMetadata> nodeRunning = createMock(Predicate.class);
|
||||
InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory = createMock(InitializeRunScriptOnNodeOrPlaceInBadMap.Factory.class);
|
||||
GetNodeMetadataStrategy getNode = createMock(GetNodeMetadataStrategy.class);
|
||||
RetryIfSocketNotYetOpen socketTester = createMock(RetryIfSocketNotYetOpen.class);
|
||||
Timeouts timeouts = new Timeouts();
|
||||
Function<TemplateOptions, Statement> templateOptionsToStatement = new TemplateOptionsToStatement();
|
||||
|
@ -112,32 +108,35 @@ public class CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapTest {
|
|||
Map<NodeMetadata, Exception> badNodes = Maps.newLinkedHashMap();
|
||||
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
|
||||
expect(nodeRunning.apply(node)).andReturn(false);
|
||||
expect(getNode.getNode(node.getId())).andReturn(null);
|
||||
// node dies
|
||||
GetNodeMetadataStrategy nodeRunning = new GetNodeMetadataStrategy(){
|
||||
|
||||
@Override
|
||||
public NodeMetadata getNode(String input) {
|
||||
Assert.assertEquals(input, node.getId());
|
||||
return deadNnode;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// replay mocks
|
||||
replay(nodeRunning);
|
||||
replay(initScriptRunnerFactory);
|
||||
replay(getNode);
|
||||
replay(socketTester);
|
||||
|
||||
replay(initScriptRunnerFactory, socketTester);
|
||||
// run
|
||||
new CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap(nodeRunning, getNode, socketTester, timeouts,
|
||||
templateOptionsToStatement, initScriptRunnerFactory, options, node, goodNodes, badNodes,
|
||||
customizationResponses).apply(node);
|
||||
AtomicReference<NodeMetadata> atomicNode = new AtomicReference<NodeMetadata>(node);
|
||||
new CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap( new AtomicNodeRunning(nodeRunning), socketTester, timeouts,
|
||||
templateOptionsToStatement, initScriptRunnerFactory, options, atomicNode, goodNodes, badNodes,
|
||||
customizationResponses).apply(atomicNode);
|
||||
|
||||
assertEquals(goodNodes.size(), 0);
|
||||
assertEquals(badNodes.keySet(), ImmutableSet.of(node));
|
||||
badNodes.get(node).printStackTrace();
|
||||
assertEquals(badNodes.get(node).getMessage(), "node(id) terminated before we could customize");
|
||||
assertEquals(customizationResponses.size(), 0);
|
||||
|
||||
// verify mocks
|
||||
verify(nodeRunning);
|
||||
verify(initScriptRunnerFactory);
|
||||
verify(getNode);
|
||||
verify(socketTester);
|
||||
verify(initScriptRunnerFactory, socketTester);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,11 +10,11 @@ function abort {
|
|||
function default {
|
||||
export INSTANCE_NAME="bootstrap"
|
||||
export INSTANCE_HOME="/tmp/bootstrap"
|
||||
export LOG_DIR="/tmp/bootstrap"
|
||||
return 0
|
||||
export LOG_DIR="$INSTANCE_HOME"
|
||||
return $?
|
||||
}
|
||||
function bootstrap {
|
||||
return 0
|
||||
return $?
|
||||
}
|
||||
function findPid {
|
||||
unset FOUND_PID;
|
||||
|
@ -62,75 +62,134 @@ init)
|
|||
mkdir -p $INSTANCE_HOME
|
||||
|
||||
# create runscript header
|
||||
cat > $INSTANCE_HOME/bootstrap.sh <<END_OF_SCRIPT
|
||||
#!/bin/bash
|
||||
set +u
|
||||
shopt -s xpg_echo
|
||||
shopt -s expand_aliases
|
||||
PROMPT_COMMAND='echo -ne "\033]0;bootstrap\007"'
|
||||
export PATH=/usr/ucb/bin:/bin:/sbin:/usr/bin:/usr/sbin
|
||||
export INSTANCE_NAME='bootstrap'
|
||||
export INSTANCE_NAME='$INSTANCE_NAME'
|
||||
export INSTANCE_HOME='$INSTANCE_HOME'
|
||||
export LOG_DIR='$LOG_DIR'
|
||||
END_OF_SCRIPT
|
||||
cat > $INSTANCE_HOME/bootstrap.sh <<-'END_OF_JCLOUDS_SCRIPT'
|
||||
#!/bin/bash
|
||||
set +u
|
||||
shopt -s xpg_echo
|
||||
shopt -s expand_aliases
|
||||
|
||||
PROMPT_COMMAND='echo -ne \"\033]0;bootstrap\007\"'
|
||||
export PATH=/usr/ucb/bin:/bin:/sbin:/usr/bin:/usr/sbin
|
||||
|
||||
export INSTANCE_NAME='bootstrap'
|
||||
END_OF_JCLOUDS_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
|
||||
cat >> $INSTANCE_HOME/bootstrap.sh <<'END_OF_SCRIPT'
|
||||
cd $INSTANCE_HOME
|
||||
rm /etc/sudoers
|
||||
cat >> /etc/sudoers <<'END_OF_FILE'
|
||||
root ALL = (ALL) ALL
|
||||
%wheel ALL = (ALL) NOPASSWD:ALL
|
||||
END_OF_FILE
|
||||
chmod 0440 /etc/sudoers
|
||||
mkdir -p /home/users
|
||||
groupadd -f wheel
|
||||
useradd -s /bin/bash -g wheel -m -d /home/users/defaultAdminUsername -p 'crypt(randompassword)' defaultAdminUsername
|
||||
mkdir -p /home/users/defaultAdminUsername/.ssh
|
||||
cat >> /home/users/defaultAdminUsername/.ssh/authorized_keys <<'END_OF_FILE'
|
||||
publicKey
|
||||
END_OF_FILE
|
||||
chmod 600 /home/users/defaultAdminUsername/.ssh/authorized_keys
|
||||
chown -R defaultAdminUsername /home/users/defaultAdminUsername
|
||||
exec 3<> /etc/ssh/sshd_config && awk -v TEXT="PasswordAuthentication no
|
||||
PermitRootLogin no
|
||||
" 'BEGIN {print TEXT}{print}' /etc/ssh/sshd_config >&3
|
||||
/etc/init.d/sshd reload||/etc/init.d/ssh reload
|
||||
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
|
||||
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
|
||||
grep `hostname` /etc/hosts >/dev/null || awk -v hostname=`hostname` 'END { print $1" "hostname }' /proc/net/arp >> /etc/hosts
|
||||
nslookup yahoo.com >/dev/null || echo nameserver 208.67.222.222 >> /etc/resolv.conf
|
||||
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
|
||||
mkdir -p /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 -)
|
||||
mv /usr/local/jdk1.7*/* /usr/local/jdk/
|
||||
test -n "$SUDO_USER" &&
|
||||
cat >> /home/$SUDO_USER/.bashrc <<'END_OF_FILE'
|
||||
export JAVA_HOME=/usr/local/jdk
|
||||
export PATH=$JAVA_HOME/bin:$PATH
|
||||
END_OF_FILE
|
||||
cat >> /etc/bashrc <<'END_OF_FILE'
|
||||
export JAVA_HOME=/usr/local/jdk
|
||||
export PATH=$JAVA_HOME/bin:$PATH
|
||||
END_OF_FILE
|
||||
cat >> $HOME/.bashrc <<'END_OF_FILE'
|
||||
export JAVA_HOME=/usr/local/jdk
|
||||
export PATH=$JAVA_HOME/bin:$PATH
|
||||
END_OF_FILE
|
||||
cat >> /etc/skel/.bashrc <<'END_OF_FILE'
|
||||
export JAVA_HOME=/usr/local/jdk
|
||||
export PATH=$JAVA_HOME/bin:$PATH
|
||||
END_OF_FILE
|
||||
ln -fs /usr/local/jdk/bin/java /usr/bin/java
|
||||
cat >> $INSTANCE_HOME/bootstrap.sh <<-'END_OF_JCLOUDS_SCRIPT'
|
||||
cd $INSTANCE_HOME
|
||||
rm -f $INSTANCE_HOME/rc
|
||||
trap 'echo $?>$INSTANCE_HOME/rc' 0 1 2 3 15
|
||||
cat > /etc/sudoers <<-'END_OF_JCLOUDS_FILE'
|
||||
root ALL = (ALL) ALL
|
||||
%wheel ALL = (ALL) NOPASSWD:ALL
|
||||
END_OF_JCLOUDS_FILE
|
||||
chmod 0440 /etc/sudoers
|
||||
mkdir -p /home/users
|
||||
groupadd -f wheel
|
||||
useradd -s /bin/bash -g wheel -m -d /home/users/defaultAdminUsername -p 'crypt(randompassword)' defaultAdminUsername
|
||||
mkdir -p /home/users/defaultAdminUsername/.ssh
|
||||
cat >> /home/users/defaultAdminUsername/.ssh/authorized_keys <<-'END_OF_JCLOUDS_FILE'
|
||||
publicKey
|
||||
END_OF_JCLOUDS_FILE
|
||||
chmod 600 /home/users/defaultAdminUsername/.ssh/authorized_keys
|
||||
chown -R defaultAdminUsername /home/users/defaultAdminUsername
|
||||
exec 3<> /etc/ssh/sshd_config && awk -v TEXT="PasswordAuthentication no
|
||||
PermitRootLogin no
|
||||
" 'BEGIN {print TEXT}{print}' /etc/ssh/sshd_config >&3
|
||||
hash service 2>/dev/null && service ssh reload || /etc/init.d/ssh* reload
|
||||
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
|
||||
setupPublicCurl || return 1
|
||||
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 -)
|
||||
mv /usr/local/jdk* /usr/local/jdk/
|
||||
test -n "$SUDO_USER" &&
|
||||
cat >> /home/$SUDO_USER/.bashrc <<-'END_OF_JCLOUDS_FILE'
|
||||
export JAVA_HOME=/usr/local/jdk
|
||||
export PATH=$JAVA_HOME/bin:$PATH
|
||||
END_OF_JCLOUDS_FILE
|
||||
cat >> /etc/bashrc <<-'END_OF_JCLOUDS_FILE'
|
||||
export JAVA_HOME=/usr/local/jdk
|
||||
export PATH=$JAVA_HOME/bin:$PATH
|
||||
END_OF_JCLOUDS_FILE
|
||||
cat >> $HOME/.bashrc <<-'END_OF_JCLOUDS_FILE'
|
||||
export JAVA_HOME=/usr/local/jdk
|
||||
export PATH=$JAVA_HOME/bin:$PATH
|
||||
END_OF_JCLOUDS_FILE
|
||||
cat >> /etc/skel/.bashrc <<-'END_OF_JCLOUDS_FILE'
|
||||
export JAVA_HOME=/usr/local/jdk
|
||||
export PATH=$JAVA_HOME/bin:$PATH
|
||||
END_OF_JCLOUDS_FILE
|
||||
ln -fs /usr/local/jdk/bin/java /usr/bin/java
|
||||
|
||||
END_OF_SCRIPT
|
||||
END_OF_JCLOUDS_SCRIPT
|
||||
|
||||
# add runscript footer
|
||||
cat >> $INSTANCE_HOME/bootstrap.sh <<'END_OF_SCRIPT'
|
||||
exit 0
|
||||
END_OF_SCRIPT
|
||||
cat >> $INSTANCE_HOME/bootstrap.sh <<-'END_OF_JCLOUDS_SCRIPT'
|
||||
exit $?
|
||||
|
||||
END_OF_JCLOUDS_SCRIPT
|
||||
|
||||
chmod u+x $INSTANCE_HOME/bootstrap.sh
|
||||
;;
|
||||
|
@ -151,6 +210,17 @@ start)
|
|||
default || 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)
|
||||
default || exit 1
|
||||
tail $LOG_DIR/stdout.log
|
||||
|
@ -164,4 +234,4 @@ run)
|
|||
$INSTANCE_HOME/$INSTANCE_NAME.sh
|
||||
;;
|
||||
esac
|
||||
exit 0
|
||||
exit $?
|
||||
|
|
|
@ -10,11 +10,11 @@ function abort {
|
|||
function default {
|
||||
export INSTANCE_NAME="configure-jboss"
|
||||
export INSTANCE_HOME="/tmp/configure-jboss"
|
||||
export LOG_DIR="/tmp/configure-jboss"
|
||||
return 0
|
||||
export LOG_DIR="$INSTANCE_HOME"
|
||||
return $?
|
||||
}
|
||||
function configure-jboss {
|
||||
return 0
|
||||
return $?
|
||||
}
|
||||
function findPid {
|
||||
unset FOUND_PID;
|
||||
|
@ -62,84 +62,143 @@ init)
|
|||
mkdir -p $INSTANCE_HOME
|
||||
|
||||
# create runscript header
|
||||
cat > $INSTANCE_HOME/configure-jboss.sh <<END_OF_SCRIPT
|
||||
#!/bin/bash
|
||||
set +u
|
||||
shopt -s xpg_echo
|
||||
shopt -s expand_aliases
|
||||
PROMPT_COMMAND='echo -ne "\033]0;configure-jboss\007"'
|
||||
export PATH=/usr/ucb/bin:/bin:/sbin:/usr/bin:/usr/sbin
|
||||
export INSTANCE_NAME='configure-jboss'
|
||||
export INSTANCE_NAME='$INSTANCE_NAME'
|
||||
export INSTANCE_HOME='$INSTANCE_HOME'
|
||||
export LOG_DIR='$LOG_DIR'
|
||||
END_OF_SCRIPT
|
||||
cat > $INSTANCE_HOME/configure-jboss.sh <<-'END_OF_JCLOUDS_SCRIPT'
|
||||
#!/bin/bash
|
||||
set +u
|
||||
shopt -s xpg_echo
|
||||
shopt -s expand_aliases
|
||||
|
||||
PROMPT_COMMAND='echo -ne \"\033]0;configure-jboss\007\"'
|
||||
export PATH=/usr/ucb/bin:/bin:/sbin:/usr/bin:/usr/sbin
|
||||
|
||||
export INSTANCE_NAME='configure-jboss'
|
||||
END_OF_JCLOUDS_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
|
||||
cat >> $INSTANCE_HOME/configure-jboss.sh <<'END_OF_SCRIPT'
|
||||
cd $INSTANCE_HOME
|
||||
rm /etc/sudoers
|
||||
cat >> /etc/sudoers <<'END_OF_FILE'
|
||||
root ALL = (ALL) ALL
|
||||
%wheel ALL = (ALL) NOPASSWD:ALL
|
||||
END_OF_FILE
|
||||
chmod 0440 /etc/sudoers
|
||||
mkdir -p /home/users
|
||||
groupadd -f wheel
|
||||
useradd -s /bin/bash -g wheel -m -d /home/users/web -p 'crypt(randompassword)' web
|
||||
mkdir -p /home/users/web/.ssh
|
||||
cat >> /home/users/web/.ssh/authorized_keys <<'END_OF_FILE'
|
||||
publicKey
|
||||
END_OF_FILE
|
||||
chmod 600 /home/users/web/.ssh/authorized_keys
|
||||
chown -R web /home/users/web
|
||||
exec 3<> /etc/ssh/sshd_config && awk -v TEXT="PasswordAuthentication no
|
||||
PermitRootLogin no
|
||||
" 'BEGIN {print TEXT}{print}' /etc/ssh/sshd_config >&3
|
||||
/etc/init.d/sshd reload||/etc/init.d/ssh reload
|
||||
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
|
||||
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
|
||||
grep `hostname` /etc/hosts >/dev/null || awk -v hostname=`hostname` 'END { print $1" "hostname }' /proc/net/arp >> /etc/hosts
|
||||
nslookup yahoo.com >/dev/null || echo nameserver 208.67.222.222 >> /etc/resolv.conf
|
||||
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
|
||||
mkdir -p /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 -)
|
||||
mv /usr/local/jdk1.7*/* /usr/local/jdk/
|
||||
test -n "$SUDO_USER" &&
|
||||
cat >> /home/$SUDO_USER/.bashrc <<'END_OF_FILE'
|
||||
export JAVA_HOME=/usr/local/jdk
|
||||
export PATH=$JAVA_HOME/bin:$PATH
|
||||
END_OF_FILE
|
||||
cat >> /etc/bashrc <<'END_OF_FILE'
|
||||
export JAVA_HOME=/usr/local/jdk
|
||||
export PATH=$JAVA_HOME/bin:$PATH
|
||||
END_OF_FILE
|
||||
cat >> $HOME/.bashrc <<'END_OF_FILE'
|
||||
export JAVA_HOME=/usr/local/jdk
|
||||
export PATH=$JAVA_HOME/bin:$PATH
|
||||
END_OF_FILE
|
||||
cat >> /etc/skel/.bashrc <<'END_OF_FILE'
|
||||
export JAVA_HOME=/usr/local/jdk
|
||||
export PATH=$JAVA_HOME/bin:$PATH
|
||||
END_OF_FILE
|
||||
ln -fs /usr/local/jdk/bin/java /usr/bin/java
|
||||
iptables -I INPUT 1 -p tcp --dport 22 -j ACCEPT
|
||||
iptables -I INPUT 1 -p tcp --dport 8080 -j ACCEPT
|
||||
iptables-save
|
||||
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 -)
|
||||
mkdir -p /usr/local/jboss
|
||||
mv /usr/local/jboss-*/* /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
|
||||
cat >> $INSTANCE_HOME/configure-jboss.sh <<-'END_OF_JCLOUDS_SCRIPT'
|
||||
cd $INSTANCE_HOME
|
||||
rm -f $INSTANCE_HOME/rc
|
||||
trap 'echo $?>$INSTANCE_HOME/rc' 0 1 2 3 15
|
||||
cat > /etc/sudoers <<-'END_OF_JCLOUDS_FILE'
|
||||
root ALL = (ALL) ALL
|
||||
%wheel ALL = (ALL) NOPASSWD:ALL
|
||||
END_OF_JCLOUDS_FILE
|
||||
chmod 0440 /etc/sudoers
|
||||
mkdir -p /home/users
|
||||
groupadd -f wheel
|
||||
useradd -s /bin/bash -g wheel -m -d /home/users/web -p 'crypt(randompassword)' web
|
||||
mkdir -p /home/users/web/.ssh
|
||||
cat >> /home/users/web/.ssh/authorized_keys <<-'END_OF_JCLOUDS_FILE'
|
||||
publicKey
|
||||
END_OF_JCLOUDS_FILE
|
||||
chmod 600 /home/users/web/.ssh/authorized_keys
|
||||
chown -R web /home/users/web
|
||||
exec 3<> /etc/ssh/sshd_config && awk -v TEXT="PasswordAuthentication no
|
||||
PermitRootLogin no
|
||||
" 'BEGIN {print TEXT}{print}' /etc/ssh/sshd_config >&3
|
||||
hash service 2>/dev/null && service ssh reload || /etc/init.d/ssh* reload
|
||||
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
|
||||
setupPublicCurl || return 1
|
||||
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 -)
|
||||
mv /usr/local/jdk* /usr/local/jdk/
|
||||
test -n "$SUDO_USER" &&
|
||||
cat >> /home/$SUDO_USER/.bashrc <<-'END_OF_JCLOUDS_FILE'
|
||||
export JAVA_HOME=/usr/local/jdk
|
||||
export PATH=$JAVA_HOME/bin:$PATH
|
||||
END_OF_JCLOUDS_FILE
|
||||
cat >> /etc/bashrc <<-'END_OF_JCLOUDS_FILE'
|
||||
export JAVA_HOME=/usr/local/jdk
|
||||
export PATH=$JAVA_HOME/bin:$PATH
|
||||
END_OF_JCLOUDS_FILE
|
||||
cat >> $HOME/.bashrc <<-'END_OF_JCLOUDS_FILE'
|
||||
export JAVA_HOME=/usr/local/jdk
|
||||
export PATH=$JAVA_HOME/bin:$PATH
|
||||
END_OF_JCLOUDS_FILE
|
||||
cat >> /etc/skel/.bashrc <<-'END_OF_JCLOUDS_FILE'
|
||||
export JAVA_HOME=/usr/local/jdk
|
||||
export PATH=$JAVA_HOME/bin:$PATH
|
||||
END_OF_JCLOUDS_FILE
|
||||
ln -fs /usr/local/jdk/bin/java /usr/bin/java
|
||||
iptables -I INPUT 1 -p tcp --dport 22 -j ACCEPT
|
||||
iptables -I INPUT 1 -p tcp --dport 8080 -j ACCEPT
|
||||
iptables-save
|
||||
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 -)
|
||||
mkdir -p /usr/local/jboss
|
||||
mv /usr/local/jboss-*/* /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
|
||||
cat >> $INSTANCE_HOME/configure-jboss.sh <<'END_OF_SCRIPT'
|
||||
exit 0
|
||||
END_OF_SCRIPT
|
||||
cat >> $INSTANCE_HOME/configure-jboss.sh <<-'END_OF_JCLOUDS_SCRIPT'
|
||||
exit $?
|
||||
|
||||
END_OF_JCLOUDS_SCRIPT
|
||||
|
||||
chmod u+x $INSTANCE_HOME/configure-jboss.sh
|
||||
;;
|
||||
|
@ -160,6 +219,17 @@ start)
|
|||
default || 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)
|
||||
default || exit 1
|
||||
tail $LOG_DIR/stdout.log
|
||||
|
@ -173,4 +243,4 @@ run)
|
|||
$INSTANCE_HOME/$INSTANCE_NAME.sh
|
||||
;;
|
||||
esac
|
||||
exit 0
|
||||
exit $?
|
||||
|
|
|
@ -10,11 +10,11 @@ function abort {
|
|||
function default {
|
||||
export INSTANCE_NAME="runScriptWithCreds"
|
||||
export INSTANCE_HOME="/tmp/runScriptWithCreds"
|
||||
export LOG_DIR="/tmp/runScriptWithCreds"
|
||||
return 0
|
||||
export LOG_DIR="$INSTANCE_HOME"
|
||||
return $?
|
||||
}
|
||||
function runScriptWithCreds {
|
||||
return 0
|
||||
return $?
|
||||
}
|
||||
function findPid {
|
||||
unset FOUND_PID;
|
||||
|
@ -62,54 +62,114 @@ init)
|
|||
mkdir -p $INSTANCE_HOME
|
||||
|
||||
# create runscript header
|
||||
cat > $INSTANCE_HOME/runScriptWithCreds.sh <<END_OF_SCRIPT
|
||||
#!/bin/bash
|
||||
set +u
|
||||
shopt -s xpg_echo
|
||||
shopt -s expand_aliases
|
||||
PROMPT_COMMAND='echo -ne "\033]0;runScriptWithCreds\007"'
|
||||
export PATH=/usr/ucb/bin:/bin:/sbin:/usr/bin:/usr/sbin
|
||||
export INSTANCE_NAME='runScriptWithCreds'
|
||||
export INSTANCE_NAME='$INSTANCE_NAME'
|
||||
export INSTANCE_HOME='$INSTANCE_HOME'
|
||||
export LOG_DIR='$LOG_DIR'
|
||||
END_OF_SCRIPT
|
||||
cat > $INSTANCE_HOME/runScriptWithCreds.sh <<-'END_OF_JCLOUDS_SCRIPT'
|
||||
#!/bin/bash
|
||||
set +u
|
||||
shopt -s xpg_echo
|
||||
shopt -s expand_aliases
|
||||
|
||||
PROMPT_COMMAND='echo -ne \"\033]0;runScriptWithCreds\007\"'
|
||||
export PATH=/usr/ucb/bin:/bin:/sbin:/usr/bin:/usr/sbin
|
||||
|
||||
export INSTANCE_NAME='runScriptWithCreds'
|
||||
END_OF_JCLOUDS_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
|
||||
cat >> $INSTANCE_HOME/runScriptWithCreds.sh <<'END_OF_SCRIPT'
|
||||
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
|
||||
grep `hostname` /etc/hosts >/dev/null || awk -v hostname=`hostname` 'END { print $1" "hostname }' /proc/net/arp >> /etc/hosts
|
||||
nslookup yahoo.com >/dev/null || echo nameserver 208.67.222.222 >> /etc/resolv.conf
|
||||
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
|
||||
mkdir -p /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 -)
|
||||
mv /usr/local/jdk1.7*/* /usr/local/jdk/
|
||||
test -n "$SUDO_USER" &&
|
||||
cat >> /home/$SUDO_USER/.bashrc <<'END_OF_FILE'
|
||||
export JAVA_HOME=/usr/local/jdk
|
||||
export PATH=$JAVA_HOME/bin:$PATH
|
||||
END_OF_FILE
|
||||
cat >> /etc/bashrc <<'END_OF_FILE'
|
||||
export JAVA_HOME=/usr/local/jdk
|
||||
export PATH=$JAVA_HOME/bin:$PATH
|
||||
END_OF_FILE
|
||||
cat >> $HOME/.bashrc <<'END_OF_FILE'
|
||||
export JAVA_HOME=/usr/local/jdk
|
||||
export PATH=$JAVA_HOME/bin:$PATH
|
||||
END_OF_FILE
|
||||
cat >> /etc/skel/.bashrc <<'END_OF_FILE'
|
||||
export JAVA_HOME=/usr/local/jdk
|
||||
export PATH=$JAVA_HOME/bin:$PATH
|
||||
END_OF_FILE
|
||||
ln -fs /usr/local/jdk/bin/java /usr/bin/java
|
||||
cat >> $INSTANCE_HOME/runScriptWithCreds.sh <<-'END_OF_JCLOUDS_SCRIPT'
|
||||
cd $INSTANCE_HOME
|
||||
rm -f $INSTANCE_HOME/rc
|
||||
trap 'echo $?>$INSTANCE_HOME/rc' 0 1 2 3 15
|
||||
setupPublicCurl || exit 1
|
||||
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 -)
|
||||
mv /usr/local/jdk* /usr/local/jdk/
|
||||
test -n "$SUDO_USER" &&
|
||||
cat >> /home/$SUDO_USER/.bashrc <<-'END_OF_JCLOUDS_FILE'
|
||||
export JAVA_HOME=/usr/local/jdk
|
||||
export PATH=$JAVA_HOME/bin:$PATH
|
||||
END_OF_JCLOUDS_FILE
|
||||
cat >> /etc/bashrc <<-'END_OF_JCLOUDS_FILE'
|
||||
export JAVA_HOME=/usr/local/jdk
|
||||
export PATH=$JAVA_HOME/bin:$PATH
|
||||
END_OF_JCLOUDS_FILE
|
||||
cat >> $HOME/.bashrc <<-'END_OF_JCLOUDS_FILE'
|
||||
export JAVA_HOME=/usr/local/jdk
|
||||
export PATH=$JAVA_HOME/bin:$PATH
|
||||
END_OF_JCLOUDS_FILE
|
||||
cat >> /etc/skel/.bashrc <<-'END_OF_JCLOUDS_FILE'
|
||||
export JAVA_HOME=/usr/local/jdk
|
||||
export PATH=$JAVA_HOME/bin:$PATH
|
||||
END_OF_JCLOUDS_FILE
|
||||
ln -fs /usr/local/jdk/bin/java /usr/bin/java
|
||||
|
||||
END_OF_SCRIPT
|
||||
END_OF_JCLOUDS_SCRIPT
|
||||
|
||||
# add runscript footer
|
||||
cat >> $INSTANCE_HOME/runScriptWithCreds.sh <<'END_OF_SCRIPT'
|
||||
exit 0
|
||||
END_OF_SCRIPT
|
||||
cat >> $INSTANCE_HOME/runScriptWithCreds.sh <<-'END_OF_JCLOUDS_SCRIPT'
|
||||
exit $?
|
||||
|
||||
END_OF_JCLOUDS_SCRIPT
|
||||
|
||||
chmod u+x $INSTANCE_HOME/runScriptWithCreds.sh
|
||||
;;
|
||||
|
@ -130,6 +190,17 @@ start)
|
|||
default || 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)
|
||||
default || exit 1
|
||||
tail $LOG_DIR/stdout.log
|
||||
|
@ -143,4 +214,4 @@ run)
|
|||
$INSTANCE_HOME/$INSTANCE_NAME.sh
|
||||
;;
|
||||
esac
|
||||
exit 0
|
||||
exit $?
|
||||
|
|
|
@ -10,11 +10,11 @@ function abort {
|
|||
function default {
|
||||
export INSTANCE_NAME="adminUpdate"
|
||||
export INSTANCE_HOME="/tmp/adminUpdate"
|
||||
export LOG_DIR="/tmp/adminUpdate"
|
||||
return 0
|
||||
export LOG_DIR="$INSTANCE_HOME"
|
||||
return $?
|
||||
}
|
||||
function adminUpdate {
|
||||
return 0
|
||||
return $?
|
||||
}
|
||||
function findPid {
|
||||
unset FOUND_PID;
|
||||
|
@ -62,50 +62,56 @@ init)
|
|||
mkdir -p $INSTANCE_HOME
|
||||
|
||||
# create runscript header
|
||||
cat > $INSTANCE_HOME/adminUpdate.sh <<END_OF_SCRIPT
|
||||
#!/bin/bash
|
||||
set +u
|
||||
shopt -s xpg_echo
|
||||
shopt -s expand_aliases
|
||||
PROMPT_COMMAND='echo -ne "\033]0;adminUpdate\007"'
|
||||
export PATH=/usr/ucb/bin:/bin:/sbin:/usr/bin:/usr/sbin
|
||||
export INSTANCE_NAME='adminUpdate'
|
||||
export INSTANCE_NAME='$INSTANCE_NAME'
|
||||
export INSTANCE_HOME='$INSTANCE_HOME'
|
||||
export LOG_DIR='$LOG_DIR'
|
||||
END_OF_SCRIPT
|
||||
cat > $INSTANCE_HOME/adminUpdate.sh <<-'END_OF_JCLOUDS_SCRIPT'
|
||||
#!/bin/bash
|
||||
set +u
|
||||
shopt -s xpg_echo
|
||||
shopt -s expand_aliases
|
||||
|
||||
PROMPT_COMMAND='echo -ne \"\033]0;adminUpdate\007\"'
|
||||
export PATH=/usr/ucb/bin:/bin:/sbin:/usr/bin:/usr/sbin
|
||||
|
||||
export INSTANCE_NAME='adminUpdate'
|
||||
END_OF_JCLOUDS_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
|
||||
cat >> $INSTANCE_HOME/adminUpdate.sh <<'END_OF_SCRIPT'
|
||||
cd $INSTANCE_HOME
|
||||
rm /etc/sudoers
|
||||
cat >> /etc/sudoers <<'END_OF_FILE'
|
||||
root ALL = (ALL) ALL
|
||||
%wheel ALL = (ALL) NOPASSWD:ALL
|
||||
END_OF_FILE
|
||||
chmod 0440 /etc/sudoers
|
||||
mkdir -p /home/users
|
||||
groupadd -f wheel
|
||||
useradd -s /bin/bash -g wheel -m -d /home/users/foo -p 'crypt(randompassword)' foo
|
||||
mkdir -p /home/users/foo/.ssh
|
||||
cat >> /home/users/foo/.ssh/authorized_keys <<'END_OF_FILE'
|
||||
publicKey
|
||||
END_OF_FILE
|
||||
chmod 600 /home/users/foo/.ssh/authorized_keys
|
||||
chown -R foo /home/users/foo
|
||||
exec 3<> /etc/ssh/sshd_config && awk -v TEXT="PasswordAuthentication no
|
||||
PermitRootLogin no
|
||||
" 'BEGIN {print TEXT}{print}' /etc/ssh/sshd_config >&3
|
||||
/etc/init.d/sshd reload||/etc/init.d/ssh reload
|
||||
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
|
||||
cat >> $INSTANCE_HOME/adminUpdate.sh <<-'END_OF_JCLOUDS_SCRIPT'
|
||||
cd $INSTANCE_HOME
|
||||
rm -f $INSTANCE_HOME/rc
|
||||
trap 'echo $?>$INSTANCE_HOME/rc' 0 1 2 3 15
|
||||
cat > /etc/sudoers <<-'END_OF_JCLOUDS_FILE'
|
||||
root ALL = (ALL) ALL
|
||||
%wheel ALL = (ALL) NOPASSWD:ALL
|
||||
END_OF_JCLOUDS_FILE
|
||||
chmod 0440 /etc/sudoers
|
||||
mkdir -p /home/users
|
||||
groupadd -f wheel
|
||||
useradd -s /bin/bash -g wheel -m -d /home/users/foo -p 'crypt(randompassword)' foo
|
||||
mkdir -p /home/users/foo/.ssh
|
||||
cat >> /home/users/foo/.ssh/authorized_keys <<-'END_OF_JCLOUDS_FILE'
|
||||
publicKey
|
||||
END_OF_JCLOUDS_FILE
|
||||
chmod 600 /home/users/foo/.ssh/authorized_keys
|
||||
chown -R foo /home/users/foo
|
||||
exec 3<> /etc/ssh/sshd_config && awk -v TEXT="PasswordAuthentication no
|
||||
PermitRootLogin no
|
||||
" 'BEGIN {print TEXT}{print}' /etc/ssh/sshd_config >&3
|
||||
hash service 2>/dev/null && service ssh reload || /etc/init.d/ssh* reload
|
||||
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
|
||||
cat >> $INSTANCE_HOME/adminUpdate.sh <<'END_OF_SCRIPT'
|
||||
exit 0
|
||||
END_OF_SCRIPT
|
||||
cat >> $INSTANCE_HOME/adminUpdate.sh <<-'END_OF_JCLOUDS_SCRIPT'
|
||||
exit $?
|
||||
|
||||
END_OF_JCLOUDS_SCRIPT
|
||||
|
||||
chmod u+x $INSTANCE_HOME/adminUpdate.sh
|
||||
;;
|
||||
|
@ -126,6 +132,17 @@ start)
|
|||
default || 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)
|
||||
default || exit 1
|
||||
tail $LOG_DIR/stdout.log
|
||||
|
@ -139,4 +156,4 @@ run)
|
|||
$INSTANCE_HOME/$INSTANCE_NAME.sh
|
||||
;;
|
||||
esac
|
||||
exit 0
|
||||
exit $?
|
||||
|
|
|
@ -10,12 +10,12 @@ function abort {
|
|||
function default {
|
||||
export INSTANCE_NAME="jboss"
|
||||
export INSTANCE_HOME="/usr/local/jboss"
|
||||
export LOG_DIR="/usr/local/jboss"
|
||||
return 0
|
||||
export LOG_DIR="$INSTANCE_HOME"
|
||||
return $?
|
||||
}
|
||||
function jboss {
|
||||
export JBOSS_HOME="/usr/local/jboss"
|
||||
return 0
|
||||
return $?
|
||||
}
|
||||
function findPid {
|
||||
unset FOUND_PID;
|
||||
|
@ -60,10 +60,10 @@ case $1 in
|
|||
init)
|
||||
default || exit 1
|
||||
jboss || exit 1
|
||||
cat >> /usr/local/jboss/standalone/configuration/standalone-custom.xml <<'END_OF_FILE'
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
cat >> /usr/local/jboss/standalone/configuration/standalone-custom.xml <<-'END_OF_JCLOUDS_FILE'
|
||||
<?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>
|
||||
<extension module="org.jboss.as.connector"/>
|
||||
<extension module="org.jboss.as.deployment-scanner"/>
|
||||
|
@ -163,36 +163,43 @@ init)
|
|||
<socket-binding name="txn-recovery-environment" port="4712"/>
|
||||
<socket-binding name="txn-status-manager" port="4713"/>
|
||||
</socket-binding-group>
|
||||
</server>
|
||||
</server>
|
||||
|
||||
END_OF_FILE
|
||||
END_OF_JCLOUDS_FILE
|
||||
mkdir -p $INSTANCE_HOME
|
||||
|
||||
# create runscript header
|
||||
cat > $INSTANCE_HOME/jboss.sh <<END_OF_SCRIPT
|
||||
#!/bin/bash
|
||||
set +u
|
||||
shopt -s xpg_echo
|
||||
shopt -s expand_aliases
|
||||
PROMPT_COMMAND='echo -ne "\033]0;jboss\007"'
|
||||
export PATH=/usr/ucb/bin:/bin:/sbin:/usr/bin:/usr/sbin
|
||||
export INSTANCE_NAME='jboss'
|
||||
export JBOSS_HOME='$JBOSS_HOME'
|
||||
export INSTANCE_NAME='$INSTANCE_NAME'
|
||||
export INSTANCE_HOME='$INSTANCE_HOME'
|
||||
export LOG_DIR='$LOG_DIR'
|
||||
END_OF_SCRIPT
|
||||
cat > $INSTANCE_HOME/jboss.sh <<-'END_OF_JCLOUDS_SCRIPT'
|
||||
#!/bin/bash
|
||||
set +u
|
||||
shopt -s xpg_echo
|
||||
shopt -s expand_aliases
|
||||
|
||||
PROMPT_COMMAND='echo -ne \"\033]0;jboss\007\"'
|
||||
export PATH=/usr/ucb/bin:/bin:/sbin:/usr/bin:/usr/sbin
|
||||
|
||||
export INSTANCE_NAME='jboss'
|
||||
END_OF_JCLOUDS_SCRIPT
|
||||
cat >> $INSTANCE_HOME/jboss.sh <<-END_OF_JCLOUDS_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
|
||||
cat >> $INSTANCE_HOME/jboss.sh <<'END_OF_SCRIPT'
|
||||
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
|
||||
END_OF_SCRIPT
|
||||
cat >> $INSTANCE_HOME/jboss.sh <<-'END_OF_JCLOUDS_SCRIPT'
|
||||
cd $INSTANCE_HOME
|
||||
rm -f $INSTANCE_HOME/rc
|
||||
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
|
||||
cat >> $INSTANCE_HOME/jboss.sh <<'END_OF_SCRIPT'
|
||||
exit 0
|
||||
END_OF_SCRIPT
|
||||
cat >> $INSTANCE_HOME/jboss.sh <<-'END_OF_JCLOUDS_SCRIPT'
|
||||
exit $?
|
||||
|
||||
END_OF_JCLOUDS_SCRIPT
|
||||
|
||||
chmod u+x $INSTANCE_HOME/jboss.sh
|
||||
;;
|
||||
|
@ -213,6 +220,17 @@ start)
|
|||
default || 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)
|
||||
default || exit 1
|
||||
tail $LOG_DIR/stdout.log
|
||||
|
@ -226,4 +244,4 @@ run)
|
|||
$INSTANCE_HOME/$INSTANCE_NAME.sh
|
||||
;;
|
||||
esac
|
||||
exit 0
|
||||
exit $?
|
||||
|
|
|
@ -132,7 +132,7 @@
|
|||
<configuration>
|
||||
<instructions>
|
||||
<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>
|
||||
</instructions>
|
||||
</configuration>
|
||||
|
|
|
@ -45,6 +45,8 @@ import org.jclouds.lifecycle.Closer;
|
|||
import org.jclouds.logging.Logger;
|
||||
|
||||
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.inject.AbstractModule;
|
||||
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
|
||||
@Singleton
|
||||
@Named(Constants.PROPERTY_USER_THREADS)
|
||||
|
|
|
@ -21,6 +21,7 @@ package org.jclouds.predicates;
|
|||
import static org.jclouds.util.Throwables2.getFirstThrowableOfType;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.concurrent.CancellationException;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
@ -88,6 +89,9 @@ public class RetryablePredicate<T> implements Predicate<T> {
|
|||
} else if (getFirstThrowableOfType(e, IllegalStateException.class) != null) {
|
||||
logger.warn(e, "predicate %s on %s illegal state [%s], returning false", input, predicate, e.getMessage());
|
||||
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) {
|
||||
logger.warn(e, "predicate %s on %s timed out [%s], returning false", input, predicate, e.getMessage());
|
||||
return false;
|
||||
|
|
|
@ -21,6 +21,7 @@ package org.jclouds.rest;
|
|||
import java.util.concurrent.ExecutorService;
|
||||
|
||||
import com.google.common.annotations.Beta;
|
||||
import com.google.common.eventbus.EventBus;
|
||||
import com.google.inject.Injector;
|
||||
import org.jclouds.crypto.Crypto;
|
||||
import org.jclouds.date.DateService;
|
||||
|
@ -88,6 +89,11 @@ public interface Utils {
|
|||
*/
|
||||
ExecutorService ioExecutor();
|
||||
|
||||
@Beta
|
||||
EventBus getEventBus();
|
||||
|
||||
EventBus eventBus();
|
||||
|
||||
LoggerFactory getLoggerFactory();
|
||||
|
||||
/**
|
||||
|
@ -104,4 +110,5 @@ public interface Utils {
|
|||
*/
|
||||
@Beta
|
||||
Injector injector();
|
||||
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ import javax.inject.Inject;
|
|||
import javax.inject.Named;
|
||||
|
||||
import com.google.common.annotations.Beta;
|
||||
import com.google.common.eventbus.EventBus;
|
||||
import com.google.inject.Injector;
|
||||
import org.jclouds.Constants;
|
||||
import org.jclouds.crypto.Crypto;
|
||||
|
@ -49,14 +50,15 @@ public class UtilsImpl implements Utils {
|
|||
private final DateService date;
|
||||
private final ExecutorService userExecutor;
|
||||
private final ExecutorService ioExecutor;
|
||||
private final EventBus eventBus;
|
||||
private final LoggerFactory loggerFactory;
|
||||
private Injector injector;
|
||||
|
||||
@Inject
|
||||
protected UtilsImpl(Injector injector, Json json, HttpClient simpleClient, HttpAsyncClient simpleAsyncClient,
|
||||
Crypto encryption, DateService date,
|
||||
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService userThreads,
|
||||
@Named(Constants.PROPERTY_IO_WORKER_THREADS) ExecutorService ioThreads, LoggerFactory loggerFactory) {
|
||||
Crypto encryption, DateService date, @Named(Constants.PROPERTY_USER_THREADS) ExecutorService userThreads,
|
||||
@Named(Constants.PROPERTY_IO_WORKER_THREADS) ExecutorService ioThreads, EventBus eventBus,
|
||||
LoggerFactory loggerFactory) {
|
||||
this.injector = injector;
|
||||
this.json = json;
|
||||
this.simpleClient = simpleClient;
|
||||
|
@ -65,6 +67,7 @@ public class UtilsImpl implements Utils {
|
|||
this.date = date;
|
||||
this.userExecutor = userThreads;
|
||||
this.ioExecutor = ioThreads;
|
||||
this.eventBus = eventBus;
|
||||
this.loggerFactory = loggerFactory;
|
||||
}
|
||||
|
||||
|
@ -128,6 +131,16 @@ public class UtilsImpl implements Utils {
|
|||
return userExecutor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EventBus getEventBus() {
|
||||
return eventBus;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EventBus eventBus() {
|
||||
return eventBus;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LoggerFactory getLoggerFactory() {
|
||||
return loggerFactory;
|
||||
|
|
|
@ -28,6 +28,7 @@ import java.util.concurrent.TimeUnit;
|
|||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Objects;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.base.Suppliers;
|
||||
|
@ -144,5 +145,28 @@ public class Suppliers2 {
|
|||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
package org.jclouds.demo.tweetstore.integration;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.io.Closeables.closeQuietly;
|
||||
import static java.lang.String.format;
|
||||
|
||||
import java.io.File;
|
||||
|
@ -45,7 +46,7 @@ public class GoogleDevServer {
|
|||
String filename = String.format(
|
||||
"%1$s/WEB-INF/jclouds.properties", warfile);
|
||||
System.err.println("file: " + filename);
|
||||
props.store(new FileOutputStream(filename), "test");
|
||||
storeProperties(filename, props);
|
||||
assert new File(filename).exists();
|
||||
this.server = new Thread(new Runnable() {
|
||||
public void run() {
|
||||
|
@ -64,6 +65,15 @@ public class GoogleDevServer {
|
|||
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 {
|
||||
// KickStart.main opens a process and calls process.waitFor(), which is interruptable
|
||||
server.interrupt();
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
package org.jclouds.demo.tweetstore.integration;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.io.Closeables.closeQuietly;
|
||||
import static java.lang.String.format;
|
||||
|
||||
import java.io.File;
|
||||
|
@ -45,7 +46,7 @@ public class GoogleDevServer {
|
|||
String filename = String.format(
|
||||
"%1$s/WEB-INF/jclouds.properties", warfile);
|
||||
System.err.println("file: " + filename);
|
||||
props.store(new FileOutputStream(filename), "test");
|
||||
storeProperties(filename, props);
|
||||
assert new File(filename).exists();
|
||||
this.server = new Thread(new Runnable() {
|
||||
public void run() {
|
||||
|
@ -64,6 +65,15 @@ public class GoogleDevServer {
|
|||
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 {
|
||||
// KickStart.main opens a process and calls process.waitFor(), which is interruptable
|
||||
server.interrupt();
|
||||
|
|
|
@ -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>
|
|
@ -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>
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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
Loading…
Reference in New Issue