diff --git a/antcontrib/src/main/java/org/jclouds/tools/ant/taskdefs/sshjava/SSHJava.java b/antcontrib/src/main/java/org/jclouds/tools/ant/taskdefs/sshjava/SSHJava.java index 9b0695a288..28c450f573 100644 --- a/antcontrib/src/main/java/org/jclouds/tools/ant/taskdefs/sshjava/SSHJava.java +++ b/antcontrib/src/main/java/org/jclouds/tools/ant/taskdefs/sshjava/SSHJava.java @@ -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 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. 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); } diff --git a/apis/atmos/pom.xml b/apis/atmos/pom.xml index 6cfd93ac09..5a794c889f 100644 --- a/apis/atmos/pom.xml +++ b/apis/atmos/pom.xml @@ -118,8 +118,8 @@ ${project.artifactId} - org.jclouds.atmos.*;version="${project.version}" - org.jclouds.*;version="${project.version}",* + org.jclouds.atmos*;version="${project.version}" + org.jclouds*;version="${project.version}",* diff --git a/apis/byon/pom.xml b/apis/byon/pom.xml index 2b0efeea58..345daf1b40 100644 --- a/apis/byon/pom.xml +++ b/apis/byon/pom.xml @@ -113,11 +113,11 @@ ${project.artifactId} - org.jclouds.byon.*;version="${project.version}" + org.jclouds.byon*;version="${project.version}" org.jclouds.compute.internal;version="${project.version}", org.jclouds.rest.internal;version="${project.version}", - org.jclouds.*;version="${project.version}", + org.jclouds*;version="${project.version}", * diff --git a/apis/cloudfiles/pom.xml b/apis/cloudfiles/pom.xml index 6191d5d1e1..a7bb4b0e4a 100644 --- a/apis/cloudfiles/pom.xml +++ b/apis/cloudfiles/pom.xml @@ -133,8 +133,12 @@ ${project.artifactId} - org.jclouds.cloudfiles.*;version="${project.version}" - org.jclouds.*;version="${project.version}",* + org.jclouds.cloudfiles*;version="${project.version}" + + org.jclouds*;version="${project.version}", + org.jclouds.openstack.swift.options;version="${project.version}", + * + diff --git a/apis/cloudloadbalancers/pom.xml b/apis/cloudloadbalancers/pom.xml index b26778163f..c2a1e088e7 100644 --- a/apis/cloudloadbalancers/pom.xml +++ b/apis/cloudloadbalancers/pom.xml @@ -119,8 +119,8 @@ ${project.artifactId} - org.jclouds.cloudloadbalancers.*;version="${project.version}" - org.jclouds.*;version="${project.version}",* + org.jclouds.cloudloadbalancers*;version="${project.version}" + org.jclouds*;version="${project.version}",* diff --git a/apis/cloudservers/pom.xml b/apis/cloudservers/pom.xml index 0b187cee8f..d3ecc8fd3e 100644 --- a/apis/cloudservers/pom.xml +++ b/apis/cloudservers/pom.xml @@ -134,11 +134,11 @@ ${project.artifactId} - org.jclouds.cloudservers.*;version="${project.version}" + org.jclouds.cloudservers*;version="${project.version}" org.jclouds.compute.internal;version="${project.version}", org.jclouds.rest.internal;version="${project.version}", - org.jclouds.*;version="${project.version}", + org.jclouds*;version="${project.version}", * diff --git a/apis/cloudservers/src/main/java/org/jclouds/cloudservers/compute/functions/ServerToNodeMetadata.java b/apis/cloudservers/src/main/java/org/jclouds/cloudservers/compute/functions/ServerToNodeMetadata.java index 8380930236..856e952df6 100644 --- a/apis/cloudservers/src/main/java/org/jclouds/cloudservers/compute/functions/ServerToNodeMetadata.java +++ b/apis/cloudservers/src/main/java/org/jclouds/cloudservers/compute/functions/ServerToNodeMetadata.java @@ -132,7 +132,7 @@ public class ServerToNodeMetadata implements Function { 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; } diff --git a/apis/cloudsigma/pom.xml b/apis/cloudsigma/pom.xml index 83eb16b6a5..abb3643b4a 100644 --- a/apis/cloudsigma/pom.xml +++ b/apis/cloudsigma/pom.xml @@ -120,11 +120,11 @@ ${project.artifactId} - org.jclouds.cloudsigma.*;version="${project.version}" + org.jclouds.cloudsigma*;version="${project.version}" org.jclouds.compute.internal;version="${project.version}", org.jclouds.rest.internal;version="${project.version}", - org.jclouds.*;version="${project.version}", + org.jclouds*;version="${project.version}", * diff --git a/apis/cloudstack/pom.xml b/apis/cloudstack/pom.xml index 2925289915..390d4e6a63 100644 --- a/apis/cloudstack/pom.xml +++ b/apis/cloudstack/pom.xml @@ -144,11 +144,11 @@ ${project.artifactId} - org.jclouds.cloudstack.*;version="${project.version}" + org.jclouds.cloudstack*;version="${project.version}" org.jclouds.compute.internal;version="${project.version}", org.jclouds.rest.internal;version="${project.version}", - org.jclouds.*;version="${project.version}", + org.jclouds*;version="${project.version}", * diff --git a/apis/cloudwatch/pom.xml b/apis/cloudwatch/pom.xml index e62ad646f5..0a8d58437b 100644 --- a/apis/cloudwatch/pom.xml +++ b/apis/cloudwatch/pom.xml @@ -109,8 +109,8 @@ ${project.artifactId} - org.jclouds.cloudwatch.*;version="${project.version}" - org.jclouds.*;version="${project.version}",* + org.jclouds.cloudwatch*;version="${project.version}" + org.jclouds*;version="${project.version}",* diff --git a/apis/deltacloud/pom.xml b/apis/deltacloud/pom.xml index 03df3ef1d5..8f8e467f42 100644 --- a/apis/deltacloud/pom.xml +++ b/apis/deltacloud/pom.xml @@ -133,11 +133,11 @@ ${project.artifactId} - org.jclouds.deltacloud.*;version="${project.version}" + org.jclouds.deltacloud*;version="${project.version}" org.jclouds.compute.internal;version="${project.version}", org.jclouds.rest.internal;version="${project.version}", - org.jclouds.*;version="${project.version}", + org.jclouds*;version="${project.version}", * diff --git a/apis/ec2/pom.xml b/apis/ec2/pom.xml index f237bfab14..08d90c6424 100644 --- a/apis/ec2/pom.xml +++ b/apis/ec2/pom.xml @@ -134,11 +134,11 @@ ${project.artifactId} - org.jclouds.ec2.*;version="${project.version}" + org.jclouds.ec2*;version="${project.version}" org.jclouds.compute.internal;version="${project.version}", org.jclouds.rest.internal;version="${project.version}", - org.jclouds.*;version="${project.version}", + org.jclouds*;version="${project.version}", * diff --git a/apis/ec2/src/main/clojure/org/jclouds/ec2/ebs.clj b/apis/ec2/src/main/clojure/org/jclouds/ec2/ebs.clj deleted file mode 100644 index bb06f27334..0000000000 --- a/apis/ec2/src/main/clojure/org/jclouds/ec2/ebs.clj +++ /dev/null @@ -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))) \ No newline at end of file diff --git a/apis/ec2/src/main/clojure/org/jclouds/ec2/elastic_ip.clj b/apis/ec2/src/main/clojure/org/jclouds/ec2/elastic_ip.clj deleted file mode 100644 index 6c52c4cc7f..0000000000 --- a/apis/ec2/src/main/clojure/org/jclouds/ec2/elastic_ip.clj +++ /dev/null @@ -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))) diff --git a/apis/ec2/src/main/java/org/jclouds/ec2/compute/EC2ComputeService.java b/apis/ec2/src/main/java/org/jclouds/ec2/compute/EC2ComputeService.java index 7c40c79eeb..5601886c75 100644 --- a/apis/ec2/src/main/java/org/jclouds/ec2/compute/EC2ComputeService.java +++ b/apis/ec2/src/main/java/org/jclouds/ec2/compute/EC2ComputeService.java @@ -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 templateBuilderProvider, Provider templateOptionsProvider, - @Named("NODE_RUNNING") Predicate nodeRunning, - @Named("NODE_TERMINATED") Predicate nodeTerminated, - @Named("NODE_SUSPENDED") Predicate nodeSuspended, + @Named("NODE_RUNNING") Predicate> nodeRunning, + @Named("NODE_TERMINATED") Predicate> nodeTerminated, + @Named("NODE_SUSPENDED") Predicate> nodeSuspended, InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory, RunScriptOnNode.Factory runScriptOnNodeFactory, InitAdminAccess initAdminAccess, PersistNodeCredentials persistNodeCredentials, Timeouts timeouts, diff --git a/apis/ec2/src/main/java/org/jclouds/ec2/compute/strategy/EC2CreateNodesInGroupThenAddToSet.java b/apis/ec2/src/main/java/org/jclouds/ec2/compute/strategy/EC2CreateNodesInGroupThenAddToSet.java index ad06974430..cb58017980 100644 --- a/apis/ec2/src/main/java/org/jclouds/ec2/compute/strategy/EC2CreateNodesInGroupThenAddToSet.java +++ b/apis/ec2/src/main/java/org/jclouds/ec2/compute/strategy/EC2CreateNodesInGroupThenAddToSet.java @@ -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 nodeRunning; + final Predicate> nodeRunning; @VisibleForTesting final LoadingCache elasticIpCache; @VisibleForTesting @@ -101,7 +102,7 @@ public class EC2CreateNodesInGroupThenAddToSet implements CreateNodesInGroupThen EC2Client client, @Named("ELASTICIP") LoadingCache elasticIpCache, - @Named("NODE_RUNNING") Predicate nodeRunning, + @Named("NODE_RUNNING") Predicate> nodeRunning, Provider templateBuilderProvider, CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions createKeyPairAndSecurityGroupsAsNeededAndReturncustomize, InstancePresent instancePresent, Function 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 node = new AtomicReference(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); diff --git a/apis/ec2/src/test/java/org/jclouds/ec2/EBSBootEC2ClientLiveTest.java b/apis/ec2/src/test/java/org/jclouds/ec2/EBSBootEC2ClientLiveTest.java index 04819b55a1..077cf7953b 100644 --- a/apis/ec2/src/test/java/org/jclouds/ec2/EBSBootEC2ClientLiveTest.java +++ b/apis/ec2/src/test/java/org/jclouds/ec2/EBSBootEC2ClientLiveTest.java @@ -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. 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); } diff --git a/apis/ec2/src/test/java/org/jclouds/ec2/compute/strategy/EC2CreateNodesInGroupThenAddToSetTest.java b/apis/ec2/src/test/java/org/jclouds/ec2/compute/strategy/EC2CreateNodesInGroupThenAddToSetTest.java index 328e161c54..6f89f7f057 100644 --- a/apis/ec2/src/test/java/org/jclouds/ec2/compute/strategy/EC2CreateNodesInGroupThenAddToSetTest.java +++ b/apis/ec2/src/test/java/org/jclouds/ec2/compute/strategy/EC2CreateNodesInGroupThenAddToSetTest.java @@ -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 reservation = new Reservation(region, ImmutableSet - . of(), ImmutableSet. of(instance), "ownerId", "requesterId", "reservationId"); - NodeMetadata nodeMetadata = createMock(NodeMetadata.class); + Reservation reservation = new Reservation(region, + ImmutableSet. of(), ImmutableSet. 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,12 +110,11 @@ 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"); expect(instanceClient.runInstancesInRegion(region, zone, imageId, 1, input.count, ec2Options)).andReturn( - Reservation.class.cast(reservation)); + Reservation.class.cast(reservation)); expect(instance.getId()).andReturn(instanceCreatedId).atLeastOnce(); // simulate a lazy credentials fetch Credentials creds = new Credentials("foo", "bar"); @@ -121,9 +126,9 @@ public class EC2CreateNodesInGroupThenAddToSetTest { expect(input.template.getOptions()).andReturn(input.options).atLeastOnce(); expect( - strategy.utils.customizeNodesAndAddToGoodMapOrPutExceptionIntoBadMap(eq(input.options), - containsNodeMetadata(nodeMetadata), eq(input.nodes), eq(input.badNodes), - eq(input.customization))).andReturn(null); + strategy.utils.customizeNodesAndAddToGoodMapOrPutExceptionIntoBadMap(eq(input.options), + 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,29 +187,32 @@ 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 reservation = new Reservation(region, ImmutableSet - . of(), ImmutableSet. of(instance), "ownerId", "requesterId", "reservationId"); - NodeMetadata nodeMetadata = createMock(NodeMetadata.class); + Reservation reservation = new Reservation(region, + ImmutableSet. of(), ImmutableSet. 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(); expect(instanceClient.runInstancesInRegion(region, zone, imageId, 1, input.count, ec2Options)).andReturn( - Reservation.class.cast(reservation)); + Reservation.class.cast(reservation)); expect(instance.getId()).andReturn(instanceCreatedId).atLeastOnce(); // simulate a lazy credentials fetch Credentials creds = new Credentials("foo", "bar"); @@ -219,16 +225,15 @@ 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); + strategy.utils.customizeNodesAndAddToGoodMapOrPutExceptionIntoBadMap(eq(input.options), + 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,26 +307,33 @@ 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 instanceToCredentials = createMock(LoadingCache.class); LoadingCache elasticIpCache = createMock(LoadingCache.class); - Predicate nodeRunning = createMock(Predicate.class); + GetNodeMetadataStrategy nodeRunning = new GetNodeMetadataStrategy(){ + + @Override + public NodeMetadata getNode(String input) { + Assert.assertEquals(input, node.getId()); + return node; + } + + }; Map credentialStore = createMock(Map.class); ComputeUtils utils = createMock(ComputeUtils.class); - return new EC2CreateNodesInGroupThenAddToSet(client, elasticIpCache, nodeRunning, Providers - . of(template), createKeyPairAndSecurityGroupsAsNeededAndReturncustomize, - instancePresent, runningInstanceToNodeMetadata, instanceToCredentials, credentialStore, utils); + return new EC2CreateNodesInGroupThenAddToSet(client, elasticIpCache, new AtomicNodeRunning(nodeRunning), + Providers. of(template), createKeyPairAndSecurityGroupsAsNeededAndReturncustomize, + instancePresent, runningInstanceToNodeMetadata, instanceToCredentials, credentialStore, utils); } private void replayStrategy(EC2CreateNodesInGroupThenAddToSet strategy) { replay(strategy.createKeyPairAndSecurityGroupsAsNeededAndReturncustomize); replay(strategy.client); replay(strategy.elasticIpCache); - replay(strategy.nodeRunning); replay(strategy.instancePresent); replay(strategy.runningInstanceToNodeMetadata); replay(strategy.instanceToCredentials); diff --git a/apis/elasticstack/pom.xml b/apis/elasticstack/pom.xml index 027002d3a1..dd17c4e8d2 100644 --- a/apis/elasticstack/pom.xml +++ b/apis/elasticstack/pom.xml @@ -133,11 +133,11 @@ ${project.artifactId} - org.jclouds.elasticstack.*;version="${project.version}" + org.jclouds.elasticstack*;version="${project.version}" org.jclouds.compute.internal;version="${project.version}", org.jclouds.rest.internal;version="${project.version}", - org.jclouds.*;version="${project.version}", + org.jclouds*;version="${project.version}", * diff --git a/apis/eucalyptus/pom.xml b/apis/eucalyptus/pom.xml index 430560c16c..af22df3166 100644 --- a/apis/eucalyptus/pom.xml +++ b/apis/eucalyptus/pom.xml @@ -128,11 +128,11 @@ ${project.artifactId} - org.jclouds.eucalyptus.*;version="${project.version}" + org.jclouds.eucalyptus*;version="${project.version}" org.jclouds.compute.internal;version="${project.version}", org.jclouds.rest.internal;version="${project.version}", - org.jclouds.*;version="${project.version}", + org.jclouds*;version="${project.version}", * diff --git a/apis/filesystem/pom.xml b/apis/filesystem/pom.xml index cf0e685d8d..84628b2cf9 100644 --- a/apis/filesystem/pom.xml +++ b/apis/filesystem/pom.xml @@ -106,8 +106,8 @@ ${project.artifactId} - org.jclouds.filesystem.*;version="${project.version}" - org.jclouds.*;version="${project.version}",* + org.jclouds.filesystem*;version="${project.version}" + org.jclouds*;version="${project.version}",* diff --git a/apis/nova/pom.xml b/apis/nova/pom.xml index 41978c048c..b308f8cef2 100644 --- a/apis/nova/pom.xml +++ b/apis/nova/pom.xml @@ -1,153 +1,153 @@ - - - - 4.0.0 - - org.jclouds - jclouds-project - 1.5.0-SNAPSHOT - ../../project/pom.xml - - org.jclouds.api - nova - jcloud nova api - jclouds components to access an implementation of OpenStack Nova - bundle - - - http://localhost:8773/services/Cloud - 1.1 - - FIXME_IDENTITY - FIXME_CREDENTIALS - - - - - - - - - - org.jclouds.common - openstack-common - ${project.version} - - - org.jclouds - jclouds-compute - ${project.version} - - - org.jclouds - jclouds-core - ${project.version} - test-jar - test - - - org.jclouds.common - openstack-common - ${project.version} - test-jar - test - - - org.jclouds - jclouds-compute - ${project.version} - test-jar - test - - - org.jclouds.driver - jclouds-sshj - ${project.version} - test - - - org.jclouds.driver - jclouds-log4j - ${project.version} - test - - - - - - live - - - - org.apache.maven.plugins - maven-surefire-plugin - - - integration - integration-test - - test - - - - ${test.nova.endpoint} - ${test.nova.api-version} - ${test.nova.build-version} - ${test.nova.identity} - ${test.nova.credential} - ${test.nova.image-id} - ${test.nova.image.login-user} - ${test.nova.image.authenticate-sudo} - ${test.ssh.keyfile.public} - ${test.ssh.keyfile.private} - - - - - - - - - - - - - - org.apache.felix - maven-bundle-plugin - - - ${project.artifactId} - org.jclouds.openstack.nova.*;version="${project.version}" - - org.jclouds.compute.internal;version="${project.version}", - org.jclouds.rest.internal;version="${project.version}", - org.jclouds.*;version="${project.version}", - * - - - - - - - - + + + + 4.0.0 + + org.jclouds + jclouds-project + 1.5.0-SNAPSHOT + ../../project/pom.xml + + org.jclouds.api + nova + jcloud nova api + jclouds components to access an implementation of OpenStack Nova + bundle + + + http://localhost:8773/services/Cloud + 1.1 + + FIXME_IDENTITY + FIXME_CREDENTIALS + + + + + + + + + + org.jclouds.common + openstack-common + ${project.version} + + + org.jclouds + jclouds-compute + ${project.version} + + + org.jclouds + jclouds-core + ${project.version} + test-jar + test + + + org.jclouds.common + openstack-common + ${project.version} + test-jar + test + + + org.jclouds + jclouds-compute + ${project.version} + test-jar + test + + + org.jclouds.driver + jclouds-sshj + ${project.version} + test + + + org.jclouds.driver + jclouds-log4j + ${project.version} + test + + + + + + live + + + + org.apache.maven.plugins + maven-surefire-plugin + + + integration + integration-test + + test + + + + ${test.nova.endpoint} + ${test.nova.api-version} + ${test.nova.build-version} + ${test.nova.identity} + ${test.nova.credential} + ${test.nova.image-id} + ${test.nova.image.login-user} + ${test.nova.image.authenticate-sudo} + ${test.ssh.keyfile.public} + ${test.ssh.keyfile.private} + + + + + + + + + + + + + + org.apache.felix + maven-bundle-plugin + + + ${project.artifactId} + org.jclouds.openstack.nova*;version="${project.version}" + + org.jclouds.compute.internal;version="${project.version}", + org.jclouds.rest.internal;version="${project.version}", + org.jclouds*;version="${project.version}", + * + + + + + + + + diff --git a/apis/nova/src/main/java/org/jclouds/openstack/nova/compute/functions/ServerToNodeMetadata.java b/apis/nova/src/main/java/org/jclouds/openstack/nova/compute/functions/ServerToNodeMetadata.java index 42955b7348..ab609777f1 100644 --- a/apis/nova/src/main/java/org/jclouds/openstack/nova/compute/functions/ServerToNodeMetadata.java +++ b/apis/nova/src/main/java/org/jclouds/openstack/nova/compute/functions/ServerToNodeMetadata.java @@ -135,7 +135,7 @@ public class ServerToNodeMetadata implements Function { 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; } diff --git a/apis/s3/pom.xml b/apis/s3/pom.xml index fd009c0f1d..470ba6ccbf 100644 --- a/apis/s3/pom.xml +++ b/apis/s3/pom.xml @@ -131,8 +131,8 @@ ${project.artifactId} - org.jclouds.s3.*;version="${project.version}" - org.jclouds.*;version="${project.version}",* + org.jclouds.s3*;version="${project.version}" + org.jclouds*;version="${project.version}",* diff --git a/apis/swift/pom.xml b/apis/swift/pom.xml index 892e84383c..eb6f620847 100644 --- a/apis/swift/pom.xml +++ b/apis/swift/pom.xml @@ -131,8 +131,8 @@ ${project.artifactId} - org.jclouds.openstack.swift.*;version="${project.version}" - org.jclouds.*;version="${project.version}",* + org.jclouds.openstack.swift*;version="${project.version}" + org.jclouds*;version="${project.version}",* diff --git a/apis/vcloud/pom.xml b/apis/vcloud/pom.xml index c81357b4d8..91e9385e4e 100644 --- a/apis/vcloud/pom.xml +++ b/apis/vcloud/pom.xml @@ -131,11 +131,11 @@ ${project.artifactId} - org.jclouds.vcloud.*;version="${project.version}" + org.jclouds.vcloud*;version="${project.version}" org.jclouds.compute.internal;version="${project.version}", org.jclouds.rest.internal;version="${project.version}", - org.jclouds.*;version="${project.version}", + org.jclouds*;version="${project.version}", * diff --git a/apis/walrus/pom.xml b/apis/walrus/pom.xml index a9feae25ab..96d9236c1b 100644 --- a/apis/walrus/pom.xml +++ b/apis/walrus/pom.xml @@ -127,8 +127,8 @@ ${project.artifactId} - org.jclouds.walrus.*;version="${project.version}" - org.jclouds.*;version="${project.version}",* + org.jclouds.walrus*;version="${project.version}" + org.jclouds*;version="${project.version}",* diff --git a/blobstore/pom.xml b/blobstore/pom.xml index 61f2e9f8d4..7a3ebe5522 100644 --- a/blobstore/pom.xml +++ b/blobstore/pom.xml @@ -97,8 +97,8 @@ ${project.artifactId} - org.jclouds.blobstore.*;version="${project.version}" - org.jclouds.*;version="${project.version}",* + org.jclouds.blobstore*;version="${project.version}" + org.jclouds*;version="${project.version}",* jclouds-core;bundle-version="[1.3,2)" diff --git a/blobstore/src/main/clojure/org/jclouds/blobstore.clj b/blobstore/src/main/clojure/org/jclouds/blobstore.clj deleted file mode 100644 index c27e95bcb0..0000000000 --- a/blobstore/src/main/clojure/org/jclouds/blobstore.clj +++ /dev/null @@ -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)) diff --git a/blobstore/src/test/clojure/org/jclouds/blobstore_test.clj b/blobstore/src/test/clojure/org/jclouds/blobstore_test.clj deleted file mode 100644 index 54318f5591..0000000000 --- a/blobstore/src/test/clojure/org/jclouds/blobstore_test.clj +++ /dev/null @@ -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))))))) diff --git a/common/aws/pom.xml b/common/aws/pom.xml index 9139a1e046..91d129daa1 100644 --- a/common/aws/pom.xml +++ b/common/aws/pom.xml @@ -56,8 +56,8 @@ ${project.artifactId} - org.jclouds.aws.*;version="${project.version}" - org.jclouds.*;version="${project.version}",* + org.jclouds.aws*;version="${project.version}" + org.jclouds*;version="${project.version}",* diff --git a/common/azure/pom.xml b/common/azure/pom.xml index 532a864891..8965dd4dff 100644 --- a/common/azure/pom.xml +++ b/common/azure/pom.xml @@ -56,8 +56,8 @@ ${project.artifactId} - org.jclouds.azure.*;version="${project.version}" - org.jclouds.*;version="${project.version}",* + org.jclouds.azure*;version="${project.version}" + org.jclouds*;version="${project.version}",* diff --git a/common/openstack/pom.xml b/common/openstack/pom.xml index 2141692968..dafa36d51e 100644 --- a/common/openstack/pom.xml +++ b/common/openstack/pom.xml @@ -57,8 +57,8 @@ ${project.artifactId} - org.jclouds.openstack.*;version="${project.version}" - org.jclouds.*;version="${project.version}",* + org.jclouds.openstack*;version="${project.version}" + org.jclouds*;version="${project.version}",* diff --git a/common/trmk/pom.xml b/common/trmk/pom.xml index 233edfa45d..59710c4a34 100644 --- a/common/trmk/pom.xml +++ b/common/trmk/pom.xml @@ -81,8 +81,8 @@ ${project.artifactId} - org.jclouds.trmk.vcloud_0_8.*;version="${project.version}" - org.jclouds.*;version="${project.version}",* + org.jclouds.trmk.vcloud_0_8*;version="${project.version}" + org.jclouds*;version="${project.version}",* diff --git a/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/compute/TerremarkVCloudComputeService.java b/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/compute/TerremarkVCloudComputeService.java index fd46d6a75f..87107915e6 100644 --- a/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/compute/TerremarkVCloudComputeService.java +++ b/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/compute/TerremarkVCloudComputeService.java @@ -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 templateBuilderProvider, Provider templateOptionsProvider, - @Named("NODE_RUNNING") Predicate nodeRunning, - @Named("NODE_TERMINATED") Predicate nodeTerminated, - @Named("NODE_SUSPENDED") Predicate nodeSuspended, + @Named("NODE_RUNNING") Predicate> nodeRunning, + @Named("NODE_TERMINATED") Predicate> nodeTerminated, + @Named("NODE_SUSPENDED") Predicate> nodeSuspended, InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory, RunScriptOnNode.Factory runScriptOnNodeFactory, InitAdminAccess initAdminAccess, PersistNodeCredentials persistNodeCredentials, Timeouts timeouts, diff --git a/compute/pom.xml b/compute/pom.xml index 2ac7fb536a..98d8ec73e2 100644 --- a/compute/pom.xml +++ b/compute/pom.xml @@ -73,8 +73,8 @@ ${project.artifactId} - org.jclouds.compute.*;version="${project.version}",org.jclouds.cim.*;version="${project.version}",org.jclouds.ovf.*;version="${project.version}",org.jclouds.ssh.*;version="${project.version}" - !org.jclouds.compute.*;org.jclouds.*;version="${project.version}",* + org.jclouds.compute*;version="${project.version}",org.jclouds.cim*;version="${project.version}",org.jclouds.ovf*;version="${project.version}",org.jclouds.ssh*;version="${project.version}" + !org.jclouds.compute.*;org.jclouds*;version="${project.version}",* jclouds-core;bundle-version="[1.3,2)" diff --git a/compute/src/main/clojure/org/jclouds/compute.clj b/compute/src/main/clojure/org/jclouds/compute.clj deleted file mode 100644 index 9589d07da4..0000000000 --- a/compute/src/main/clojure/org/jclouds/compute.clj +++ /dev/null @@ -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))) diff --git a/compute/src/main/clojure/org/jclouds/compute2.clj b/compute/src/main/clojure/org/jclouds/compute2.clj index bb02907863..600960e418 100644 --- a/compute/src/main/clojure/org/jclouds/compute2.clj +++ b/compute/src/main/clojure/org/jclouds/compute2.clj @@ -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 diff --git a/compute/src/main/java/org/jclouds/compute/RunScriptData.java b/compute/src/main/java/org/jclouds/compute/RunScriptData.java index d2eafcdfc3..16f3601b29 100644 --- a/compute/src/main/java/org/jclouds/compute/RunScriptData.java +++ b/compute/src/main/java/org/jclouds/compute/RunScriptData.java @@ -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 builder = ImmutableList. 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.of(appendFile(JBOSS_HOME + "/standalone/configuration/standalone-custom.xml", Splitter.on('\n').split(configuration))), - ImmutableList - . 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,70 +89,13 @@ public class RunScriptData { .append("org.jboss.as.standalone").append(' ') .append("-Djboss.home.dir=$JBOSS_HOME").append(' ') .append("--server-config=standalone-custom.xml") - .toString()))); + .toString())).build(); } - public static Statement normalizeHostAndDNSConfig() { - return newStatementList(// - addHostnameToEtcHostsIfMissing(),// - addDnsToResolverIfMissing()); - } - - public static Statement addHostnameToEtcHostsIfMissing() { - return exec("grep `hostname` /etc/hosts >/dev/null || awk -v hostname=`hostname` 'END { print $1\" \"hostname }' /proc/net/arp >> /etc/hosts"); - } - - public static Statement addDnsToResolverIfMissing() { - return exec("nslookup yahoo.com >/dev/null || echo nameserver 208.67.222.222 >> /etc/resolv.conf"); - } - // TODO make this a cli option private static Statement changeStandaloneConfigToListenOnAllIPAddresses() { return exec(format( "(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 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); } diff --git a/compute/src/main/java/org/jclouds/compute/callables/BlockUntilInitScriptStatusIsZeroThenReturnOutput.java b/compute/src/main/java/org/jclouds/compute/callables/BlockUntilInitScriptStatusIsZeroThenReturnOutput.java index 8ebb35238b..a6f07fbc96 100644 --- a/compute/src/main/java/org/jclouds/compute/callables/BlockUntilInitScriptStatusIsZeroThenReturnOutput.java +++ b/compute/src/main/java/org/jclouds/compute/callables/BlockUntilInitScriptStatusIsZeroThenReturnOutput.java @@ -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 notRunningAnymore; - private boolean shouldCancel; + public SudoAwareInitManager getCommandRunner() { + return commandRunner; + } + + private final RetryablePredicate notRunningAnymore; @Inject public BlockUntilInitScriptStatusIsZeroThenReturnOutput( - @Named(Constants.PROPERTY_USER_THREADS) ExecutorService userThreads, - 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! + @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 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(new Predicate() { @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,72 +150,54 @@ 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 public ExecResponse get(long timeout, TimeUnit unit) throws InterruptedException, TimeoutException, - ExecutionException { + ExecutionException { 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; } } diff --git a/compute/src/main/java/org/jclouds/compute/callables/InitScriptConfigurationForTasks.java b/compute/src/main/java/org/jclouds/compute/callables/InitScriptConfigurationForTasks.java index ef6eab8804..0394a50b29 100644 --- a/compute/src/main/java/org/jclouds/compute/callables/InitScriptConfigurationForTasks.java +++ b/compute/src/main/java/org/jclouds/compute/callables/InitScriptConfigurationForTasks.java @@ -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; diff --git a/compute/src/main/java/org/jclouds/compute/callables/RunScriptOnNodeAsInitScriptUsingSsh.java b/compute/src/main/java/org/jclouds/compute/callables/RunScriptOnNodeAsInitScriptUsingSsh.java index d2a52cfca0..a3e263af23 100644 --- a/compute/src/main/java/org/jclouds/compute/callables/RunScriptOnNodeAsInitScriptUsingSsh.java +++ b/compute/src/main/java/org/jclouds/compute/callables/RunScriptOnNodeAsInitScriptUsingSsh.java @@ -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 sshFactory, + public RunScriptOnNodeAsInitScriptUsingSsh(Function 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 - . emptyMap(), Collections.singleton(script)); + return InitScript.builder().name(name).home(config.getBasedir() + "/" + name).run(script).build(); } protected void refreshSshIfNewAdminCredentialsConfigured(AdminAccess input) { @@ -115,34 +104,41 @@ public class RunScriptOnNodeAsInitScriptUsingSsh extends SudoAwareInitManager im } protected ExecResponse doCall() { + eventBus.post(new InitScriptOnNodeSubmission(init, node)); 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 (logger.isTraceEnabled()) - logger.warn(e, "<< (%s) problem using sftp [%s], attempting via sshexec", ssh.toString(), e.getMessage()); - else - logger.warn("<< (%s) problem using sftp [%s], attempting via sshexec", ssh.toString(), e.getMessage()); - ssh.disconnect(); - 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)); - } - - ssh.exec("chmod 755 " + initFile); - setupLinkToInitFile(); - - runAction("init"); - init.getInitStatement().accept(new AdminAccessVisitor() { - - @Override - public void visit(AdminAccess input) { - refreshSshIfNewAdminCredentialsConfigured(input); + 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 (logger.isTraceEnabled()) + logger.warn(e, "<< (%s) problem using sftp [%s], attempting via sshexec", ssh.toString(), e.getMessage()); + else + logger.warn("<< (%s) problem using sftp [%s], attempting via sshexec", ssh.toString(), e.getMessage()); + ssh.disconnect(); + ssh.connect(); + ssh.exec("rm " + initFile); + ssh.exec(Statements.appendFile(initFile, Splitter.on('\n').split(init.render(OsFamily.UNIX)), + AppendFile.DELIMETER + "_" + init.getInstanceName()).render(OsFamily.UNIX)); } - }); - return runAction("start"); + ssh.exec("chmod 755 " + initFile); + setupLinkToInitFile(); + + runAction("init"); + init.getInitStatement().accept(new AdminAccessVisitor() { + + @Override + public void visit(AdminAccess input) { + refreshSshIfNewAdminCredentialsConfigured(input); + } + + }); + return runAction("start"); + } catch (Throwable e) { + eventBus.post(new StatementOnNodeFailure(init, node, e)); + throw Throwables.propagate(e); + } } protected void setupLinkToInitFile() { diff --git a/compute/src/main/java/org/jclouds/compute/callables/RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilComplete.java b/compute/src/main/java/org/jclouds/compute/callables/RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilComplete.java index d95899ff33..84fa837bd6 100644 --- a/compute/src/main/java/org/jclouds/compute/callables/RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilComplete.java +++ b/compute/src/main/java/org/jclouds/compute/callables/RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilComplete.java @@ -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; /** @@ -46,10 +47,11 @@ public class RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilComplete extends Ru @Inject public RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilComplete( - BlockUntilInitScriptStatusIsZeroThenReturnOutput.Factory statusFactory, Timeouts timeouts, - Function sshFactory, InitScriptConfigurationForTasks initScriptConfiguration, - @Assisted NodeMetadata node, @Assisted Statement script, @Assisted RunScriptOptions options) { - super(sshFactory, initScriptConfiguration, node, script, options); + BlockUntilInitScriptStatusIsZeroThenReturnOutput.Factory statusFactory, Timeouts timeouts, + Function 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(); } diff --git a/compute/src/main/java/org/jclouds/compute/callables/RunScriptOnNodeUsingSsh.java b/compute/src/main/java/org/jclouds/compute/callables/RunScriptOnNodeUsingSsh.java index f45b108353..b72d325b70 100644 --- a/compute/src/main/java/org/jclouds/compute/callables/RunScriptOnNodeUsingSsh.java +++ b/compute/src/main/java/org/jclouds/compute/callables/RunScriptOnNodeUsingSsh.java @@ -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 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 sshFactory, @Assisted NodeMetadata node, - @Assisted Statement statement, @Assisted RunScriptOptions options) { + public RunScriptOnNodeUsingSsh(Function 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)); - returnVal = runCommand(command); + 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) diff --git a/compute/src/main/java/org/jclouds/compute/callables/SudoAwareInitManager.java b/compute/src/main/java/org/jclouds/compute/callables/SudoAwareInitManager.java index 8dbe9cdcbd..e94df32e21 100644 --- a/compute/src/main/java/org/jclouds/compute/callables/SudoAwareInitManager.java +++ b/compute/src/main/java/org/jclouds/compute/callables/SudoAwareInitManager.java @@ -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 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 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); - else - computeLogger.debug(statement); - return ssh.exec(command); + logger.trace(">> running " + statement); + else + 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; } } \ No newline at end of file diff --git a/compute/src/main/java/org/jclouds/compute/config/BaseComputeServiceContextModule.java b/compute/src/main/java/org/jclouds/compute/config/BaseComputeServiceContextModule.java index ce6863e6e9..d5de71481b 100644 --- a/compute/src/main/java/org/jclouds/compute/config/BaseComputeServiceContextModule.java +++ b/compute/src/main/java/org/jclouds/compute/config/BaseComputeServiceContextModule.java @@ -103,7 +103,7 @@ public abstract class BaseComputeServiceContextModule extends AbstractModule { install(new FactoryModuleBuilder().implement(new TypeLiteral>() { }, CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap.class) - .implement(new TypeLiteral>() { + .implement(new TypeLiteral, Void>>() { }, CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap.class) .build(CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap.Factory.class)); diff --git a/compute/src/main/java/org/jclouds/compute/config/ComputeServiceTimeoutsModule.java b/compute/src/main/java/org/jclouds/compute/config/ComputeServiceTimeoutsModule.java index a653307eec..9c76083805 100644 --- a/compute/src/main/java/org/jclouds/compute/config/ComputeServiceTimeoutsModule.java +++ b/compute/src/main/java/org/jclouds/compute/config/ComputeServiceTimeoutsModule.java @@ -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> nodeRunning(AtomicNodeRunning stateRunning, Timeouts timeouts) { + return timeouts.nodeRunning == 0 ? stateRunning : new RetryablePredicate>(stateRunning, + timeouts.nodeRunning); + } + + @Provides + @Singleton + @Named("NODE_TERMINATED") + protected Predicate> serverTerminated(AtomicNodeRunning stateTerminated, Timeouts timeouts) { + return timeouts.nodeTerminated == 0 ? stateTerminated : new RetryablePredicate>(stateTerminated, + timeouts.nodeTerminated); + } + + + @Provides + @Singleton + @Named("NODE_SUSPENDED") + protected Predicate> serverSuspended(AtomicNodeRunning stateSuspended, Timeouts timeouts) { + return timeouts.nodeSuspended == 0 ? stateSuspended : new RetryablePredicate>(stateSuspended, + timeouts.nodeSuspended); + } + + @Provides + @Singleton + @Named("NODE_RUNNING") + @Deprecated protected Predicate nodeRunning(NodeRunning stateRunning, Timeouts timeouts) { return timeouts.nodeRunning == 0 ? stateRunning : new RetryablePredicate(stateRunning, timeouts.nodeRunning); @@ -54,6 +83,7 @@ public class ComputeServiceTimeoutsModule extends AbstractModule { @Provides @Singleton @Named("NODE_TERMINATED") + @Deprecated protected Predicate serverTerminated(NodeTerminated stateTerminated, Timeouts timeouts) { return timeouts.nodeTerminated == 0 ? stateTerminated : new RetryablePredicate(stateTerminated, timeouts.nodeTerminated); @@ -63,6 +93,7 @@ public class ComputeServiceTimeoutsModule extends AbstractModule { @Provides @Singleton @Named("NODE_SUSPENDED") + @Deprecated protected Predicate serverSuspended(NodeSuspended stateSuspended, Timeouts timeouts) { return timeouts.nodeSuspended == 0 ? stateSuspended : new RetryablePredicate(stateSuspended, timeouts.nodeSuspended); diff --git a/compute/src/main/java/org/jclouds/compute/domain/ExecResponse.java b/compute/src/main/java/org/jclouds/compute/domain/ExecResponse.java index adc9d4cd67..595d4d30ec 100644 --- a/compute/src/main/java/org/jclouds/compute/domain/ExecResponse.java +++ b/compute/src/main/java/org/jclouds/compute/domain/ExecResponse.java @@ -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(); } } \ No newline at end of file diff --git a/compute/src/main/java/org/jclouds/compute/domain/TemplateBuilder.java b/compute/src/main/java/org/jclouds/compute/domain/TemplateBuilder.java index d99ddb589d..69251b70b7 100644 --- a/compute/src/main/java/org/jclouds/compute/domain/TemplateBuilder.java +++ b/compute/src/main/java/org/jclouds/compute/domain/TemplateBuilder.java @@ -68,6 +68,11 @@ public interface TemplateBuilder { * configure this template to the largest hardware, based on cores, ram, then disk */ 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. diff --git a/compute/src/main/java/org/jclouds/compute/domain/internal/NodeMetadataImpl.java b/compute/src/main/java/org/jclouds/compute/domain/internal/NodeMetadataImpl.java index 4262864686..6574da6613 100644 --- a/compute/src/main/java/org/jclouds/compute/domain/internal/NodeMetadataImpl.java +++ b/compute/src/main/java/org/jclouds/compute/domain/internal/NodeMetadataImpl.java @@ -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; } diff --git a/compute/src/main/java/org/jclouds/compute/domain/internal/TemplateBuilderImpl.java b/compute/src/main/java/org/jclouds/compute/domain/internal/TemplateBuilderImpl.java index 6c3e0f3c3a..17f1da2d43 100644 --- a/compute/src/main/java/org/jclouds/compute/domain/internal/TemplateBuilderImpl.java +++ b/compute/src/main/java/org/jclouds/compute/domain/internal/TemplateBuilderImpl.java @@ -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 hardwareIdPredicate = new Predicate() { @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; } @@ -362,6 +369,26 @@ public class TemplateBuilderImpl implements TemplateBuilder { return "hardwareId(" + hardwareId + ")"; } }; + + private final Predicate hypervisorPredicate = new Predicate() { + @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 hardwareCoresPredicate = new Predicate() { @Override @@ -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,9 +931,19 @@ 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; + } + /** * {@inheritDoc} */ @@ -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 diff --git a/compute/src/main/java/org/jclouds/compute/events/InitScriptOnNodeSubmission.java b/compute/src/main/java/org/jclouds/compute/events/InitScriptOnNodeSubmission.java new file mode 100644 index 0000000000..e80c31b0d6 --- /dev/null +++ b/compute/src/main/java/org/jclouds/compute/events/InitScriptOnNodeSubmission.java @@ -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. + *

+ * 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); + } + +} \ No newline at end of file diff --git a/compute/src/main/java/org/jclouds/compute/events/StatementOnNode.java b/compute/src/main/java/org/jclouds/compute/events/StatementOnNode.java new file mode 100644 index 0000000000..b4964cb86a --- /dev/null +++ b/compute/src/main/java/org/jclouds/compute/events/StatementOnNode.java @@ -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()); + } + +} \ No newline at end of file diff --git a/compute/src/main/java/org/jclouds/compute/events/StatementOnNodeCompletion.java b/compute/src/main/java/org/jclouds/compute/events/StatementOnNodeCompletion.java new file mode 100644 index 0000000000..c058faaa3c --- /dev/null +++ b/compute/src/main/java/org/jclouds/compute/events/StatementOnNodeCompletion.java @@ -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); + } +} \ No newline at end of file diff --git a/compute/src/main/java/org/jclouds/compute/events/StatementOnNodeFailure.java b/compute/src/main/java/org/jclouds/compute/events/StatementOnNodeFailure.java new file mode 100644 index 0000000000..de29cf426c --- /dev/null +++ b/compute/src/main/java/org/jclouds/compute/events/StatementOnNodeFailure.java @@ -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()); + } +} \ No newline at end of file diff --git a/compute/src/main/java/org/jclouds/compute/events/StatementOnNodeSubmission.java b/compute/src/main/java/org/jclouds/compute/events/StatementOnNodeSubmission.java new file mode 100644 index 0000000000..add0af9a9d --- /dev/null +++ b/compute/src/main/java/org/jclouds/compute/events/StatementOnNodeSubmission.java @@ -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. + *

+ * 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); + } + +} \ No newline at end of file diff --git a/compute/src/main/java/org/jclouds/compute/functions/TemplateOptionsToStatement.java b/compute/src/main/java/org/jclouds/compute/functions/TemplateOptionsToStatement.java index c38c21ff8d..95e122b042 100644 --- a/compute/src/main/java/org/jclouds/compute/functions/TemplateOptionsToStatement.java +++ b/compute/src/main/java/org/jclouds/compute/functions/TemplateOptionsToStatement.java @@ -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= 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); } diff --git a/compute/src/main/java/org/jclouds/compute/internal/BaseComputeService.java b/compute/src/main/java/org/jclouds/compute/internal/BaseComputeService.java index 98ec74a125..27a9547b37 100644 --- a/compute/src/main/java/org/jclouds/compute/internal/BaseComputeService.java +++ b/compute/src/main/java/org/jclouds/compute/internal/BaseComputeService.java @@ -125,9 +125,9 @@ public class BaseComputeService implements ComputeService { private final SuspendNodeStrategy suspendNodeStrategy; private final Provider templateBuilderProvider; private final Provider templateOptionsProvider; - private final Predicate nodeRunning; - private final Predicate nodeTerminated; - private final Predicate nodeSuspended; + private final Predicate> nodeRunning; + private final Predicate> nodeTerminated; + private final Predicate> 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 templateBuilderProvider, Provider templateOptionsProvider, - @Named("NODE_RUNNING") Predicate nodeRunning, - @Named("NODE_TERMINATED") Predicate nodeTerminated, - @Named("NODE_SUSPENDED") Predicate nodeSuspended, + @Named("NODE_RUNNING") Predicate> nodeRunning, + @Named("NODE_TERMINATED") Predicate> nodeTerminated, + @Named("NODE_SUSPENDED") Predicate> 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 node = new AtomicReference(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 node = new AtomicReference(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 node = new AtomicReference(suspendNodeStrategy.suspendNode(id)); boolean successful = nodeSuspended.apply(node); logger.debug("<< suspended node(%s) success(%s)", id, successful); } diff --git a/compute/src/main/java/org/jclouds/compute/internal/UtilsImpl.java b/compute/src/main/java/org/jclouds/compute/internal/UtilsImpl.java index bc8b259581..bcaab810b8 100644 --- a/compute/src/main/java/org/jclouds/compute/internal/UtilsImpl.java +++ b/compute/src/main/java/org/jclouds/compute/internal/UtilsImpl.java @@ -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 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 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 sshForNode) { + super(injector, json, simpleClient, simpleAsyncClient, encryption, date, userThreads, ioThreads, eventBus, + loggerFactory); this.sshForNode = sshForNode; } diff --git a/compute/src/main/java/org/jclouds/compute/predicates/AtomicNodeRunning.java b/compute/src/main/java/org/jclouds/compute/predicates/AtomicNodeRunning.java new file mode 100644 index 0000000000..ab66cb91c1 --- /dev/null +++ b/compute/src/main/java/org/jclouds/compute/predicates/AtomicNodeRunning.java @@ -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); + } +} diff --git a/compute/src/main/java/org/jclouds/compute/predicates/AtomicNodeSuspended.java b/compute/src/main/java/org/jclouds/compute/predicates/AtomicNodeSuspended.java new file mode 100644 index 0000000000..0eb86b13e4 --- /dev/null +++ b/compute/src/main/java/org/jclouds/compute/predicates/AtomicNodeSuspended.java @@ -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); + } +} diff --git a/compute/src/main/java/org/jclouds/compute/predicates/NodePresentAndInIntendedState.java b/compute/src/main/java/org/jclouds/compute/predicates/NodePresentAndInIntendedState.java index eb7139d23e..44dbe87ab1 100644 --- a/compute/src/main/java/org/jclouds/compute/predicates/NodePresentAndInIntendedState.java +++ b/compute/src/main/java/org/jclouds/compute/predicates/NodePresentAndInIntendedState.java @@ -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 { diff --git a/compute/src/main/java/org/jclouds/compute/predicates/NodeRunning.java b/compute/src/main/java/org/jclouds/compute/predicates/NodeRunning.java index 3811c7c838..e8300825fb 100644 --- a/compute/src/main/java/org/jclouds/compute/predicates/NodeRunning.java +++ b/compute/src/main/java/org/jclouds/compute/predicates/NodeRunning.java @@ -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 diff --git a/compute/src/main/java/org/jclouds/compute/predicates/NodeSuspended.java b/compute/src/main/java/org/jclouds/compute/predicates/NodeSuspended.java index f0dc578def..2c459747e2 100644 --- a/compute/src/main/java/org/jclouds/compute/predicates/NodeSuspended.java +++ b/compute/src/main/java/org/jclouds/compute/predicates/NodeSuspended.java @@ -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 diff --git a/compute/src/main/java/org/jclouds/compute/predicates/NodeTerminated.java b/compute/src/main/java/org/jclouds/compute/predicates/NodeTerminated.java index b28bead6d5..c4555fea2a 100644 --- a/compute/src/main/java/org/jclouds/compute/predicates/NodeTerminated.java +++ b/compute/src/main/java/org/jclouds/compute/predicates/NodeTerminated.java @@ -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 { private final GetNodeMetadataStrategy client; diff --git a/compute/src/main/java/org/jclouds/compute/predicates/RefreshAndDoubleCheckOnFailUnlessStateInvalid.java b/compute/src/main/java/org/jclouds/compute/predicates/RefreshAndDoubleCheckOnFailUnlessStateInvalid.java new file mode 100644 index 0000000000..d450c44740 --- /dev/null +++ b/compute/src/main/java/org/jclouds/compute/predicates/RefreshAndDoubleCheckOnFailUnlessStateInvalid.java @@ -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> { + + private final GetNodeMetadataStrategy client; + private final NodeState intended; + private final Set 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 invalids, GetNodeMetadataStrategy client) { + this.intended = intended; + this.client = client; + this.invalids = invalids; + } + + public boolean apply(AtomicReference 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()); + } +} diff --git a/compute/src/main/java/org/jclouds/compute/predicates/ScriptStatusReturnsZero.java b/compute/src/main/java/org/jclouds/compute/predicates/ScriptStatusReturnsZero.java index 43df011d9d..a2245ebeab 100644 --- a/compute/src/main/java/org/jclouds/compute/predicates/ScriptStatusReturnsZero.java +++ b/compute/src/main/java/org/jclouds/compute/predicates/ScriptStatusReturnsZero.java @@ -44,11 +44,11 @@ public class ScriptStatusReturnsZero implements Predicate> { + + private final GetNodeMetadataStrategy client; + + @Resource + protected Logger logger = Logger.NULL; + + @Inject + public TrueIfNullOrTerminatedRefreshAndDoubleCheckOnFalse(GetNodeMetadataStrategy client) { + this.client = client; + } + + public boolean apply(AtomicReference 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()); + } +} diff --git a/compute/src/main/java/org/jclouds/compute/strategy/CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap.java b/compute/src/main/java/org/jclouds/compute/strategy/CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap.java index dd788bd6f8..fea546f14b 100644 --- a/compute/src/main/java/org/jclouds/compute/strategy/CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap.java +++ b/compute/src/main/java/org/jclouds/compute/strategy/CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap.java @@ -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, - Function { + Function, Void> { public static interface Factory { - Callable create(TemplateOptions options, NodeMetadata node, Set goodNodes, - Map badNodes, - Multimap customizationResponses); + Callable create(TemplateOptions options, AtomicReference node, Set goodNodes, + Map badNodes, Multimap customizationResponses); - Function create(TemplateOptions options, Set goodNodes, - Map badNodes, - Multimap customizationResponses); + Function, Void> create(TemplateOptions options, Set goodNodes, + Map badNodes, Multimap customizationResponses); } @Resource @Named(ComputeServiceConstants.COMPUTE_LOGGER) protected Logger logger = Logger.NULL; - private final Predicate nodeRunning; + private final Predicate> 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 node; private final Set goodNodes; private final Map badNodes; private final Multimap customizationResponses; @@ -88,18 +86,17 @@ public class CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap implements Cal @AssistedInject public CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap( - @Named("NODE_RUNNING") Predicate nodeRunning, GetNodeMetadataStrategy getNode, - RetryIfSocketNotYetOpen socketTester, Timeouts timeouts, - Function templateOptionsToStatement, - InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory, - @Assisted TemplateOptions options, @Assisted @Nullable NodeMetadata node, - @Assisted Set goodNodes, @Assisted Map badNodes, - @Assisted Multimap customizationResponses) { + @Named("NODE_RUNNING") Predicate> nodeRunning, + RetryIfSocketNotYetOpen socketTester, Timeouts timeouts, + Function templateOptionsToStatement, + InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory, @Assisted TemplateOptions options, + @Assisted AtomicReference node, @Assisted Set goodNodes, + @Assisted Map badNodes, + @Assisted Multimap customizationResponses) { this.statement = checkNotNull(templateOptionsToStatement, "templateOptionsToStatement").apply( - checkNotNull(options, "options")); + 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 nodeRunning, GetNodeMetadataStrategy getNode, - RetryIfSocketNotYetOpen socketTester, Timeouts timeouts, - Function templateOptionsToStatement, - InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory, - @Assisted TemplateOptions options, @Assisted Set goodNodes, - @Assisted Map badNodes, - @Assisted Multimap customizationResponses) { - this(nodeRunning, getNode, socketTester, timeouts, templateOptionsToStatement, initScriptRunnerFactory, options, - null, goodNodes, badNodes, customizationResponses); + @Named("NODE_RUNNING") Predicate> nodeRunning, GetNodeMetadataStrategy getNode, + RetryIfSocketNotYetOpen socketTester, Timeouts timeouts, + Function templateOptionsToStatement, + InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory, @Assisted TemplateOptions options, + @Assisted Set goodNodes, @Assisted Map badNodes, + @Assisted Multimap customizationResponses) { + this(nodeRunning, socketTester, timeouts, templateOptionsToStatement, initScriptRunnerFactory, options, + new AtomicReference(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) + 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 new IllegalStateException(format( - "node(%s) didn't achieve the state running within %d seconds, final state: %s", originalId, - timeouts.nodeRunning / 1000, state)); + } 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 input) { this.node = input; call(); return null; diff --git a/compute/src/main/java/org/jclouds/compute/strategy/RunScriptOnNodeAndAddToGoodMapOrPutExceptionIntoBadMap.java b/compute/src/main/java/org/jclouds/compute/strategy/RunScriptOnNodeAndAddToGoodMapOrPutExceptionIntoBadMap.java index 7d5fc23b77..5ee09df3b1 100644 --- a/compute/src/main/java/org/jclouds/compute/strategy/RunScriptOnNodeAndAddToGoodMapOrPutExceptionIntoBadMap.java +++ b/compute/src/main/java/org/jclouds/compute/strategy/RunScriptOnNodeAndAddToGoodMapOrPutExceptionIntoBadMap.java @@ -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) { diff --git a/compute/src/main/java/org/jclouds/compute/strategy/impl/CreateNodesWithGroupEncodedIntoNameThenAddToSet.java b/compute/src/main/java/org/jclouds/compute/strategy/impl/CreateNodesWithGroupEncodedIntoNameThenAddToSet.java index a1f1a80013..22e1dca93a 100644 --- a/compute/src/main/java/org/jclouds/compute/strategy/impl/CreateNodesWithGroupEncodedIntoNameThenAddToSet.java +++ b/compute/src/main/java/org/jclouds/compute/strategy/impl/CreateNodesWithGroupEncodedIntoNameThenAddToSet.java @@ -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 { + private class AddNode implements Callable> { 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 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(node); } public String toString() { diff --git a/compute/src/main/java/org/jclouds/compute/util/ComputeUtils.java b/compute/src/main/java/org/jclouds/compute/util/ComputeUtils.java index 488a6944fa..100c036c40 100644 --- a/compute/src/main/java/org/jclouds/compute/util/ComputeUtils.java +++ b/compute/src/main/java/org/jclouds/compute/util/ComputeUtils.java @@ -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> responses = newLinkedHashMap(); for (NodeMetadata node : runningNodes) { responses.put(node, executor.submit(customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory.create( - options, node, goodNodes, badNodes, customizationResponses))); + options, new AtomicReference(node), goodNodes, badNodes, customizationResponses))); } return responses; } diff --git a/compute/src/test/clojure/org/jclouds/compute_test.clj b/compute/src/test/clojure/org/jclouds/compute_test.clj deleted file mode 100644 index 9e7e839a41..0000000000 --- a/compute/src/test/clojure/org/jclouds/compute_test.clj +++ /dev/null @@ -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})))))) diff --git a/compute/src/test/clojure/org/jclouds/ssh_test.clj b/compute/src/test/clojure/org/jclouds/ssh_test.clj index 61799932ae..d6ea701351 100644 --- a/compute/src/test/clojure/org/jclouds/ssh_test.clj +++ b/compute/src/test/clojure/org/jclouds/ssh_test.clj @@ -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 "[]"} {}))) diff --git a/compute/src/test/java/org/jclouds/compute/BaseComputeServiceLiveTest.java b/compute/src/test/java/org/jclouds/compute/BaseComputeServiceLiveTest.java index e0141d59dd..a67fec02ac 100644 --- a/compute/src/test/java/org/jclouds/compute/BaseComputeServiceLiveTest.java +++ b/compute/src/test/java/org/jclouds/compute/BaseComputeServiceLiveTest.java @@ -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 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 download : ImmutableMap. of("jboss7", JBOSS7_URL, "jdk7", JDK7_URL) + for (Entry download : ImmutableMap. 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() { @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 diff --git a/compute/src/test/java/org/jclouds/compute/ComputeTestUtils.java b/compute/src/test/java/org/jclouds/compute/ComputeTestUtils.java index 1471d1786b..3b73b6ba16 100644 --- a/compute/src/test/java/org/jclouds/compute/ComputeTestUtils.java +++ b/compute/src/test/java/org/jclouds/compute/ComputeTestUtils.java @@ -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 setupKeyPair() throws FileNotFoundException, IOException { String secretKeyFile; diff --git a/compute/src/test/java/org/jclouds/compute/StubComputeServiceIntegrationTest.java b/compute/src/test/java/org/jclouds/compute/StubComputeServiceIntegrationTest.java index 3ea2262417..2c42a16a19 100644 --- a/compute/src/test/java/org/jclouds/compute/StubComputeServiceIntegrationTest.java +++ b/compute/src/test/java/org/jclouds/compute/StubComputeServiceIntegrationTest.java @@ -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) { diff --git a/compute/src/test/java/org/jclouds/compute/callables/RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilCompleteTest.java b/compute/src/test/java/org/jclouds/compute/callables/RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilCompleteTest.java index 00c5509fec..4e44027680 100644 --- a/compute/src/test/java/org/jclouds/compute/callables/RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilCompleteTest.java +++ b/compute/src/test/java/org/jclouds/compute/callables/RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilCompleteTest.java @@ -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 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. 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. 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. 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); + } } diff --git a/compute/src/test/java/org/jclouds/compute/callables/RunScriptOnNodeAsInitScriptUsingSshTest.java b/compute/src/test/java/org/jclouds/compute/callables/RunScriptOnNodeAsInitScriptUsingSshTest.java index bb74d982d9..3716c746ba 100644 --- a/compute/src/test/java/org/jclouds/compute/callables/RunScriptOnNodeAsInitScriptUsingSshTest.java +++ b/compute/src/test/java/org/jclouds/compute/callables/RunScriptOnNodeAsInitScriptUsingSshTest.java @@ -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. 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. 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. 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"); diff --git a/compute/src/test/java/org/jclouds/compute/callables/RunScriptOnNodeUsingSshTest.java b/compute/src/test/java/org/jclouds/compute/callables/RunScriptOnNodeUsingSshTest.java index 2c117ff8c1..2a6bed2249 100644 --- a/compute/src/test/java/org/jclouds/compute/callables/RunScriptOnNodeUsingSshTest.java +++ b/compute/src/test/java/org/jclouds/compute/callables/RunScriptOnNodeUsingSshTest.java @@ -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 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(); diff --git a/compute/src/test/java/org/jclouds/compute/domain/internal/TemplateBuilderImplTest.java b/compute/src/test/java/org/jclouds/compute/domain/internal/TemplateBuilderImplTest.java index c979c78489..1537916bcc 100644 --- a/compute/src/test/java/org/jclouds/compute/domain/internal/TemplateBuilderImplTest.java +++ b/compute/src/test/java/org/jclouds/compute/domain/internal/TemplateBuilderImplTest.java @@ -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); @@ -771,5 +776,111 @@ public class TemplateBuilderImplTest { verify(optionsProvider); verify(templateBuilderProvider); } + + @SuppressWarnings("unchecked") + @Test + public void testHardwareIdNullsHypervisor() { + Supplier> locations = Suppliers.> ofInstance(ImmutableSet + . of()); + Supplier> images = Suppliers.> ofInstance(ImmutableSet. of()); + Supplier> hardwares = Suppliers.> ofInstance(ImmutableSet + . of()); + Location defaultLocation = createMock(Location.class); + Provider optionsProvider = createMock(Provider.class); + Provider 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> locations = Suppliers.> ofInstance(ImmutableSet + . of(defaultLocation)); + final Supplier> images = Suppliers.> ofInstance(ImmutableSet + . 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> hardwares = Suppliers.> ofInstance(ImmutableSet + . 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. 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. of(new VolumeImpl((float) 5, true, true))).hypervisor("OpenVZ") + .location(defaultLocation) + .supportsImage(ImagePredicates.idIn(ImmutableSet.of("Ubuntu 11.04 64-bit"))).build())); + + final Provider optionsProvider = new Provider() { + + @Override + public TemplateOptions get() { + return new TemplateOptions(); + } + + }; + Provider templateBuilderProvider = new Provider() { + + @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); + } } diff --git a/compute/src/test/java/org/jclouds/compute/predicates/AtomicNodePredicatesTest.java b/compute/src/test/java/org/jclouds/compute/predicates/AtomicNodePredicatesTest.java new file mode 100644 index 0000000000..d8e300a736 --- /dev/null +++ b/compute/src/test/java/org/jclouds/compute/predicates/AtomicNodePredicatesTest.java @@ -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 reference = new AtomicReference(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 reference = new AtomicReference(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 reference = new AtomicReference(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 reference = new AtomicReference(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 reference = new AtomicReference(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 reference = new AtomicReference(node); + nodeRunning.apply(reference); + Assert.assertEquals(reference.get(), node); + } +} diff --git a/compute/src/test/java/org/jclouds/compute/strategy/CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapTest.java b/compute/src/test/java/org/jclouds/compute/strategy/CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapTest.java index a0708ca46b..85ae78f04d 100644 --- a/compute/src/test/java/org/jclouds/compute/strategy/CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapTest.java +++ b/compute/src/test/java/org/jclouds/compute/strategy/CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapTest.java @@ -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 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 templateOptionsToStatement = new TemplateOptionsToStatement(); @@ -67,41 +65,39 @@ public class CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapTest { Map badNodes = Maps.newLinkedHashMap(); Multimap 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 atomicNode = new AtomicReference(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 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 templateOptionsToStatement = new TemplateOptionsToStatement(); @@ -112,32 +108,35 @@ public class CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapTest { Map badNodes = Maps.newLinkedHashMap(); Multimap 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 atomicNode = new AtomicReference(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); } } diff --git a/compute/src/test/resources/initscript_with_java.sh b/compute/src/test/resources/initscript_with_java.sh index b0494d5e69..e22fa6d73b 100644 --- a/compute/src/test/resources/initscript_with_java.sh +++ b/compute/src/test/resources/initscript_with_java.sh @@ -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 < $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 - -END_OF_SCRIPT + 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_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 $? diff --git a/compute/src/test/resources/initscript_with_jboss.sh b/compute/src/test/resources/initscript_with_jboss.sh index c9ea3f34e5..36216b850d 100644 --- a/compute/src/test/resources/initscript_with_jboss.sh +++ b/compute/src/test/resources/initscript_with_jboss.sh @@ -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 < $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 - -END_OF_SCRIPT + 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_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 $? diff --git a/compute/src/test/resources/runscript.sh b/compute/src/test/resources/runscript.sh index d20f61a84d..927daac349 100644 --- a/compute/src/test/resources/runscript.sh +++ b/compute/src/test/resources/runscript.sh @@ -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 < $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 - -END_OF_SCRIPT + 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_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 $? diff --git a/compute/src/test/resources/runscript_adminUpdate.sh b/compute/src/test/resources/runscript_adminUpdate.sh index cd448eb461..068aa3457b 100644 --- a/compute/src/test/resources/runscript_adminUpdate.sh +++ b/compute/src/test/resources/runscript_adminUpdate.sh @@ -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 < $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 - -END_OF_SCRIPT + 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_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 $? diff --git a/compute/src/test/resources/runscript_jboss.sh b/compute/src/test/resources/runscript_jboss.sh index 508b954785..a919188c91 100644 --- a/compute/src/test/resources/runscript_jboss.sh +++ b/compute/src/test/resources/runscript_jboss.sh @@ -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,139 +60,146 @@ case $1 in init) default || exit 1 jboss || exit 1 - cat >> /usr/local/jboss/standalone/configuration/standalone-custom.xml <<'END_OF_FILE' - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -END_OF_FILE + cat >> /usr/local/jboss/standalone/configuration/standalone-custom.xml <<-'END_OF_JCLOUDS_FILE' + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +END_OF_JCLOUDS_FILE mkdir -p $INSTANCE_HOME # create runscript header - cat > $INSTANCE_HOME/jboss.sh < $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 $? diff --git a/core/pom.xml b/core/pom.xml index 98d1f31288..d4b22d5e96 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -132,7 +132,7 @@ ${project.artifactId} - org.jclouds.*;version=${project.version} + org.jclouds*;version=${project.version} org.jclouds.* diff --git a/core/src/main/java/org/jclouds/concurrent/config/ExecutorServiceModule.java b/core/src/main/java/org/jclouds/concurrent/config/ExecutorServiceModule.java index 5097696e94..99d8601a4c 100644 --- a/core/src/main/java/org/jclouds/concurrent/config/ExecutorServiceModule.java +++ b/core/src/main/java/org/jclouds/concurrent/config/ExecutorServiceModule.java @@ -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; @@ -320,7 +322,13 @@ 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) diff --git a/core/src/main/java/org/jclouds/predicates/RetryablePredicate.java b/core/src/main/java/org/jclouds/predicates/RetryablePredicate.java index aa2de5a9d8..79d142b1ef 100644 --- a/core/src/main/java/org/jclouds/predicates/RetryablePredicate.java +++ b/core/src/main/java/org/jclouds/predicates/RetryablePredicate.java @@ -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 implements Predicate { } 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; diff --git a/core/src/main/java/org/jclouds/rest/Utils.java b/core/src/main/java/org/jclouds/rest/Utils.java index e721277178..353363321d 100644 --- a/core/src/main/java/org/jclouds/rest/Utils.java +++ b/core/src/main/java/org/jclouds/rest/Utils.java @@ -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(); + } diff --git a/core/src/main/java/org/jclouds/rest/internal/UtilsImpl.java b/core/src/main/java/org/jclouds/rest/internal/UtilsImpl.java index b7dfee9801..b7b948e2a3 100644 --- a/core/src/main/java/org/jclouds/rest/internal/UtilsImpl.java +++ b/core/src/main/java/org/jclouds/rest/internal/UtilsImpl.java @@ -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; } @@ -127,7 +130,17 @@ public class UtilsImpl implements Utils { public ExecutorService userExecutor() { return userExecutor; } - + + @Override + public EventBus getEventBus() { + return eventBus; + } + + @Override + public EventBus eventBus() { + return eventBus; + } + @Override public LoggerFactory getLoggerFactory() { return loggerFactory; diff --git a/core/src/main/java/org/jclouds/util/Suppliers2.java b/core/src/main/java/org/jclouds/util/Suppliers2.java index 733dcf70d6..44cbb5f271 100644 --- a/core/src/main/java/org/jclouds/util/Suppliers2.java +++ b/core/src/main/java/org/jclouds/util/Suppliers2.java @@ -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(); + } + } } diff --git a/demos/tweetstore/gae-tweetstore-spring/src/test/java/org/jclouds/demo/tweetstore/integration/GoogleDevServer.java b/demos/tweetstore/gae-tweetstore-spring/src/test/java/org/jclouds/demo/tweetstore/integration/GoogleDevServer.java index 41bed848e7..63223607ac 100644 --- a/demos/tweetstore/gae-tweetstore-spring/src/test/java/org/jclouds/demo/tweetstore/integration/GoogleDevServer.java +++ b/demos/tweetstore/gae-tweetstore-spring/src/test/java/org/jclouds/demo/tweetstore/integration/GoogleDevServer.java @@ -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(); diff --git a/demos/tweetstore/gae-tweetstore/src/test/java/org/jclouds/demo/tweetstore/integration/GoogleDevServer.java b/demos/tweetstore/gae-tweetstore/src/test/java/org/jclouds/demo/tweetstore/integration/GoogleDevServer.java index 41bed848e7..63223607ac 100644 --- a/demos/tweetstore/gae-tweetstore/src/test/java/org/jclouds/demo/tweetstore/integration/GoogleDevServer.java +++ b/demos/tweetstore/gae-tweetstore/src/test/java/org/jclouds/demo/tweetstore/integration/GoogleDevServer.java @@ -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(); diff --git a/demos/tweetstore/rhcloud-tweetstore/README.txt b/demos/tweetstore/rhcloud-tweetstore/README.txt new file mode 100644 index 0000000000..559859f1cb --- /dev/null +++ b/demos/tweetstore/rhcloud-tweetstore/README.txt @@ -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' + + + keys + + true + + + YOUR_ACCESS_KEY_ID + YOUR_SECRET_KEY + YOUR_USER + YOUR_HEX_KEY + YOUR_ACCOUNT + YOUR_BASE64_ENCODED_KEY + YOUR_TWITTER_CONSUMER_KEY + YOUR_TWITTER_CONSUMER_SECRET + YOUR_TWITTER_ACCESSTOKEN + YOUR_TWITTER_ACCESSTOKEN_SECRET + + \ No newline at end of file diff --git a/demos/tweetstore/rhcloud-tweetstore/pom.xml b/demos/tweetstore/rhcloud-tweetstore/pom.xml new file mode 100644 index 0000000000..82ce8d4684 --- /dev/null +++ b/demos/tweetstore/rhcloud-tweetstore/pom.xml @@ -0,0 +1,124 @@ + + + + 4.0.0 + + org.jclouds + jclouds-demos-tweetstore-project + 1.5.0-SNAPSHOT + + jclouds-demo-rhcloud-tweetstore + war + jclouds TweetStore for OpenShift Express + jclouds TweetStore for RedHat's OpenShift Express using Guice for Dependency Injection + + + 7.0.2.Final + localhost + 8088 + jclouds-rhcloud-tweetstore + + + + + com.google.inject.extensions + guice-servlet + 3.0 + + + + + org.jboss.as + jboss-as-embedded + ${rhcloud.jboss.version} + test + + + + jboss-logmanager + org.jboss.logmanager + + + + + + + + live + + + + maven-surefire-plugin + + + integration + integration-test + + test + + + + ${test.twitter.runatcloud-tweetstore.consumer.identity} + ${test.twitter.runatcloud-tweetstore.consumer.credential} + ${test.twitter.runatcloud-tweetstore.access.identity} + ${test.twitter.runatcloud-tweetstore.access.credential} + ${test.azureblob.identity} + ${test.azureblob.credential} + ${test.cloudfiles-us.identity} + ${test.cloudfiles-us.credential} + ${test.aws-s3.identity} + ${test.aws-s3.credential} + ${test.cloudonestorage.identity} + ${test.cloudonestorage.credential} + ${test.ninefold-storage.identity} + ${test.ninefold-storage.credential} + ${rhcloud.jboss.home} + ${rhcloud.jboss.address} + ${rhcloud.jboss.port} + ${jclouds.tweetstore.blobstores} + test.${jclouds.tweetstore.container} + ${project.build.directory}/rhcloud-jboss + ${project.basedir}/src/test/resources/jbossas7/configuration + ${project.build.directory}/${project.build.finalName} + + + ${rhcloud.jboss.address} + ${rhcloud.jboss.port} + + + + + + + + + + + deploy + + + rhcloud-tweetstore + + + + diff --git a/demos/tweetstore/rhcloud-tweetstore/src/main/java/org/jclouds/demo/paas/PlatformServices.java b/demos/tweetstore/rhcloud-tweetstore/src/main/java/org/jclouds/demo/paas/PlatformServices.java new file mode 100644 index 0000000000..c768b42611 --- /dev/null +++ b/demos/tweetstore/rhcloud-tweetstore/src/main/java/org/jclouds/demo/paas/PlatformServices.java @@ -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 taskQueues; + + public PlatformServices(String baseUrl, Map 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); + } +} diff --git a/demos/tweetstore/rhcloud-tweetstore/src/main/java/org/jclouds/demo/paas/RunnableHttpRequest.java b/demos/tweetstore/rhcloud-tweetstore/src/main/java/org/jclouds/demo/paas/RunnableHttpRequest.java new file mode 100644 index 0000000000..ad72a1a58d --- /dev/null +++ b/demos/tweetstore/rhcloud-tweetstore/src/main/java/org/jclouds/demo/paas/RunnableHttpRequest.java @@ -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 Multimap copyOfWithEntry( + Multimap multimap, K k1, V v1) { + return ImmutableMultimap.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; + } + } +} diff --git a/demos/tweetstore/rhcloud-tweetstore/src/main/java/org/jclouds/demo/paas/config/PlatformServicesInitializer.java b/demos/tweetstore/rhcloud-tweetstore/src/main/java/org/jclouds/demo/paas/config/PlatformServicesInitializer.java new file mode 100644 index 0000000000..886a09b3ad --- /dev/null +++ b/demos/tweetstore/rhcloud-tweetstore/src/main/java/org/jclouds/demo/paas/config/PlatformServicesInitializer.java @@ -0,0 +1,104 @@ +/** + * 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.config; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.inject.name.Names.bindProperties; +import static java.lang.String.format; +import static java.util.concurrent.TimeUnit.SECONDS; + +import java.util.Properties; + +import javax.servlet.ServletContext; +import javax.servlet.ServletContextEvent; +import javax.servlet.ServletContextListener; +import javax.ws.rs.core.UriBuilder; + +import org.jclouds.PropertiesBuilder; +import org.jclouds.concurrent.config.ExecutorServiceModule; +import org.jclouds.demo.paas.PlatformServices; +import org.jclouds.demo.paas.service.taskqueue.TaskQueue; +import org.jclouds.demo.tweetstore.config.util.PropertiesLoader; +import org.jclouds.http.HttpCommandExecutorService; +import org.jclouds.http.config.JavaUrlHttpCommandExecutorServiceModule; + +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableMap.Builder; +import com.google.inject.AbstractModule; +import com.google.inject.Guice; +import com.sun.jersey.api.uri.UriBuilderImpl; + +/** + * @author Andrew Phillips + */ +public class PlatformServicesInitializer implements ServletContextListener { + public static final String PLATFORM_SERVICES_ATTRIBUTE_NAME = PlatformServicesInitializer.class.getName(); + + // from .openshift/config/standalone.xml + protected static final String HOST_VARIABLE = "OPENSHIFT_INTERNAL_IP"; + protected static final String PORT_VARIABLE = "OPENSHIFT_INTERNAL_PORT"; + + @Override + public void contextInitialized(ServletContextEvent contextEvent) { + ServletContext context = contextEvent.getServletContext(); + context.setAttribute(PLATFORM_SERVICES_ATTRIBUTE_NAME, createServices(context)); + } + + protected static PlatformServices createServices(ServletContext context) { + HttpCommandExecutorService httpClient = createHttpClient(context); + return new PlatformServices(getBaseUrl(context), createTaskQueues(httpClient)); + } + + protected static HttpCommandExecutorService createHttpClient( + final ServletContext context) { + return Guice.createInjector(new ExecutorServiceModule(), + new JavaUrlHttpCommandExecutorServiceModule(), + new AbstractModule() { + @Override + protected void configure() { + // URL connection defaults + Properties toBind = new PropertiesBuilder().build(); + toBind.putAll(checkNotNull(new PropertiesLoader(context).get(), "properties")); + toBind.putAll(System.getProperties()); + bindProperties(binder(), toBind); + bind(UriBuilder.class).to(UriBuilderImpl.class); + } + }).getInstance(HttpCommandExecutorService.class); + } + + protected static String getBaseUrl(ServletContext context) { + return format("http://%s:%s%s", checkNotNull(System.getenv(HOST_VARIABLE), HOST_VARIABLE), + checkNotNull(System.getenv(PORT_VARIABLE), PORT_VARIABLE), context.getContextPath()); + } + + // TODO: make the number and names of queues configurable + protected static ImmutableMap createTaskQueues(HttpCommandExecutorService httpClient) { + Builder taskQueues = ImmutableMap.builder(); + taskQueues.put("twitter", TaskQueue.builder(httpClient) + .name("twitter").period(SECONDS.toMillis(30)) + .build()); + return taskQueues.build(); + } + + @Override + public void contextDestroyed(ServletContextEvent servletContextEvent) { + ServletContext context = servletContextEvent.getServletContext(); + context.removeAttribute(PLATFORM_SERVICES_ATTRIBUTE_NAME); + } +} diff --git a/demos/tweetstore/rhcloud-tweetstore/src/main/java/org/jclouds/demo/paas/reference/PaasConstants.java b/demos/tweetstore/rhcloud-tweetstore/src/main/java/org/jclouds/demo/paas/reference/PaasConstants.java new file mode 100644 index 0000000000..8af7021bd2 --- /dev/null +++ b/demos/tweetstore/rhcloud-tweetstore/src/main/java/org/jclouds/demo/paas/reference/PaasConstants.java @@ -0,0 +1,28 @@ +/** + * 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.reference; + +/** + * Configuration properties and constants used in PaaS applications. + * + * @author Andrew Phillips + */ +public interface PaasConstants { + static final String PROPERTY_PLATFORM_BASE_URL = "jclouds.paas.baseurl"; +} diff --git a/demos/tweetstore/rhcloud-tweetstore/src/main/java/org/jclouds/demo/paas/service/taskqueue/TaskQueue.java b/demos/tweetstore/rhcloud-tweetstore/src/main/java/org/jclouds/demo/paas/service/taskqueue/TaskQueue.java new file mode 100644 index 0000000000..e317a305cf --- /dev/null +++ b/demos/tweetstore/rhcloud-tweetstore/src/main/java/org/jclouds/demo/paas/service/taskqueue/TaskQueue.java @@ -0,0 +1,107 @@ +/** + * 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.service.taskqueue; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; +import static java.lang.String.format; + +import java.util.Timer; +import java.util.TimerTask; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.TimeUnit; + +import org.jclouds.demo.paas.RunnableHttpRequest; +import org.jclouds.demo.paas.RunnableHttpRequest.Factory; +import org.jclouds.http.HttpCommandExecutorService; + +import com.google.inject.Provider; + +public class TaskQueue { + protected final Factory httpRequestFactory; + private final Timer timer; + private final ConcurrentLinkedQueue tasks = new ConcurrentLinkedQueue(); + + private TaskQueue(String name, long pollingIntervalMillis, Factory httpRequestFactory) { + this.httpRequestFactory = httpRequestFactory; + timer = new Timer(name); + timer.scheduleAtFixedRate(new TimerTask() { + @Override + public void run() { + Runnable task = tasks.poll(); + if (task != null) { + task.run(); + } + } + }, 0, pollingIntervalMillis); + } + + public void add(final Runnable task) { + tasks.add(task); + } + + public Factory getHttpRequestFactory() { + return httpRequestFactory; + } + + public void destroy() { + timer.cancel(); + tasks.clear(); + } + + public static Builder builder(HttpCommandExecutorService httpClient) { + return new Builder(httpClient); + } + + public static class Builder implements Provider { + protected final HttpCommandExecutorService httpClient; + protected String name = "default"; + protected long pollingIntervalMillis = TimeUnit.SECONDS.toMillis(1); + + private Builder(HttpCommandExecutorService httpClient) { + this.httpClient = checkNotNull(httpClient, "httpClient"); + } + + public Builder name(String name) { + this.name = checkNotNull(name, "name"); + return this; + } + + public Builder period(TimeUnit period) { + this.pollingIntervalMillis = checkNotNull(period, "period").toMillis(1); + return this; + } + + public Builder period(long pollingIntervalMillis) { + checkArgument(pollingIntervalMillis > 0, "pollingIntervalMillis"); + this.pollingIntervalMillis = pollingIntervalMillis; + return this; + } + + public TaskQueue build() { + return new TaskQueue(name, pollingIntervalMillis, + RunnableHttpRequest.factory(httpClient, format("taskqueue-%s", name))); + } + + @Override + public TaskQueue get() { + return build(); + } + } +} \ No newline at end of file diff --git a/demos/tweetstore/rhcloud-tweetstore/src/main/java/org/jclouds/demo/tweetstore/config/GuiceServletConfig.java b/demos/tweetstore/rhcloud-tweetstore/src/main/java/org/jclouds/demo/tweetstore/config/GuiceServletConfig.java new file mode 100644 index 0000000000..78729cbfb7 --- /dev/null +++ b/demos/tweetstore/rhcloud-tweetstore/src/main/java/org/jclouds/demo/tweetstore/config/GuiceServletConfig.java @@ -0,0 +1,153 @@ +/** + * 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.tweetstore.config; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; +import static com.google.common.base.Predicates.in; +import static com.google.common.collect.ImmutableSet.copyOf; +import static com.google.common.collect.Sets.filter; +import static org.jclouds.demo.paas.reference.PaasConstants.PROPERTY_PLATFORM_BASE_URL; +import static org.jclouds.demo.tweetstore.reference.TweetStoreConstants.PROPERTY_TWEETSTORE_BLOBSTORES; +import static org.jclouds.demo.tweetstore.reference.TweetStoreConstants.PROPERTY_TWEETSTORE_CONTAINER; +import static org.jclouds.demo.tweetstore.reference.TwitterConstants.PROPERTY_TWITTER_ACCESSTOKEN; +import static org.jclouds.demo.tweetstore.reference.TwitterConstants.PROPERTY_TWITTER_ACCESSTOKEN_SECRET; +import static org.jclouds.demo.tweetstore.reference.TwitterConstants.PROPERTY_TWITTER_CONSUMER_KEY; +import static org.jclouds.demo.tweetstore.reference.TwitterConstants.PROPERTY_TWITTER_CONSUMER_SECRET; + +import java.util.Map; +import java.util.Properties; +import java.util.Set; + +import javax.servlet.ServletContext; +import javax.servlet.ServletContextEvent; + +import org.jclouds.blobstore.BlobStoreContext; +import org.jclouds.blobstore.BlobStoreContextFactory; +import org.jclouds.demo.paas.PlatformServices; +import org.jclouds.demo.paas.service.taskqueue.TaskQueue; +import org.jclouds.demo.tweetstore.config.util.CredentialsCollector; +import org.jclouds.demo.tweetstore.config.util.PropertiesLoader; +import org.jclouds.demo.tweetstore.controller.AddTweetsController; +import org.jclouds.demo.tweetstore.controller.EnqueueStoresController; +import org.jclouds.demo.tweetstore.controller.StoreTweetsController; + +import twitter4j.Twitter; +import twitter4j.TwitterFactory; +import twitter4j.conf.Configuration; +import twitter4j.conf.ConfigurationBuilder; + +import com.google.common.base.Splitter; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Maps; +import com.google.inject.Guice; +import com.google.inject.Injector; +import com.google.inject.Module; +import com.google.inject.TypeLiteral; +import com.google.inject.name.Names; +import com.google.inject.servlet.GuiceServletContextListener; +import com.google.inject.servlet.ServletModule; + +/** + * Setup Logging and create Injector for use in testing S3. + * + * @author Adrian Cole + */ +public class GuiceServletConfig extends GuiceServletContextListener { + private Map providerTypeToBlobStoreMap; + private Twitter twitterClient; + private String container; + private TaskQueue queue; + private String baseUrl; + + @Override + public void contextInitialized(ServletContextEvent servletContextEvent) { + BlobStoreContextFactory blobStoreContextFactory = new BlobStoreContextFactory(); + ServletContext servletContext = servletContextEvent.getServletContext(); + + Properties props = new PropertiesLoader(servletContext).get(); + Set modules = ImmutableSet.of(); + // shared across all blobstores and used to retrieve tweets + try { + Configuration twitterConf = new ConfigurationBuilder() + .setOAuthConsumerKey(props.getProperty(PROPERTY_TWITTER_CONSUMER_KEY)) + .setOAuthConsumerSecret(props.getProperty(PROPERTY_TWITTER_CONSUMER_SECRET)) + .setOAuthAccessToken(props.getProperty(PROPERTY_TWITTER_ACCESSTOKEN)) + .setOAuthAccessTokenSecret(props.getProperty(PROPERTY_TWITTER_ACCESSTOKEN_SECRET)) + .build(); + twitterClient = new TwitterFactory(twitterConf).getInstance(); + } catch (IllegalArgumentException e) { + throw new IllegalArgumentException("properties for twitter not configured properly in " + props.toString(), e); + } + // common namespace for storing tweets + container = checkNotNull(props.getProperty(PROPERTY_TWEETSTORE_CONTAINER), PROPERTY_TWEETSTORE_CONTAINER); + + // instantiate and store references to all blobstores by provider name + providerTypeToBlobStoreMap = Maps.newHashMap(); + for (String hint : getBlobstoreContexts(props)) { + providerTypeToBlobStoreMap.put(hint, blobStoreContextFactory.createContext(hint, modules, props)); + } + + // get a queue for submitting store tweet requests and the application's base URL + PlatformServices platform = PlatformServices.get(servletContext); + queue = platform.getTaskQueue("twitter"); + baseUrl = platform.getBaseUrl(); + + super.contextInitialized(servletContextEvent); + } + + private static Iterable getBlobstoreContexts(Properties props) { + Set contexts = new CredentialsCollector().apply(props).keySet(); + String explicitContexts = props.getProperty(PROPERTY_TWEETSTORE_BLOBSTORES); + if (explicitContexts != null) { + contexts = filter(contexts, in(copyOf(Splitter.on(',').split(explicitContexts)))); + } + checkState(!contexts.isEmpty(), "no credentials available for any requested context"); + return contexts; + } + + @Override + protected Injector getInjector() { + return Guice.createInjector(new ServletModule() { + @Override + protected void configureServlets() { + bind(new TypeLiteral>() {}) + .toInstance(providerTypeToBlobStoreMap); + bind(Twitter.class).toInstance(twitterClient); + bind(TaskQueue.class).toInstance(queue); + bindConstant().annotatedWith(Names.named(PROPERTY_PLATFORM_BASE_URL)) + .to(baseUrl); + bindConstant().annotatedWith(Names.named(PROPERTY_TWEETSTORE_CONTAINER)) + .to(container); + serve("/store/*").with(StoreTweetsController.class); + serve("/tweets/*").with(AddTweetsController.class); + serve("/stores/*").with(EnqueueStoresController.class); + } + }); + } + + @Override + public void contextDestroyed(ServletContextEvent servletContextEvent) { + for (BlobStoreContext context : providerTypeToBlobStoreMap.values()) { + context.close(); + } + queue.destroy(); + super.contextDestroyed(servletContextEvent); + } +} \ No newline at end of file diff --git a/demos/tweetstore/rhcloud-tweetstore/src/main/java/org/jclouds/demo/tweetstore/config/util/CredentialsCollector.java b/demos/tweetstore/rhcloud-tweetstore/src/main/java/org/jclouds/demo/tweetstore/config/util/CredentialsCollector.java new file mode 100644 index 0000000000..ce3943376e --- /dev/null +++ b/demos/tweetstore/rhcloud-tweetstore/src/main/java/org/jclouds/demo/tweetstore/config/util/CredentialsCollector.java @@ -0,0 +1,153 @@ +/** + * 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.tweetstore.config.util; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; +import static com.google.common.base.Predicates.notNull; +import static com.google.common.collect.Collections2.filter; +import static com.google.common.collect.Collections2.transform; +import static com.google.common.collect.ImmutableSet.copyOf; +import static com.google.common.collect.Maps.filterValues; +import static org.jclouds.util.Maps2.fromKeys; + +import java.util.Collection; +import java.util.Map; +import java.util.Properties; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.jclouds.demo.tweetstore.config.util.CredentialsCollector.Credential; + +import com.google.common.annotations.GwtIncompatible; +import com.google.common.base.Function; +import com.google.common.base.Predicate; + +/** + * Reads provider credentials from a {@link Properties} bag. + * + * @author Andrew Phillips + * + */ +public class CredentialsCollector implements Function> { + private static final String IDENTITY_PROPERTY_SUFFIX = ".identity"; + private static final String CREDENTIAL_PROPERTY_SUFFIX = ".credential"; + + // using the identity for provider name extraction + private static final Pattern IDENTITY_PROPERTY_PATTERN = + Pattern.compile("([a-zA-Z0-9-]+)" + Pattern.quote(IDENTITY_PROPERTY_SUFFIX)); + + @Override + public Map apply(final Properties properties) { + Collection providerNames = transform( + filter(properties.stringPropertyNames(), MatchesPattern.matches(IDENTITY_PROPERTY_PATTERN)), + new Function() { + @Override + public String apply(String input) { + Matcher matcher = IDENTITY_PROPERTY_PATTERN.matcher(input); + // as a side-effect, sets the matching group! + checkState(matcher.matches(), "'%s' should match '%s'", input, IDENTITY_PROPERTY_PATTERN); + return matcher.group(1); + } + }); + /* + * Providers without a credential property result in null values, which are + * removed from the returned map. + */ + return filterValues(fromKeys(copyOf(providerNames), new Function() { + @Override + public Credential apply(String providerName) { + String identity = properties.getProperty(providerName + IDENTITY_PROPERTY_SUFFIX); + String credential = properties.getProperty(providerName + CREDENTIAL_PROPERTY_SUFFIX); + return (((identity != null) && (credential != null)) + ? new Credential(identity, credential) + : null); + } + }), notNull()); + } + + public static class Credential { + private final String identity; + private final String credential; + + public Credential(String identity, String credential) { + this.identity = checkNotNull(identity, "identity"); + this.credential = checkNotNull(credential, "credential"); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + + ((credential == null) ? 0 : credential.hashCode()); + result = prime * result + + ((identity == null) ? 0 : identity.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Credential other = (Credential) obj; + if (credential == null) { + if (other.credential != null) + return false; + } else if (!credential.equals(other.credential)) + return false; + if (identity == null) { + if (other.identity != null) + return false; + } else if (!identity.equals(other.identity)) + return false; + return true; + } + + public String getIdentity() { + return identity; + } + + public String getCredential() { + return credential; + } + } + + @GwtIncompatible(value = "java.util.regex.Pattern") + private static class MatchesPattern implements Predicate { + private final Pattern pattern; + + private MatchesPattern(Pattern pattern) { + this.pattern = pattern; + } + + @Override + public boolean apply(String input) { + return pattern.matcher(input).matches(); + } + + private static MatchesPattern matches(Pattern pattern) { + return new MatchesPattern(pattern); + } + } +} diff --git a/demos/tweetstore/rhcloud-tweetstore/src/main/java/org/jclouds/demo/tweetstore/config/util/PropertiesLoader.java b/demos/tweetstore/rhcloud-tweetstore/src/main/java/org/jclouds/demo/tweetstore/config/util/PropertiesLoader.java new file mode 100644 index 0000000000..dafa5c311b --- /dev/null +++ b/demos/tweetstore/rhcloud-tweetstore/src/main/java/org/jclouds/demo/tweetstore/config/util/PropertiesLoader.java @@ -0,0 +1,59 @@ +/** + * 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.tweetstore.config.util; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Properties; + +import javax.servlet.ServletContext; + +import com.google.common.io.Closeables; +import com.google.inject.Provider; + +/** + * @author Andrew Phillips + */ +public class PropertiesLoader implements Provider{ + private static final String PROPERTIES_FILE = "/WEB-INF/jclouds.properties"; + + private final Properties properties; + + public PropertiesLoader(ServletContext context) { + properties = loadJcloudsProperties(context); + } + + private static Properties loadJcloudsProperties(ServletContext context) { + InputStream input = context.getResourceAsStream(PROPERTIES_FILE); + Properties props = new Properties(); + try { + props.load(input); + } catch (IOException e) { + throw new RuntimeException(e); + } finally { + Closeables.closeQuietly(input); + } + return props; + } + + @Override + public Properties get() { + return properties; + } +} diff --git a/demos/tweetstore/rhcloud-tweetstore/src/main/java/org/jclouds/demo/tweetstore/controller/AddTweetsController.java b/demos/tweetstore/rhcloud-tweetstore/src/main/java/org/jclouds/demo/tweetstore/controller/AddTweetsController.java new file mode 100644 index 0000000000..007fbafdef --- /dev/null +++ b/demos/tweetstore/rhcloud-tweetstore/src/main/java/org/jclouds/demo/tweetstore/controller/AddTweetsController.java @@ -0,0 +1,96 @@ +/** + * 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.tweetstore.controller; + +import java.io.IOException; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeoutException; + +import javax.annotation.Resource; +import javax.inject.Inject; +import javax.inject.Singleton; +import javax.servlet.RequestDispatcher; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.jclouds.blobstore.BlobStoreContext; +import org.jclouds.demo.tweetstore.domain.StoredTweetStatus; +import org.jclouds.demo.tweetstore.functions.ServiceToStoredTweetStatuses; +import org.jclouds.logging.Logger; + +import com.google.common.base.Function; +import com.google.common.collect.Iterables; +import com.google.common.collect.Lists; + +/** + * Shows an example of how to use @{link BlobStoreContext} injected with Guice. + * + * @author Adrian Cole + */ +@Singleton +public class AddTweetsController extends HttpServlet implements + Function, List> { + + /** The serialVersionUID */ + private static final long serialVersionUID = 3888348023150822683L; + private final Map contexts; + private final ServiceToStoredTweetStatuses blobStoreContextToContainerResult; + + @Resource + protected Logger logger = Logger.NULL; + + @Inject + AddTweetsController(Map contexts, + ServiceToStoredTweetStatuses blobStoreContextToContainerResult) { + this.contexts = contexts; + this.blobStoreContextToContainerResult = blobStoreContextToContainerResult; + } + + @Override + protected void doGet(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + try { + addMyTweetsToRequest(request); + RequestDispatcher dispatcher = getServletContext().getRequestDispatcher("/tweets.jsp"); + dispatcher.forward(request, response); + } catch (Exception e) { + logger.error(e, "Error listing containers"); + throw new ServletException(e); + } + } + + void addMyTweetsToRequest(HttpServletRequest request) throws InterruptedException, + ExecutionException, TimeoutException { + request.setAttribute("tweets", apply(contexts.keySet())); + } + + public List apply(Set in) { + List statuses = Lists.newArrayList(); + for (Iterable list : Iterables.transform(in, + blobStoreContextToContainerResult)) { + Iterables.addAll(statuses, list); + } + return statuses; + } +} diff --git a/demos/tweetstore/rhcloud-tweetstore/src/main/java/org/jclouds/demo/tweetstore/controller/EnqueueStoresController.java b/demos/tweetstore/rhcloud-tweetstore/src/main/java/org/jclouds/demo/tweetstore/controller/EnqueueStoresController.java new file mode 100644 index 0000000000..937766c460 --- /dev/null +++ b/demos/tweetstore/rhcloud-tweetstore/src/main/java/org/jclouds/demo/tweetstore/controller/EnqueueStoresController.java @@ -0,0 +1,100 @@ +/** + * 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.tweetstore.controller; + +import static com.google.common.base.Strings.nullToEmpty; + +import java.io.IOException; +import java.net.URI; +import java.util.Map; +import java.util.Set; + +import javax.annotation.Resource; +import javax.inject.Inject; +import javax.inject.Named; +import javax.inject.Singleton; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.ws.rs.core.MediaType; + +import org.jclouds.blobstore.BlobStoreContext; +import org.jclouds.demo.paas.reference.PaasConstants; +import org.jclouds.demo.paas.service.taskqueue.TaskQueue; +import org.jclouds.http.HttpRequest; +import org.jclouds.logging.Logger; + +import com.google.common.annotations.VisibleForTesting; +import com.google.common.collect.ImmutableMultimap; + +/** + * Adds tasks to retrieve and store tweets in all registered contexts to an async + * task queue. + * + * @author Andrew Phillips + * @see StoreTweetsController + */ +@Singleton +public class EnqueueStoresController extends HttpServlet { + /** The serialVersionUID */ + private static final long serialVersionUID = 7215420527854203714L; + + private final Set contextNames; + private final TaskQueue taskQueue; + private final String baseUrl; + + @Resource + protected Logger logger = Logger.NULL; + + @Inject + public EnqueueStoresController(Map contexts, TaskQueue taskQueue, + @Named(PaasConstants.PROPERTY_PLATFORM_BASE_URL) String baseUrl) { + contextNames = contexts.keySet(); + this.taskQueue = taskQueue; + this.baseUrl = baseUrl; + } + + @VisibleForTesting + void enqueueStoreTweetTasks() { + for (String contextName : contextNames) { + logger.debug("enqueuing task to store tweets in blobstore '%s'", contextName); + taskQueue.add(taskQueue.getHttpRequestFactory().create(HttpRequest.builder() + .endpoint(URI.create(baseUrl + "/store/do")) + .headers(ImmutableMultimap.of("context", contextName)) + .method("GET").build())); + } + } + + @Override + protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + if (!nullToEmpty(request.getHeader("X-Rhcloud-Cron")).equals("true")) { + response.sendError(401); + } + + try { + enqueueStoreTweetTasks(); + response.setContentType(MediaType.TEXT_PLAIN); + response.getWriter().println("Done!"); + } catch (Exception e) { + logger.error(e, "Error storing tweets"); + throw new ServletException(e); + } + } +} \ No newline at end of file diff --git a/demos/tweetstore/rhcloud-tweetstore/src/main/java/org/jclouds/demo/tweetstore/controller/StoreTweetsController.java b/demos/tweetstore/rhcloud-tweetstore/src/main/java/org/jclouds/demo/tweetstore/controller/StoreTweetsController.java new file mode 100644 index 0000000000..948c9ff4ca --- /dev/null +++ b/demos/tweetstore/rhcloud-tweetstore/src/main/java/org/jclouds/demo/tweetstore/controller/StoreTweetsController.java @@ -0,0 +1,130 @@ +/** + * 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.tweetstore.controller; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Strings.nullToEmpty; +import static org.jclouds.demo.paas.RunnableHttpRequest.PLATFORM_REQUEST_ORIGINATOR_HEADER; + +import java.io.IOException; +import java.util.Map; + +import javax.annotation.Resource; +import javax.inject.Inject; +import javax.inject.Named; +import javax.inject.Singleton; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.ws.rs.core.MediaType; + +import org.jclouds.blobstore.BlobMap; +import org.jclouds.blobstore.BlobStoreContext; +import org.jclouds.blobstore.domain.Blob; +import org.jclouds.demo.tweetstore.reference.TweetStoreConstants; +import org.jclouds.logging.Logger; +import org.jclouds.rest.AuthorizationException; + +import twitter4j.Status; +import twitter4j.Twitter; + +import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Function; + +/** + * Grab tweets related to me and store them into blobstores + * + * @author Adrian Cole + */ +@Singleton +public class StoreTweetsController extends HttpServlet { + + private static final class StatusToBlob implements Function { + private final BlobMap map; + + private StatusToBlob(BlobMap map) { + this.map = map; + } + + public Blob apply(Status from) { + Blob to = map.blobBuilder().name(from.getId() + "").build(); + to.setPayload(from.getText()); + to.getPayload().getContentMetadata().setContentType(MediaType.TEXT_PLAIN); + to.getMetadata().getUserMetadata().put(TweetStoreConstants.SENDER_NAME, from.getUser().getScreenName()); + return to; + } + } + + /** The serialVersionUID */ + private static final long serialVersionUID = 7215420527854203714L; + + private final Map contexts; + private final Twitter client; + private final String container; + + @Resource + protected Logger logger = Logger.NULL; + + @Inject + @VisibleForTesting + public StoreTweetsController(Map contexts, + @Named(TweetStoreConstants.PROPERTY_TWEETSTORE_CONTAINER) String container, Twitter client) { + this.container = container; + this.contexts = contexts; + this.client = client; + } + + @VisibleForTesting + public void addMyTweets(String contextName, Iterable responseList) { + BlobStoreContext context = checkNotNull(contexts.get(contextName), "no context for " + contextName + " in " + + contexts.keySet()); + BlobMap map = context.createBlobMap(container); + for (Status status : responseList) { + Blob blob = null; + try { + blob = new StatusToBlob(map).apply(status); + map.put(status.getId() + "", blob); + } catch (AuthorizationException e) { + throw e; + } catch (Exception e) { + logger.error(e, "Error storing tweet %s (blob[%s]) on map %s/%s", status.getId(), blob, context, container); + } + } + } + + @Override + protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + if (nullToEmpty(request.getHeader(PLATFORM_REQUEST_ORIGINATOR_HEADER)).equals("taskqueue-twitter")) { + try { + String contextName = checkNotNull(request.getHeader("context"), "missing header context"); + logger.info("retrieving tweets"); + addMyTweets(contextName, client.getMentions()); + logger.debug("done storing tweets"); + response.setContentType(MediaType.TEXT_PLAIN); + response.getWriter().println("Done!"); + } catch (Exception e) { + logger.error(e, "Error storing tweets"); + throw new ServletException(e); + } + } else { + response.sendError(401); + } + } +} \ No newline at end of file diff --git a/demos/tweetstore/rhcloud-tweetstore/src/main/java/org/jclouds/demo/tweetstore/domain/StoredTweetStatus.java b/demos/tweetstore/rhcloud-tweetstore/src/main/java/org/jclouds/demo/tweetstore/domain/StoredTweetStatus.java new file mode 100644 index 0000000000..42ad65df01 --- /dev/null +++ b/demos/tweetstore/rhcloud-tweetstore/src/main/java/org/jclouds/demo/tweetstore/domain/StoredTweetStatus.java @@ -0,0 +1,149 @@ +/** + * 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.tweetstore.domain; + +import java.io.Serializable; + +/** + * + * @author Adrian Cole + */ +public class StoredTweetStatus implements Comparable, Serializable { + + /** The serialVersionUID */ + private static final long serialVersionUID = -3257496189689220018L; + private final String service; + private final String host; + private final String container; + private final String id; + private final String from; + private final String tweet; + private final String status; + + @Override + public String toString() { + return "StoredTweetStatus [container=" + container + ", from=" + from + ", host=" + host + + ", id=" + id + ", service=" + service + ", status=" + status + ", tweet=" + tweet + + "]"; + } + + public StoredTweetStatus(String service, String host, String container, String id, String from, + String tweet, String status) { + this.service = service; + this.host = host; + this.container = container; + this.id = id; + this.from = from; + this.tweet = tweet; + this.status = status; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((container == null) ? 0 : container.hashCode()); + result = prime * result + ((from == null) ? 0 : from.hashCode()); + result = prime * result + ((host == null) ? 0 : host.hashCode()); + result = prime * result + ((id == null) ? 0 : id.hashCode()); + result = prime * result + ((service == null) ? 0 : service.hashCode()); + result = prime * result + ((tweet == null) ? 0 : tweet.hashCode()); + return result; + } + + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + StoredTweetStatus other = (StoredTweetStatus) obj; + if (container == null) { + if (other.container != null) + return false; + } else if (!container.equals(other.container)) + return false; + if (from == null) { + if (other.from != null) + return false; + } else if (!from.equals(other.from)) + return false; + if (host == null) { + if (other.host != null) + return false; + } else if (!host.equals(other.host)) + return false; + if (id == null) { + if (other.id != null) + return false; + } else if (!id.equals(other.id)) + return false; + if (service == null) { + if (other.service != null) + return false; + } else if (!service.equals(other.service)) + return false; + if (tweet == null) { + if (other.tweet != null) + return false; + } else if (!tweet.equals(other.tweet)) + return false; + return true; + } + + + public String getService() { + return service; + } + + public String getHost() { + return host; + } + + public String getContainer() { + return container; + } + + public String getFrom() { + return from; + } + + public String getTweet() { + return tweet; + } + + public String getStatus() { + return status; + } + + public int compareTo(StoredTweetStatus o) { + if (id == null) + return -1; + return (int) ((this == o) ? 0 : id.compareTo(o.id)); + } + + + public String getId() { + return id; + } + +} diff --git a/demos/tweetstore/rhcloud-tweetstore/src/main/java/org/jclouds/demo/tweetstore/functions/KeyToStoredTweetStatus.java b/demos/tweetstore/rhcloud-tweetstore/src/main/java/org/jclouds/demo/tweetstore/functions/KeyToStoredTweetStatus.java new file mode 100644 index 0000000000..2a6ea0a69c --- /dev/null +++ b/demos/tweetstore/rhcloud-tweetstore/src/main/java/org/jclouds/demo/tweetstore/functions/KeyToStoredTweetStatus.java @@ -0,0 +1,71 @@ +/** + * 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.tweetstore.functions; + +import static org.jclouds.util.Strings2.toStringAndClose; + +import javax.annotation.Resource; + +import org.jclouds.blobstore.BlobMap; +import org.jclouds.blobstore.domain.Blob; +import org.jclouds.demo.tweetstore.domain.StoredTweetStatus; +import org.jclouds.demo.tweetstore.reference.TweetStoreConstants; +import org.jclouds.logging.Logger; + +import com.google.common.base.Function; + +/** + * + * @author Adrian Cole + */ +public class KeyToStoredTweetStatus implements Function { + private final String host; + private final BlobMap map; + private final String service; + private final String container; + + @Resource + protected Logger logger = Logger.NULL; + + KeyToStoredTweetStatus(BlobMap map, String service, String host, String container) { + this.host = host; + this.map = map; + this.service = service; + this.container = container; + } + + public StoredTweetStatus apply(String id) { + String status; + String from; + String tweet; + try { + long start = System.currentTimeMillis(); + Blob blob = map.get(id); + status = ((System.currentTimeMillis() - start) + "ms"); + from = blob.getMetadata().getUserMetadata().get(TweetStoreConstants.SENDER_NAME); + tweet = toStringAndClose(blob.getPayload().getInput()); + } catch (Exception e) { + logger.error(e, "Error listing container %s//%s/%s", service, container, id); + status = (e.getMessage()); + tweet = ""; + from = ""; + } + return new StoredTweetStatus(service, host, container, id, from, tweet, status); + } +} diff --git a/demos/tweetstore/rhcloud-tweetstore/src/main/java/org/jclouds/demo/tweetstore/functions/ServiceToStoredTweetStatuses.java b/demos/tweetstore/rhcloud-tweetstore/src/main/java/org/jclouds/demo/tweetstore/functions/ServiceToStoredTweetStatuses.java new file mode 100644 index 0000000000..0807c7bb46 --- /dev/null +++ b/demos/tweetstore/rhcloud-tweetstore/src/main/java/org/jclouds/demo/tweetstore/functions/ServiceToStoredTweetStatuses.java @@ -0,0 +1,71 @@ +/** + * 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.tweetstore.functions; + +import java.util.Collections; +import java.util.Map; +import java.util.Set; + +import javax.annotation.Resource; +import javax.inject.Inject; +import javax.inject.Named; +import javax.inject.Singleton; + +import org.jclouds.blobstore.BlobMap; +import org.jclouds.blobstore.BlobStoreContext; +import org.jclouds.demo.tweetstore.domain.StoredTweetStatus; +import org.jclouds.demo.tweetstore.reference.TweetStoreConstants; +import org.jclouds.logging.Logger; + +import com.google.common.base.Function; +import com.google.common.collect.Iterables; + +@Singleton +public class ServiceToStoredTweetStatuses implements Function> { + + private final Map contexts; + private final String container; + + @Inject + public ServiceToStoredTweetStatuses(Map contexts, + @Named(TweetStoreConstants.PROPERTY_TWEETSTORE_CONTAINER) String container) { + this.contexts = contexts; + this.container = container; + } + + @Resource + protected Logger logger = Logger.NULL; + + public Iterable apply(String service) { + BlobStoreContext context = contexts.get(service); + String host = context.getProviderSpecificContext().getEndpoint().getHost(); + try { + BlobMap blobMap = context.createBlobMap(container); + Set blobs = blobMap.keySet(); + return Iterables.transform(blobs, new KeyToStoredTweetStatus(blobMap, service, host, + container)); + } catch (Exception e) { + StoredTweetStatus result = new StoredTweetStatus(service, host, container, null, null, + null, e.getMessage()); + logger.error(e, "Error listing service %s", service); + return Collections.singletonList(result); + } + + } +} \ No newline at end of file diff --git a/demos/tweetstore/rhcloud-tweetstore/src/main/java/org/jclouds/demo/tweetstore/reference/TweetStoreConstants.java b/demos/tweetstore/rhcloud-tweetstore/src/main/java/org/jclouds/demo/tweetstore/reference/TweetStoreConstants.java new file mode 100644 index 0000000000..42ec480ae2 --- /dev/null +++ b/demos/tweetstore/rhcloud-tweetstore/src/main/java/org/jclouds/demo/tweetstore/reference/TweetStoreConstants.java @@ -0,0 +1,34 @@ +/** + * 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.tweetstore.reference; + +/** + * Configuration properties and constants used in TweetStore connections. + * + * @author Adrian Cole + */ +public interface TweetStoreConstants { + static final String PROPERTY_TWEETSTORE_BLOBSTORES = "jclouds.tweetstore.blobstores"; + static final String PROPERTY_TWEETSTORE_CONTAINER = "jclouds.tweetstore.container"; + /** + * Note that this has to conform to restrictions of all blobstores. for + * example, azure doesn't support periods. + */ + static final String SENDER_NAME = "sendername"; +} diff --git a/demos/tweetstore/rhcloud-tweetstore/src/main/java/org/jclouds/demo/tweetstore/reference/TwitterConstants.java b/demos/tweetstore/rhcloud-tweetstore/src/main/java/org/jclouds/demo/tweetstore/reference/TwitterConstants.java new file mode 100644 index 0000000000..dc8b97915f --- /dev/null +++ b/demos/tweetstore/rhcloud-tweetstore/src/main/java/org/jclouds/demo/tweetstore/reference/TwitterConstants.java @@ -0,0 +1,31 @@ +/** + * 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.tweetstore.reference; + +/** + * Configuration properties and constants used in Twitter connections. + * + * @author Andrew Phillips + */ +public interface TwitterConstants { + static final String PROPERTY_TWITTER_CONSUMER_KEY = "twitter.consumer.identity"; + static final String PROPERTY_TWITTER_CONSUMER_SECRET = "twitter.consumer.credential"; + static final String PROPERTY_TWITTER_ACCESSTOKEN = "twitter.access.identity"; + static final String PROPERTY_TWITTER_ACCESSTOKEN_SECRET = "twitter.access.credential"; +} diff --git a/demos/tweetstore/rhcloud-tweetstore/src/main/platform/.gitignore b/demos/tweetstore/rhcloud-tweetstore/src/main/platform/.gitignore new file mode 100644 index 0000000000..843dfe79c0 --- /dev/null +++ b/demos/tweetstore/rhcloud-tweetstore/src/main/platform/.gitignore @@ -0,0 +1 @@ +# PaaS vendor specific files go in here \ No newline at end of file diff --git a/demos/tweetstore/rhcloud-tweetstore/src/main/webapp/WEB-INF/web.xml b/demos/tweetstore/rhcloud-tweetstore/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 0000000000..5bf6bdf0bb --- /dev/null +++ b/demos/tweetstore/rhcloud-tweetstore/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,51 @@ + + + + jclouds-tweetstore + + + + guiceFilter + com.google.inject.servlet.GuiceFilter + + + + guiceFilter + /* + + + + + org.jclouds.demo.paas.config.PlatformServicesInitializer + + + + org.jclouds.demo.tweetstore.config.GuiceServletConfig + + + + index.jsp + + + \ No newline at end of file diff --git a/demos/tweetstore/rhcloud-tweetstore/src/main/webapp/images/openshift-logo.png b/demos/tweetstore/rhcloud-tweetstore/src/main/webapp/images/openshift-logo.png new file mode 100644 index 0000000000..fc0075f9d4 Binary files /dev/null and b/demos/tweetstore/rhcloud-tweetstore/src/main/webapp/images/openshift-logo.png differ diff --git a/demos/tweetstore/rhcloud-tweetstore/src/main/webapp/index.jsp b/demos/tweetstore/rhcloud-tweetstore/src/main/webapp/index.jsp new file mode 100644 index 0000000000..977ad5a303 --- /dev/null +++ b/demos/tweetstore/rhcloud-tweetstore/src/main/webapp/index.jsp @@ -0,0 +1,30 @@ +<%-- + + 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. + +--%> + + +jclouds: anyweight cloudware for java + + +

Welcome!

+

Click here to see tweets about jclouds.

+

Powered by OpenShift Express

+ + diff --git a/demos/tweetstore/rhcloud-tweetstore/src/main/webapp/tweets.jsp b/demos/tweetstore/rhcloud-tweetstore/src/main/webapp/tweets.jsp new file mode 100644 index 0000000000..351af2f4fd --- /dev/null +++ b/demos/tweetstore/rhcloud-tweetstore/src/main/webapp/tweets.jsp @@ -0,0 +1,108 @@ +<%-- + + 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. + +--%> +<%@ page buffer="20kb"%> +<%@ taglib uri="http://displaytag.sf.net" prefix="display"%> + + +jclouds: anyweight cloudware for java + + + +

Tweets in Clouds

+ + + + + + + +
+
+ + + + + + + + +
+
Powered by OpenShift Express
+ + diff --git a/demos/tweetstore/rhcloud-tweetstore/src/test/java/org/jboss/as/embedded/EmbeddedServerFactory2.java b/demos/tweetstore/rhcloud-tweetstore/src/test/java/org/jboss/as/embedded/EmbeddedServerFactory2.java new file mode 100644 index 0000000000..8d5e3d69ab --- /dev/null +++ b/demos/tweetstore/rhcloud-tweetstore/src/test/java/org/jboss/as/embedded/EmbeddedServerFactory2.java @@ -0,0 +1,96 @@ +/** + * 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.jboss.as.embedded; + +import java.io.File; +import java.util.Map; +import java.util.Properties; +import java.util.logging.LogManager; + +import org.jboss.modules.Module; +import org.jboss.modules.ModuleClassLoader; +import org.jboss.modules.ModuleIdentifier; +import org.jboss.modules.ModuleLoadException; +import org.jboss.modules.ModuleLoader; +import org.jboss.modules.log.JDKModuleLogger; +import org.jclouds.demo.tweetstore.integration.util.ObjectFields; + +/** + * A variant of {@link EmbeddedServerFactory} that resets JDK logging for JBoss, + * which requires its own settings in this area. + * + * Needs to be in the org.jboss.as.embedded package to be able to use + * {@code InitialModuleLoaderFactory}. + * + * @author Andrew Phillips + * @see EmbeddedServerFactory + */ +public class EmbeddedServerFactory2 { + + // mainly copied from EmbeddedServerFactory + public static StandaloneServer create(final File jbossHomeDir, final Properties systemProps, final Map systemEnv, String...systemPackages) { + if (jbossHomeDir == null || jbossHomeDir.isDirectory() == false) + throw new IllegalStateException("Invalid jboss.home.dir: " + jbossHomeDir); + + if (systemProps.getProperty(ServerEnvironment.HOME_DIR) == null) + systemProps.setProperty(ServerEnvironment.HOME_DIR, jbossHomeDir.getAbsolutePath()); + + File modulesDir = new File(jbossHomeDir + "/modules"); + final ModuleLoader moduleLoader = InitialModuleLoaderFactory.getModuleLoader(modulesDir, systemPackages); + + try { + Module.registerURLStreamHandlerFactoryModule(moduleLoader.loadModule(ModuleIdentifier.create("org.jboss.vfs"))); + + // Initialize the Logging system + ModuleIdentifier logModuleId = ModuleIdentifier.create("org.jboss.logmanager"); + ModuleClassLoader logModuleClassLoader = moduleLoader.loadModule(logModuleId).getClassLoader(); + try { + /* + * The original code simply sets the thread context classloader and lets LogManager + * load the class. This causes problems in tests because any other component that + * also happens to use JDK logging will have potentially loaded a *different* + * LogManager. + * If you force the JBoss LogManager to be loaded (by setting the 'java.util.logging.manager' + * system property) earlier in the test run, it will not be loaded by the correct + * classloader and cause ClassCastExceptions. + */ + LogManager jbossLogManager = (LogManager) logModuleClassLoader.loadClass("org.jboss.logmanager.LogManager").newInstance(); + ObjectFields.set("manager", null, jbossLogManager, LogManager.class); + ObjectFields.set("readPrimordialConfiguration", jbossLogManager, false, LogManager.class); + + if (LogManager.getLogManager().getClass() == LogManager.class) { + System.err.println("WARNING: Failed to load the specified logmodule " + logModuleId); + } else { + Module.setModuleLogger(new JDKModuleLogger()); + } + } catch (Exception exception) { + // copied from LogManager + System.err.println("Could not load Logmanager \"org.jboss.logmanager.LogManager\""); + exception.printStackTrace(); + } + + __redirected.__JAXPRedirected.changeAll(ModuleIdentifier.fromString("javax.xml.jaxp-provider"), moduleLoader); + + return EmbeddedServerFactory.create(moduleLoader, jbossHomeDir, systemProps, systemEnv); + } + catch (ModuleLoadException e) { + throw new RuntimeException(e); + } + } +} diff --git a/demos/tweetstore/rhcloud-tweetstore/src/test/java/org/jclouds/demo/tweetstore/config/util/CredentialsCollectorTest.java b/demos/tweetstore/rhcloud-tweetstore/src/test/java/org/jclouds/demo/tweetstore/config/util/CredentialsCollectorTest.java new file mode 100644 index 0000000000..031bb199fc --- /dev/null +++ b/demos/tweetstore/rhcloud-tweetstore/src/test/java/org/jclouds/demo/tweetstore/config/util/CredentialsCollectorTest.java @@ -0,0 +1,82 @@ +/** + * 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.tweetstore.config.util; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; + +import java.util.Map; +import java.util.Properties; + +import org.jclouds.demo.tweetstore.config.util.CredentialsCollector; +import org.jclouds.demo.tweetstore.config.util.CredentialsCollector.Credential; +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableMap; + +/** + * Tests behavior of {@code CredentialsCollector} + * + * @author Andrew Phillips + */ +@Test(groups = "unit") +public class CredentialsCollectorTest { + private CredentialsCollector collector = new CredentialsCollector(); + + public void testEmptyProperties() { + assertTrue(collector.apply(new Properties()).isEmpty(), + "Expected returned map to be empty"); + } + + public void testNoCredentials() { + Properties properties = propertiesOf(ImmutableMap.of("not-an-identity", + "v1", "not-a-credential", "v2")); + assertTrue(collector.apply(properties).isEmpty(), + "Expected returned map to be empty"); + } + + private static Properties propertiesOf(Map entries) { + Properties properties = new Properties(); + properties.putAll(entries); + return properties; + } + + public void testNonMatchingCredentials() { + Properties properties = propertiesOf(ImmutableMap.of("non_matching.identity", "v1", + "non_matching.credential", "v2")); + assertTrue(collector.apply(properties).isEmpty(), + "Expected returned map to be empty"); + } + + public void testIncompleteCredentials() { + Properties properties = propertiesOf(ImmutableMap.of("acme.identity", "v1", + "acme-2.credential", "v2")); + assertTrue(collector.apply(properties).isEmpty(), + "Expected returned map to be empty"); + } + + public void testCredentials() { + Properties properties = propertiesOf(ImmutableMap.of("acme.identity", "v1", + "acme.credential", "v2", "acme-2.identity", "v3", + "acme-2.credential", "v4")); + assertEquals(collector.apply(properties), + ImmutableMap.of("acme", new Credential("v1", "v2"), + "acme-2", new Credential("v3", "v4"))); + } +} \ No newline at end of file diff --git a/demos/tweetstore/rhcloud-tweetstore/src/test/java/org/jclouds/demo/tweetstore/controller/AddTweetsControllerTest.java b/demos/tweetstore/rhcloud-tweetstore/src/test/java/org/jclouds/demo/tweetstore/controller/AddTweetsControllerTest.java new file mode 100644 index 0000000000..f8328fa44e --- /dev/null +++ b/demos/tweetstore/rhcloud-tweetstore/src/test/java/org/jclouds/demo/tweetstore/controller/AddTweetsControllerTest.java @@ -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.demo.tweetstore.controller; + +import static org.testng.Assert.assertEquals; + +import java.io.IOException; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ExecutionException; + +import org.jclouds.blobstore.BlobStoreContext; +import org.jclouds.blobstore.BlobStoreContextFactory; +import org.jclouds.blobstore.domain.Blob; +import org.jclouds.demo.tweetstore.domain.StoredTweetStatus; +import org.jclouds.demo.tweetstore.functions.ServiceToStoredTweetStatuses; +import org.jclouds.demo.tweetstore.reference.TweetStoreConstants; +import org.testng.annotations.Test; +import org.testng.collections.Maps; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; + +/** + * Tests behavior of {@code AddTweetsController} + * + * @author Adrian Cole + */ +@Test(groups = "unit") +public class AddTweetsControllerTest { + + Map createServices(String container) throws InterruptedException, + ExecutionException { + Map services = Maps.newHashMap(); + for (String name : new String[] { "1", "2" }) { + BlobStoreContext context = new BlobStoreContextFactory().createContext("transient", "dummy", "dummy"); + context.getAsyncBlobStore().createContainerInLocation(null, container).get(); + Blob blob = context.getAsyncBlobStore().blobBuilder("1").build(); + blob.getMetadata().getUserMetadata().put(TweetStoreConstants.SENDER_NAME, "frank"); + blob.setPayload("I love beans!"); + context.getAsyncBlobStore().putBlob(container, blob).get(); + services.put(name, context); + } + return services; + } + + public void testStoreTweets() throws IOException, InterruptedException, ExecutionException { + String container = "container"; + Map contexts = createServices(container); + + ServiceToStoredTweetStatuses function = new ServiceToStoredTweetStatuses(contexts, container); + AddTweetsController controller = new AddTweetsController(contexts, function); + List list = controller.apply(ImmutableSet.of("1", "2")); + assertEquals(list.size(), 2); + assertEquals(list, ImmutableList.of(new StoredTweetStatus("1", "localhost", container, "1", + "frank", "I love beans!", null), new StoredTweetStatus("2", "localhost", container, + "1", "frank", "I love beans!", null))); + + } +} diff --git a/demos/tweetstore/rhcloud-tweetstore/src/test/java/org/jclouds/demo/tweetstore/controller/EnqueueStoresControllerTest.java b/demos/tweetstore/rhcloud-tweetstore/src/test/java/org/jclouds/demo/tweetstore/controller/EnqueueStoresControllerTest.java new file mode 100644 index 0000000000..ff3b651175 --- /dev/null +++ b/demos/tweetstore/rhcloud-tweetstore/src/test/java/org/jclouds/demo/tweetstore/controller/EnqueueStoresControllerTest.java @@ -0,0 +1,83 @@ +/** + * 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.tweetstore.controller; + +import static org.easymock.EasyMock.*; + +import java.net.URI; +import java.util.Map; + +import org.jclouds.blobstore.BlobStoreContext; +import org.jclouds.blobstore.BlobStoreContextFactory; +import org.jclouds.demo.paas.RunnableHttpRequest; +import org.jclouds.demo.paas.RunnableHttpRequest.Factory; +import org.jclouds.demo.paas.service.taskqueue.TaskQueue; +import org.jclouds.http.HttpRequest; +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableMultimap; + +/** + * Tests behavior of {@code EnqueueStoresController} + * + * @author Andrew Phillips + */ +@Test(groups = "unit") +public class EnqueueStoresControllerTest { + + Map createBlobStores() { + Map contexts = ImmutableMap.of( + "test1", new BlobStoreContextFactory().createContext("transient", "dummy", "dummy"), + "test2", new BlobStoreContextFactory().createContext("transient", "dummy", "dummy")); + return contexts; + } + + public void testEnqueueStores() { + Map stores = createBlobStores(); + TaskQueue taskQueue = createMock(TaskQueue.class); + Factory httpRequestFactory = createMock(Factory.class); + EnqueueStoresController function = new EnqueueStoresController(stores, + taskQueue, "http://localhost:8080"); + + expect(taskQueue.getHttpRequestFactory()).andStubReturn(httpRequestFactory); + + HttpRequest storeInTest1Request = HttpRequest.builder().endpoint( + URI.create("http://localhost:8080/store/do")) + .headers(ImmutableMultimap.of("context", "test1")).method("GET").build(); + RunnableHttpRequest storeInTest1Task = null; + expect(httpRequestFactory.create(eq(storeInTest1Request))).andReturn(storeInTest1Task); + + HttpRequest storeInTest2Request = HttpRequest.builder().endpoint( + URI.create("http://localhost:8080/store/do")) + .headers(ImmutableMultimap.of("context", "test2")).method("GET").build(); + RunnableHttpRequest storeInTest2Task = null; + expect(httpRequestFactory.create(eq(storeInTest2Request))).andReturn(storeInTest2Task); + + taskQueue.add(storeInTest1Task); + expectLastCall(); + taskQueue.add(storeInTest2Task); + expectLastCall(); + replay(httpRequestFactory, taskQueue); + + function.enqueueStoreTweetTasks(); + + verify(taskQueue); + } +} \ No newline at end of file diff --git a/demos/tweetstore/rhcloud-tweetstore/src/test/java/org/jclouds/demo/tweetstore/controller/StoreTweetsControllerTest.java b/demos/tweetstore/rhcloud-tweetstore/src/test/java/org/jclouds/demo/tweetstore/controller/StoreTweetsControllerTest.java new file mode 100644 index 0000000000..0e82a13f25 --- /dev/null +++ b/demos/tweetstore/rhcloud-tweetstore/src/test/java/org/jclouds/demo/tweetstore/controller/StoreTweetsControllerTest.java @@ -0,0 +1,118 @@ +/** + * 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.tweetstore.controller; + +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.jclouds.util.Strings2.toStringAndClose; +import static org.testng.Assert.assertEquals; + +import java.io.IOException; +import java.util.Map; +import java.util.Map.Entry; +import java.util.concurrent.ExecutionException; + +import org.jclouds.blobstore.BlobMap; +import org.jclouds.blobstore.BlobStoreContext; +import org.jclouds.blobstore.BlobStoreContextFactory; +import org.jclouds.blobstore.domain.Blob; +import org.jclouds.demo.tweetstore.reference.TweetStoreConstants; +import org.testng.annotations.Test; + +import twitter4j.Status; +import twitter4j.Twitter; +import twitter4j.User; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; + +/** + * Tests behavior of {@code StoreTweetsController} + * + * @author Adrian Cole + */ +@Test(groups = "unit") +public class StoreTweetsControllerTest { + + Twitter createTwitter() { + return createMock(Twitter.class); + } + + Map createBlobStores() throws InterruptedException, ExecutionException { + Map contexts = ImmutableMap. of("test1", + new BlobStoreContextFactory().createContext("transient", "dummy", "dummy"), "test2", + new BlobStoreContextFactory().createContext("transient", "dummy", "dummy")); + for (BlobStoreContext blobstore : contexts.values()) { + blobstore.getAsyncBlobStore().createContainerInLocation(null, "favo").get(); + } + return contexts; + } + + public void testStoreTweets() throws IOException, InterruptedException, ExecutionException { + Map stores = createBlobStores(); + StoreTweetsController function = new StoreTweetsController(stores, "favo", createTwitter()); + + User frank = createMock(User.class); + expect(frank.getScreenName()).andReturn("frank").atLeastOnce(); + + Status frankStatus = createMock(Status.class); + expect(frankStatus.getId()).andReturn(1l).atLeastOnce(); + expect(frankStatus.getUser()).andReturn(frank).atLeastOnce(); + expect(frankStatus.getText()).andReturn("I love beans!").atLeastOnce(); + + User jimmy = createMock(User.class); + expect(jimmy.getScreenName()).andReturn("jimmy").atLeastOnce(); + + Status jimmyStatus = createMock(Status.class); + expect(jimmyStatus.getId()).andReturn(2l).atLeastOnce(); + expect(jimmyStatus.getUser()).andReturn(jimmy).atLeastOnce(); + expect(jimmyStatus.getText()).andReturn("cloud is king").atLeastOnce(); + + replay(frank); + replay(frankStatus); + replay(jimmy); + replay(jimmyStatus); + + function.addMyTweets("test1", ImmutableList.of(frankStatus, jimmyStatus)); + function.addMyTweets("test2", ImmutableList.of(frankStatus, jimmyStatus)); + + verify(frank); + verify(frankStatus); + verify(jimmy); + verify(jimmyStatus); + + for (Entry entry : stores.entrySet()) { + BlobMap map = entry.getValue().createBlobMap("favo"); + Blob frankBlob = map.get("1"); + assertEquals(frankBlob.getMetadata().getName(), "1"); + assertEquals(frankBlob.getMetadata().getUserMetadata().get(TweetStoreConstants.SENDER_NAME), "frank"); + assertEquals(frankBlob.getMetadata().getContentMetadata().getContentType(), "text/plain"); + assertEquals(toStringAndClose(frankBlob.getPayload().getInput()), "I love beans!"); + + Blob jimmyBlob = map.get("2"); + assertEquals(jimmyBlob.getMetadata().getName(), "2"); + assertEquals(jimmyBlob.getMetadata().getUserMetadata().get(TweetStoreConstants.SENDER_NAME), "jimmy"); + assertEquals(jimmyBlob.getMetadata().getContentMetadata().getContentType(), "text/plain"); + assertEquals(toStringAndClose(jimmyBlob.getPayload().getInput()), "cloud is king"); + } + + } +} diff --git a/demos/tweetstore/rhcloud-tweetstore/src/test/java/org/jclouds/demo/tweetstore/functions/KeyToStoredTweetStatusTest.java b/demos/tweetstore/rhcloud-tweetstore/src/test/java/org/jclouds/demo/tweetstore/functions/KeyToStoredTweetStatusTest.java new file mode 100644 index 0000000000..c662dd8a74 --- /dev/null +++ b/demos/tweetstore/rhcloud-tweetstore/src/test/java/org/jclouds/demo/tweetstore/functions/KeyToStoredTweetStatusTest.java @@ -0,0 +1,67 @@ +/** + * 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.tweetstore.functions; + +import static org.testng.Assert.assertEquals; + +import java.io.IOException; +import java.util.concurrent.ExecutionException; + +import org.jclouds.blobstore.BlobMap; +import org.jclouds.blobstore.BlobStoreContext; +import org.jclouds.blobstore.BlobStoreContextFactory; +import org.jclouds.blobstore.domain.Blob; +import org.jclouds.demo.tweetstore.domain.StoredTweetStatus; +import org.jclouds.demo.tweetstore.reference.TweetStoreConstants; +import org.testng.annotations.Test; + +/** + * Tests behavior of {@code KeyToStoredTweetStatus} + * + * @author Adrian Cole + */ +@Test(groups = "unit") +public class KeyToStoredTweetStatusTest { + + BlobMap createMap() throws InterruptedException, ExecutionException { + BlobStoreContext context = new BlobStoreContextFactory().createContext("transient", "dummy", "dummy"); + context.getBlobStore().createContainerInLocation(null, "test1"); + return context.createBlobMap("test1"); + } + + public void testStoreTweets() throws IOException, InterruptedException, ExecutionException { + BlobMap map = createMap(); + Blob blob = map.blobBuilder().name("1").build(); + blob.getMetadata().getUserMetadata().put(TweetStoreConstants.SENDER_NAME, "frank"); + blob.setPayload("I love beans!"); + map.put("1", blob); + String host = "localhost"; + String service = "stub"; + String container = "tweetstore"; + + KeyToStoredTweetStatus function = new KeyToStoredTweetStatus(map, service, host, container); + StoredTweetStatus result = function.apply("1"); + + StoredTweetStatus expected = new StoredTweetStatus(service, host, container, "1", "frank", + "I love beans!", null); + + assertEquals(result, expected); + + } +} diff --git a/demos/tweetstore/rhcloud-tweetstore/src/test/java/org/jclouds/demo/tweetstore/functions/ServiceToStoredTweetStatusesTest.java b/demos/tweetstore/rhcloud-tweetstore/src/test/java/org/jclouds/demo/tweetstore/functions/ServiceToStoredTweetStatusesTest.java new file mode 100644 index 0000000000..51df008762 --- /dev/null +++ b/demos/tweetstore/rhcloud-tweetstore/src/test/java/org/jclouds/demo/tweetstore/functions/ServiceToStoredTweetStatusesTest.java @@ -0,0 +1,74 @@ +/** + * 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.tweetstore.functions; + +import static org.testng.Assert.assertEquals; + +import java.io.IOException; +import java.util.Map; +import java.util.concurrent.ExecutionException; + +import org.jclouds.blobstore.BlobStoreContext; +import org.jclouds.blobstore.BlobStoreContextFactory; +import org.jclouds.blobstore.domain.Blob; +import org.jclouds.demo.tweetstore.domain.StoredTweetStatus; +import org.jclouds.demo.tweetstore.reference.TweetStoreConstants; +import org.testng.annotations.Test; +import org.testng.collections.Maps; + +import com.google.common.collect.Iterables; + +/** + * Tests behavior of {@code ServiceToStoredTweetStatuses} + * + * @author Adrian Cole + */ +@Test(groups = "unit") +public class ServiceToStoredTweetStatusesTest { + + Map createServices(String container) throws InterruptedException, + ExecutionException { + Map services = Maps.newHashMap(); + for (String name : new String[] { "1", "2" }) { + BlobStoreContext context = new BlobStoreContextFactory().createContext("transient", + "dummy", "dummy"); + context.getAsyncBlobStore().createContainerInLocation(null, container).get(); + Blob blob = context.getAsyncBlobStore().blobBuilder("1").build(); + blob.getMetadata().getUserMetadata().put(TweetStoreConstants.SENDER_NAME, "frank"); + blob.setPayload("I love beans!"); + context.getAsyncBlobStore().putBlob(container, blob).get(); + services.put(name, context); + } + return services; + } + + public void testStoreTweets() throws IOException, InterruptedException, ExecutionException { + String container = "container"; + Map contexts = createServices(container); + + ServiceToStoredTweetStatuses function = new ServiceToStoredTweetStatuses(contexts, container); + + assertEquals(Iterables.getLast(function.apply("1")), new StoredTweetStatus("1", "localhost", + container, "1", "frank", "I love beans!", null)); + + assertEquals(Iterables.getLast(function.apply("2")), new StoredTweetStatus("2", "localhost", + container, "1", "frank", "I love beans!", null)); + + } +} diff --git a/demos/tweetstore/rhcloud-tweetstore/src/test/java/org/jclouds/demo/tweetstore/integration/RhcloudServer.java b/demos/tweetstore/rhcloud-tweetstore/src/test/java/org/jclouds/demo/tweetstore/integration/RhcloudServer.java new file mode 100644 index 0000000000..ce4096f669 --- /dev/null +++ b/demos/tweetstore/rhcloud-tweetstore/src/test/java/org/jclouds/demo/tweetstore/integration/RhcloudServer.java @@ -0,0 +1,109 @@ +/** + * 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.tweetstore.integration; + +import static com.google.common.collect.Iterables.find; +import static com.google.common.io.Closeables.closeQuietly; +import static java.lang.String.format; +import static org.jclouds.demo.tweetstore.integration.util.Zips.zipFile; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.Properties; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; + +import org.jboss.as.controller.client.helpers.standalone.DeploymentAction; +import org.jboss.as.controller.client.helpers.standalone.DeploymentPlan; +import org.jboss.as.controller.client.helpers.standalone.ServerDeploymentActionResult; +import org.jboss.as.controller.client.helpers.standalone.ServerDeploymentManager; +import org.jboss.as.controller.client.helpers.standalone.ServerDeploymentPlanResult; +import org.jboss.as.embedded.EmbeddedServerFactory2; +import org.jboss.as.embedded.ServerStartException; +import org.jboss.as.embedded.StandaloneServer; + +import com.google.common.base.Predicate; +import com.google.common.io.Files; + +/** + * Basic functionality to start a local JBoss AS 7 instance. + * + * @author Andrew Phillips + */ +public class RhcloudServer { + private static final byte[] CONTEXT_ROOT_XML_BYTES = + "/".getBytes(); + + protected StandaloneServer server; + protected ServerDeploymentManager manager; + + public void writePropertiesAndStartServer(String warfile, + String serverHome, Properties props) throws IOException, + ServerStartException, InterruptedException, ExecutionException { + String propsfile = String.format("%1$s/WEB-INF/jclouds.properties", warfile); + System.err.println("file: " + propsfile); + storeProperties(propsfile, props); + assert new File(propsfile).exists(); + + // in OpenShift, TweetStore runs at the server root + String ctxrootfile = String.format("%1$s/WEB-INF/jboss-web.xml", warfile); + System.err.println("file: " + ctxrootfile); + Files.write(CONTEXT_ROOT_XML_BYTES, new File(ctxrootfile)); + assert new File(ctxrootfile).exists(); + + server = EmbeddedServerFactory2.create(new File(serverHome), System.getProperties(), System.getenv()); + server.start(); + TimeUnit.SECONDS.sleep(30); + manager = ServerDeploymentManager.Factory.create(server.getModelControllerClient()); + ServerDeploymentActionResult deploymentResult = deploy(warfile); + System.err.println("deployment result: " + deploymentResult.getResult()); + } + + private static void storeProperties(String filename, Properties props) + throws IOException { + FileOutputStream targetFile = new FileOutputStream(filename); + try { + props.store(targetFile, "test"); + } finally { + closeQuietly(targetFile); + } + } + + protected ServerDeploymentActionResult deploy(String explodedWar) + throws IOException, InterruptedException, ExecutionException { + File war = zipFile(explodedWar, format("%s-rhcloud.war", explodedWar), true); + final String deploymentName = war.getName(); + + DeploymentPlan plan = + manager.newDeploymentPlan().add(deploymentName, war).andDeploy().build(); + ServerDeploymentPlanResult deploymentResult = manager.execute(plan).get(); + return deploymentResult.getDeploymentActionResult(find( + plan.getDeploymentActions(), new Predicate() { + @Override + public boolean apply(DeploymentAction input) { + return input.getDeploymentUnitUniqueName().equals(deploymentName); + } + }).getId()); + } + + public void stop() throws Exception { + server.stop(); + } +} \ No newline at end of file diff --git a/demos/tweetstore/rhcloud-tweetstore/src/test/java/org/jclouds/demo/tweetstore/integration/TweetStoreLiveTest.java b/demos/tweetstore/rhcloud-tweetstore/src/test/java/org/jclouds/demo/tweetstore/integration/TweetStoreLiveTest.java new file mode 100644 index 0000000000..aa0a6833de --- /dev/null +++ b/demos/tweetstore/rhcloud-tweetstore/src/test/java/org/jclouds/demo/tweetstore/integration/TweetStoreLiveTest.java @@ -0,0 +1,231 @@ +/** + * 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.tweetstore.integration; + +import static com.google.common.base.Preconditions.checkNotNull; +import static org.jclouds.demo.paas.RunnableHttpRequest.PLATFORM_REQUEST_ORIGINATOR_HEADER; +import static org.jclouds.demo.tweetstore.reference.TweetStoreConstants.PROPERTY_TWEETSTORE_BLOBSTORES; +import static org.jclouds.demo.tweetstore.reference.TweetStoreConstants.PROPERTY_TWEETSTORE_CONTAINER; +import static org.jclouds.demo.tweetstore.reference.TwitterConstants.PROPERTY_TWITTER_ACCESSTOKEN; +import static org.jclouds.demo.tweetstore.reference.TwitterConstants.PROPERTY_TWITTER_ACCESSTOKEN_SECRET; +import static org.jclouds.demo.tweetstore.reference.TwitterConstants.PROPERTY_TWITTER_CONSUMER_KEY; +import static org.jclouds.demo.tweetstore.reference.TwitterConstants.PROPERTY_TWITTER_CONSUMER_SECRET; + +import java.io.IOException; +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Properties; +import java.util.Set; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeoutException; + +import org.jclouds.blobstore.BlobStoreContext; +import org.jclouds.blobstore.BlobStoreContextFactory; +import org.jclouds.demo.tweetstore.controller.StoreTweetsController; +import org.jclouds.logging.log4j.config.Log4JLoggingModule; +import org.jclouds.rest.AuthorizationException; +import org.jclouds.util.Strings2; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Parameters; +import org.testng.annotations.Test; + +import twitter4j.ResponseList; +import twitter4j.Status; +import twitter4j.Twitter; +import twitter4j.TwitterException; +import twitter4j.TwitterFactory; +import twitter4j.conf.Configuration; +import twitter4j.conf.ConfigurationBuilder; + +import com.google.common.base.Splitter; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Maps; +import com.google.inject.Module; + +/** + * Starts up a JBoss AS 7 server (simulating OpenShift Express) and deploys + * an application which tests accesses twitter and blobstores. + * + * @author Andrew Phillips + */ +@Test(groups = "live", singleThreaded = true) +public class TweetStoreLiveTest { + + RhcloudServer server; + private URL url; + private Map contexts; + private String container; + private static final Iterable blobstores = + Splitter.on(',').split(getRequiredSystemProperty(PROPERTY_TWEETSTORE_BLOBSTORES)); + private static final Properties props = new Properties(); + + @BeforeTest + void clearAndCreateContainers() throws InterruptedException, ExecutionException, TimeoutException, IOException, + TwitterException { + container = getRequiredSystemProperty(PROPERTY_TWEETSTORE_CONTAINER); + + props.setProperty(PROPERTY_TWEETSTORE_CONTAINER, container); + + // put all identity/credential pairs into the client + addCredentialsForBlobStores(props); + + // example of an ad-hoc client configuration + addConfigurationForTwitter(props); + + final BlobStoreContextFactory factory = new BlobStoreContextFactory(); + // for testing, capture logs. + final Set wiring = ImmutableSet. of(new Log4JLoggingModule()); + this.contexts = Maps.newConcurrentMap(); + + for (String provider : blobstores) { + contexts.put(provider, factory.createContext(provider, wiring, props)); + } + + Configuration conf = new ConfigurationBuilder() + .setOAuthConsumerKey(props.getProperty(PROPERTY_TWITTER_CONSUMER_KEY)) + .setOAuthConsumerSecret(props.getProperty(PROPERTY_TWITTER_CONSUMER_SECRET)) + .setOAuthAccessToken(props.getProperty(PROPERTY_TWITTER_ACCESSTOKEN)) + .setOAuthAccessTokenSecret(props.getProperty(PROPERTY_TWITTER_ACCESSTOKEN_SECRET)) + .build(); + Twitter client = new TwitterFactory(conf).getInstance(); + StoreTweetsController controller = new StoreTweetsController(contexts, container, client); + + ResponseList statuses = client.getMentions(); + + boolean deleted = false; + for (BlobStoreContext context : contexts.values()) { + try { + if (context.getBlobStore().containerExists(container)) { + System.err.printf("deleting container %s at %s%n", container, context.getProviderSpecificContext() + .getEndpoint()); + context.getBlobStore().deleteContainer(container); + deleted = true; + } + } catch (AuthorizationException e) { + throw new AuthorizationException("for context: " + context, e); + } + } + if (deleted) { + System.err.println("sleeping 60 seconds to allow containers to clear"); + Thread.sleep(60000); + } + for (BlobStoreContext context : contexts.values()) { + System.err.printf("creating container %s at %s%n", container, context.getProviderSpecificContext() + .getEndpoint()); + context.getBlobStore().createContainerInLocation(null, container); + } + + if (deleted) { + System.err.println("sleeping 5 seconds to allow containers to create"); + Thread.sleep(5000); + } + + for (Entry entry : contexts.entrySet()) { + System.err.printf("filling container %s at %s%n", container, entry.getKey()); + controller.addMyTweets(entry.getKey(), statuses); + } + } + + private static String getRequiredSystemProperty(String key) { + return checkNotNull(System.getProperty(key), key); + } + + private void addConfigurationForTwitter(Properties props) { + props.setProperty(PROPERTY_TWITTER_CONSUMER_KEY, + getRequiredSystemProperty("test." + PROPERTY_TWITTER_CONSUMER_KEY)); + props.setProperty(PROPERTY_TWITTER_CONSUMER_SECRET, + getRequiredSystemProperty("test." + PROPERTY_TWITTER_CONSUMER_SECRET)); + props.setProperty(PROPERTY_TWITTER_ACCESSTOKEN, + getRequiredSystemProperty("test." + PROPERTY_TWITTER_ACCESSTOKEN)); + props.setProperty(PROPERTY_TWITTER_ACCESSTOKEN_SECRET, + getRequiredSystemProperty("test." + PROPERTY_TWITTER_ACCESSTOKEN_SECRET)); + } + + private void addCredentialsForBlobStores(Properties props) { + for (String provider : blobstores) { + props.setProperty(provider + ".identity", + getRequiredSystemProperty("test." + provider + ".identity")); + props.setProperty(provider + ".credential", + getRequiredSystemProperty("test." + provider + ".credential")); + } + } + + @BeforeTest(dependsOnMethods = "clearAndCreateContainers") + @Parameters({ "warfile", "rhcloud.jboss.address", "rhcloud.jboss.port", "rhcloud.jboss.home" }) + public void startDevAppServer(final String warfile, final String address, final String port, + String serverHome) throws Exception { + url = new URL(String.format("http://%s:%s", address, port)); + + server = new RhcloudServer(); + server.writePropertiesAndStartServer(warfile, serverHome, props); + } + + @Test + public void shouldPass() throws InterruptedException, IOException { + InputStream i = url.openStream(); + String string = Strings2.toStringAndClose(i); + assert string.indexOf("Welcome") >= 0 : string; + } + + @Test(dependsOnMethods = "shouldPass", expectedExceptions = IOException.class) + public void shouldFail() throws InterruptedException, IOException { + new URL(url, "/store/do").openStream(); + } + + @Test(dependsOnMethods = "shouldFail") + public void testPrimeContainers() throws IOException, InterruptedException { + URL gurl = new URL(url, "/store/do"); + + for (String context : blobstores) { + System.out.println("storing at context: " + context); + HttpURLConnection connection = (HttpURLConnection) gurl.openConnection(); + connection.addRequestProperty(PLATFORM_REQUEST_ORIGINATOR_HEADER, "taskqueue-twitter"); + connection.addRequestProperty("context", context); + InputStream i = connection.getInputStream(); + String string = Strings2.toStringAndClose(i); + assert string.indexOf("Done!") >= 0 : string; + connection.disconnect(); + } + + System.err.println("sleeping 20 seconds to allow for eventual consistency delay"); + Thread.sleep(20000); + for (BlobStoreContext context : contexts.values()) { + assert context.createInputStreamMap(container).size() > 0 : context.getProviderSpecificContext().getEndpoint(); + } + } + + @Test(invocationCount = 5, dependsOnMethods = "testPrimeContainers") + public void testSerial() throws InterruptedException, IOException { + URL gurl = new URL(url, "/tweets/get"); + InputStream i = gurl.openStream(); + String string = Strings2.toStringAndClose(i); + assert string.indexOf("Tweets in Clouds") >= 0 : string; + } + + @Test(invocationCount = 10, dependsOnMethods = "testPrimeContainers", threadPoolSize = 3) + public void testParallel() throws InterruptedException, IOException { + URL gurl = new URL(url, "/tweets/get"); + InputStream i = gurl.openStream(); + String string = Strings2.toStringAndClose(i); + assert string.indexOf("Tweets in Clouds") >= 0 : string; + } +} diff --git a/demos/tweetstore/rhcloud-tweetstore/src/test/java/org/jclouds/demo/tweetstore/integration/util/ObjectFields.java b/demos/tweetstore/rhcloud-tweetstore/src/test/java/org/jclouds/demo/tweetstore/integration/util/ObjectFields.java new file mode 100644 index 0000000000..8c4edd5ea9 --- /dev/null +++ b/demos/tweetstore/rhcloud-tweetstore/src/test/java/org/jclouds/demo/tweetstore/integration/util/ObjectFields.java @@ -0,0 +1,43 @@ +/** + * 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.tweetstore.integration.util; + +import java.lang.reflect.Field; + +public class ObjectFields { + + private static Field getAccessibleField(String name, Class declaringClass) throws SecurityException, NoSuchFieldException { + Field field = declaringClass.getDeclaredField(name); + field.setAccessible(true); + return field; + } + + public static void set(String fieldName, Object target, Object value) { + set(fieldName, target, value, target.getClass()); + } + + public static void set(String fieldName, Object target, Object value, + Class fieldDeclaringClass) { + try { + getAccessibleField(fieldName, fieldDeclaringClass).set(target, value); + } catch (Exception exception) { + throw new IllegalArgumentException(exception); + } + } +} diff --git a/demos/tweetstore/rhcloud-tweetstore/src/test/java/org/jclouds/demo/tweetstore/integration/util/Zips.java b/demos/tweetstore/rhcloud-tweetstore/src/test/java/org/jclouds/demo/tweetstore/integration/util/Zips.java new file mode 100644 index 0000000000..a9c201dca9 --- /dev/null +++ b/demos/tweetstore/rhcloud-tweetstore/src/test/java/org/jclouds/demo/tweetstore/integration/util/Zips.java @@ -0,0 +1,73 @@ +/** + * 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.tweetstore.integration.util; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; + +public class Zips { + private static final int DEFAULT_BUFFER_SIZE = 1024 * 4; + + public static File zipFile(String fileToZip, String zipFile, + boolean excludeToplevelFolder) throws IOException { + ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream(zipFile)); + try { + File srcFile = new File(fileToZip); + if (excludeToplevelFolder && srcFile.isDirectory()) { + for (String fileName : srcFile.list()) { + addToZip("", fileToZip + "/" + fileName, zipOut); + } + } else { + addToZip("", fileToZip, zipOut); + } + zipOut.flush(); + } finally { + zipOut.close(); + } + return new File(zipFile); + } + + private static void addToZip(String path, String srcFile, + ZipOutputStream zipOut) throws IOException { + File file = new File(srcFile); + String filePath = ("".equals(path) ? file.getName() + : path + "/" + file.getName()); + if (file.isDirectory()) { + for (String fileName : file.list()) { + addToZip(filePath, srcFile + "/" + fileName, zipOut); + } + } else { + zipOut.putNextEntry(new ZipEntry(filePath)); + FileInputStream in = new FileInputStream(srcFile); + try { + byte[] buffer = new byte[DEFAULT_BUFFER_SIZE]; + int len; + while ((len = in.read(buffer)) != -1) { + zipOut.write(buffer, 0, len); + } + } finally { + in.close(); + } + } + } +} \ No newline at end of file diff --git a/demos/tweetstore/rhcloud-tweetstore/src/test/resources/jbossas7/configuration/standalone.xml b/demos/tweetstore/rhcloud-tweetstore/src/test/resources/jbossas7/configuration/standalone.xml new file mode 100644 index 0000000000..8b2f988c68 --- /dev/null +++ b/demos/tweetstore/rhcloud-tweetstore/src/test/resources/jbossas7/configuration/standalone.xml @@ -0,0 +1,208 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + jdbc:h2:${jboss.server.data.dir}/test;DB_CLOSE_DELAY=-1 + h2 + + + sa + sa + + + + + + + jdbc:mysql://${OPENSHIFT_DB_HOST}:${OPENSHIFT_DB_PORT}/${OPENSHIFT_APP_NAME} + mysql + + ${OPENSHIFT_DB_USERNAME} + ${OPENSHIFT_DB_PASSWORD} + + + + + org.h2.jdbcx.JdbcDataSource + + + com.mysql.jdbc.jdbc2.optional.MysqlXADataSource + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/demos/tweetstore/rhcloud-tweetstore/src/test/resources/log4j.xml b/demos/tweetstore/rhcloud-tweetstore/src/test/resources/log4j.xml new file mode 100644 index 0000000000..2e5d01fb9e --- /dev/null +++ b/demos/tweetstore/rhcloud-tweetstore/src/test/resources/log4j.xml @@ -0,0 +1,95 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/demos/tweetstore/runatcloud-tweetstore/src/test/java/org/jclouds/demo/tweetstore/integration/RunAtCloudServer.java b/demos/tweetstore/runatcloud-tweetstore/src/test/java/org/jclouds/demo/tweetstore/integration/RunAtCloudServer.java index ee3374c98e..0272aea3b1 100644 --- a/demos/tweetstore/runatcloud-tweetstore/src/test/java/org/jclouds/demo/tweetstore/integration/RunAtCloudServer.java +++ b/demos/tweetstore/runatcloud-tweetstore/src/test/java/org/jclouds/demo/tweetstore/integration/RunAtCloudServer.java @@ -18,6 +18,8 @@ */ package org.jclouds.demo.tweetstore.integration; +import static com.google.common.io.Closeables.closeQuietly; + import java.io.File; import java.io.FileOutputStream; import java.io.IOException; @@ -29,9 +31,9 @@ import javax.servlet.ServletException; import org.apache.commons.cli.ParseException; /** - * Basic functionality to start a local google app engine instance. + * Basic functionality to start a local RUN@cloud instance. * - * @author Adrian Cole + * @author Andrew Phillips */ public class RunAtCloudServer { protected StaxSdkAppServer2 server; @@ -42,7 +44,7 @@ public class RunAtCloudServer { 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(); server = StaxSdkAppServer2.createServer(new String[] { "-web", warfile, "-port", port, "-env", environments, "-dir", serverBaseDirectory }, new String[0], Thread.currentThread().getContextClassLoader()); @@ -50,6 +52,15 @@ public class RunAtCloudServer { 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 { server.stop(); } diff --git a/demos/tweetstore/runatcloud-tweetstore/src/test/java/org/jclouds/demo/tweetstore/integration/TweetStoreLiveTest.java b/demos/tweetstore/runatcloud-tweetstore/src/test/java/org/jclouds/demo/tweetstore/integration/TweetStoreLiveTest.java index 8f4aaf9a2c..f972aace6e 100644 --- a/demos/tweetstore/runatcloud-tweetstore/src/test/java/org/jclouds/demo/tweetstore/integration/TweetStoreLiveTest.java +++ b/demos/tweetstore/runatcloud-tweetstore/src/test/java/org/jclouds/demo/tweetstore/integration/TweetStoreLiveTest.java @@ -62,10 +62,10 @@ import com.google.common.collect.Maps; import com.google.inject.Module; /** - * Starts up the Google App Engine for Java Development environment and deploys an application which + * Starts up the RUN@cloud for Java Development environment and deploys an application which * tests accesses twitter and blobstores. * - * @author Adrian Cole + * @author Andrew Phillips */ @Test(groups = "live", singleThreaded = true) public class TweetStoreLiveTest { diff --git a/drivers/apachehc/pom.xml b/drivers/apachehc/pom.xml index b0c58f35a6..e79b28b19e 100644 --- a/drivers/apachehc/pom.xml +++ b/drivers/apachehc/pom.xml @@ -78,8 +78,8 @@ ${project.artifactId} - org.jclouds.http.apachehc.*;version="${project.version}" - org.jclouds.*;version="${project.version}",* + org.jclouds.http.apachehc*;version="${project.version}" + org.jclouds*;version="${project.version}",* diff --git a/drivers/bouncycastle/pom.xml b/drivers/bouncycastle/pom.xml index 0d5d0bd398..b679b0dc5e 100644 --- a/drivers/bouncycastle/pom.xml +++ b/drivers/bouncycastle/pom.xml @@ -73,8 +73,8 @@ ${project.artifactId} - org.jclouds.encryption.bouncycastle.*;version="${project.version}" - org.jclouds.*;version="${project.version}",* + org.jclouds.encryption.bouncycastle*;version="${project.version}" + org.jclouds*;version="${project.version}",* diff --git a/drivers/enterprise/pom.xml b/drivers/enterprise/pom.xml index 95348ea328..c878f04021 100644 --- a/drivers/enterprise/pom.xml +++ b/drivers/enterprise/pom.xml @@ -87,8 +87,8 @@ ${project.artifactId} - org.jclouds.enterprise.*;version="${project.version}" - org.jclouds.*;version="${project.version}",* + org.jclouds.enterprise*;version="${project.version}" + org.jclouds*;version="${project.version}",* diff --git a/drivers/gae/pom.xml b/drivers/gae/pom.xml index c436eaf5f2..cc6e98b678 100644 --- a/drivers/gae/pom.xml +++ b/drivers/gae/pom.xml @@ -103,8 +103,8 @@ ${project.artifactId} - org.jclouds.gae.*;version="${project.version}" - org.jclouds.*;version="${project.version}",* + org.jclouds.gae*;version="${project.version}" + org.jclouds*;version="${project.version}",* diff --git a/drivers/joda/pom.xml b/drivers/joda/pom.xml index 062800f4fd..79035012f6 100644 --- a/drivers/joda/pom.xml +++ b/drivers/joda/pom.xml @@ -73,8 +73,8 @@ ${project.artifactId} - org.jclouds.date.joda.*;version="${project.version}" - org.jclouds.*;version="${project.version}",* + org.jclouds.date.joda*;version="${project.version}" + org.jclouds*;version="${project.version}",* diff --git a/drivers/jsch/pom.xml b/drivers/jsch/pom.xml index e52b691853..16d4b46834 100644 --- a/drivers/jsch/pom.xml +++ b/drivers/jsch/pom.xml @@ -101,8 +101,8 @@ ${project.artifactId} - org.jclouds.ssh.jsch.*;version="${project.version}" - org.jclouds.*;version="${project.version}",* + org.jclouds.ssh.jsch*;version="${project.version}" + org.jclouds*;version="${project.version}",* diff --git a/drivers/log4j/pom.xml b/drivers/log4j/pom.xml index db11f6a0ee..d873e9ea06 100644 --- a/drivers/log4j/pom.xml +++ b/drivers/log4j/pom.xml @@ -73,8 +73,8 @@ ${project.artifactId} - org.jclouds.logging.log4j.*;version="${project.version}" - org.jclouds.*;version="${project.version}",* + org.jclouds.logging.log4j*;version="${project.version}" + org.jclouds*;version="${project.version}",* diff --git a/drivers/netty/pom.xml b/drivers/netty/pom.xml index 05d9d0a6fa..819bcd0359 100644 --- a/drivers/netty/pom.xml +++ b/drivers/netty/pom.xml @@ -86,8 +86,8 @@ ${project.artifactId} - org.jclouds.netty.*;version="${project.version}" - org.jclouds.*;version="${project.version}",* + org.jclouds.netty*;version="${project.version}" + org.jclouds*;version="${project.version}",* diff --git a/drivers/slf4j/pom.xml b/drivers/slf4j/pom.xml index 47587a27e1..43bbc6ae77 100644 --- a/drivers/slf4j/pom.xml +++ b/drivers/slf4j/pom.xml @@ -73,8 +73,8 @@ ${project.artifactId} - org.jclouds.logging.slf4j.*;version="${project.version}" - org.jclouds.*;version="${project.version}",* + org.jclouds.logging.slf4j*;version="${project.version}" + org.jclouds*;version="${project.version}",* diff --git a/drivers/sshj/pom.xml b/drivers/sshj/pom.xml index 9faa32790b..5c4112b500 100644 --- a/drivers/sshj/pom.xml +++ b/drivers/sshj/pom.xml @@ -106,8 +106,8 @@ ${project.artifactId} - org.jclouds.sshj.*;version="${project.version}" - org.jclouds.*;version="${project.version}",* + org.jclouds.sshj*;version="${project.version}" + org.jclouds*;version="${project.version}",* diff --git a/sandbox-providers/glesys/pom.xml b/labs/glesys/pom.xml similarity index 88% rename from sandbox-providers/glesys/pom.xml rename to labs/glesys/pom.xml index 9943a4ed7f..cbf2ab5180 100644 --- a/sandbox-providers/glesys/pom.xml +++ b/labs/glesys/pom.xml @@ -27,26 +27,12 @@ 1.5.0-SNAPSHOT ../../project/pom.xml - org.jclouds.provider + org.jclouds.labs glesys jclouds GleSYS core jclouds components to access GleSYS bundle - - - - jclouds-sona-snapshots-nexus - https://oss.sonatype.org/content/repositories/snapshots - - false - - - true - - - - https://api.glesys.com 1 @@ -57,6 +43,7 @@ + org.jclouds @@ -133,8 +120,8 @@ ${project.artifactId} - org.jclouds.glesys.*;version="${project.version}" - org.jclouds.*;version="${project.version}",* + org.jclouds.glesys*;version="${project.version}" + org.jclouds*;version="${project.version}",* diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/GleSYSAsyncClient.java b/labs/glesys/src/main/java/org/jclouds/glesys/GleSYSAsyncClient.java similarity index 100% rename from sandbox-providers/glesys/src/main/java/org/jclouds/glesys/GleSYSAsyncClient.java rename to labs/glesys/src/main/java/org/jclouds/glesys/GleSYSAsyncClient.java diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/GleSYSClient.java b/labs/glesys/src/main/java/org/jclouds/glesys/GleSYSClient.java similarity index 100% rename from sandbox-providers/glesys/src/main/java/org/jclouds/glesys/GleSYSClient.java rename to labs/glesys/src/main/java/org/jclouds/glesys/GleSYSClient.java diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/GleSYSContextBuilder.java b/labs/glesys/src/main/java/org/jclouds/glesys/GleSYSContextBuilder.java similarity index 100% rename from sandbox-providers/glesys/src/main/java/org/jclouds/glesys/GleSYSContextBuilder.java rename to labs/glesys/src/main/java/org/jclouds/glesys/GleSYSContextBuilder.java diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/GleSYSPropertiesBuilder.java b/labs/glesys/src/main/java/org/jclouds/glesys/GleSYSPropertiesBuilder.java similarity index 95% rename from sandbox-providers/glesys/src/main/java/org/jclouds/glesys/GleSYSPropertiesBuilder.java rename to labs/glesys/src/main/java/org/jclouds/glesys/GleSYSPropertiesBuilder.java index dba345ad19..bae37e4008 100644 --- a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/GleSYSPropertiesBuilder.java +++ b/labs/glesys/src/main/java/org/jclouds/glesys/GleSYSPropertiesBuilder.java @@ -48,6 +48,8 @@ public class GleSYSPropertiesBuilder extends PropertiesBuilder { properties.setProperty(PROPERTY_ZONE + ".Falkenberg." + ISO3166_CODES, "SE-N"); properties.setProperty(PROPERTY_ZONE + ".New York City." + ISO3166_CODES, "US-NY"); properties.setProperty(PROPERTY_ZONE + ".Stockholm." + ISO3166_CODES, "SE-AB"); + properties.setProperty("jclouds.ssh.max-retries", "5"); + properties.setProperty("jclouds.ssh.retry-auth", "true"); properties.setProperty(PROPERTY_GLESYS_DEFAULT_DC, "Falkenberg"); return properties; } diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/GleSYSProviderMetadata.java b/labs/glesys/src/main/java/org/jclouds/glesys/GleSYSProviderMetadata.java similarity index 100% rename from sandbox-providers/glesys/src/main/java/org/jclouds/glesys/GleSYSProviderMetadata.java rename to labs/glesys/src/main/java/org/jclouds/glesys/GleSYSProviderMetadata.java diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/compute/GleSYSComputeServiceAdapter.java b/labs/glesys/src/main/java/org/jclouds/glesys/compute/GleSYSComputeServiceAdapter.java similarity index 66% rename from sandbox-providers/glesys/src/main/java/org/jclouds/glesys/compute/GleSYSComputeServiceAdapter.java rename to labs/glesys/src/main/java/org/jclouds/glesys/compute/GleSYSComputeServiceAdapter.java index dec819f0c6..d2e2feb677 100644 --- a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/compute/GleSYSComputeServiceAdapter.java +++ b/labs/glesys/src/main/java/org/jclouds/glesys/compute/GleSYSComputeServiceAdapter.java @@ -20,9 +20,12 @@ package org.jclouds.glesys.compute; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; +import static org.jclouds.concurrent.FutureIterables.transformParallel; -import java.util.Set; import java.util.Map.Entry; +import java.util.Set; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Future; import javax.annotation.Resource; import javax.inject.Inject; @@ -30,6 +33,7 @@ import javax.inject.Named; import javax.inject.Provider; import javax.inject.Singleton; +import org.jclouds.Constants; import org.jclouds.collect.FindResourceInSet; import org.jclouds.collect.Memoized; import org.jclouds.compute.ComputeService; @@ -42,28 +46,33 @@ import org.jclouds.compute.domain.Volume; import org.jclouds.compute.domain.internal.VolumeImpl; import org.jclouds.compute.predicates.ImagePredicates; import org.jclouds.compute.reference.ComputeServiceConstants; +import org.jclouds.compute.reference.ComputeServiceConstants.Timeouts; import org.jclouds.domain.Location; import org.jclouds.domain.LoginCredentials; +import org.jclouds.glesys.GleSYSAsyncClient; import org.jclouds.glesys.GleSYSClient; import org.jclouds.glesys.compute.options.GleSYSTemplateOptions; import org.jclouds.glesys.domain.AllowedArgumentsForCreateServer; import org.jclouds.glesys.domain.OSTemplate; +import org.jclouds.glesys.domain.Server; import org.jclouds.glesys.domain.ServerDetails; import org.jclouds.glesys.domain.ServerSpec; import org.jclouds.glesys.options.CreateServerOptions; import org.jclouds.glesys.options.DestroyServerOptions; import org.jclouds.location.predicates.LocationPredicates; import org.jclouds.logging.Logger; +import org.jclouds.predicates.RetryablePredicate; import com.google.common.base.Function; +import com.google.common.base.Predicate; import com.google.common.base.Supplier; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; /** - * defines the connection between the {@link GleSYSClient} implementation and the jclouds - * {@link ComputeService} + * defines the connection between the {@link GleSYSClient} implementation and + * the jclouds {@link ComputeService} * */ @Singleton @@ -74,32 +83,39 @@ public class GleSYSComputeServiceAdapter implements ComputeServiceAdapter> locations; private final Provider passwordProvider; @Inject - public GleSYSComputeServiceAdapter(GleSYSClient client, @Memoized Supplier> locations, - @Named("PASSWORD") Provider passwordProvider) { + public GleSYSComputeServiceAdapter(GleSYSClient client, GleSYSAsyncClient aclient, + @Named(Constants.PROPERTY_USER_THREADS) ExecutorService userThreads, Timeouts timeouts, + @Memoized Supplier> locations, @Named("PASSWORD") Provider passwordProvider) { this.client = checkNotNull(client, "client"); + this.aclient = checkNotNull(aclient, "aclient"); + this.userThreads = checkNotNull(userThreads, "userThreads"); + this.timeouts = checkNotNull(timeouts, "timeouts"); this.locations = checkNotNull(locations, "locations"); this.passwordProvider = checkNotNull(passwordProvider, "passwordProvider"); } @Override public NodeAndInitialCredentials createNodeWithGroupEncodedIntoName(String group, String name, - Template template) { + Template template) { checkNotNull(template, "template was null"); checkNotNull(template.getOptions(), "template options was null"); checkArgument(template.getOptions().getClass().isAssignableFrom(GleSYSTemplateOptions.class), - "options class %s should have been assignable from GleSYSTemplateOptions", template.getOptions() - .getClass()); + "options class %s should have been assignable from GleSYSTemplateOptions", template.getOptions().getClass()); GleSYSTemplateOptions templateOptions = template.getOptions().as(GleSYSTemplateOptions.class); CreateServerOptions createServerOptions = new CreateServerOptions(); createServerOptions.ip(templateOptions.getIp()); - createServerOptions.description(name); // TODO: add to templateOptions and set if present + createServerOptions.description(name); // TODO: add to templateOptions and + // set if present ServerSpec.Builder builder = ServerSpec.builder(); builder.datacenter(template.getLocation().getId()); @@ -111,15 +127,16 @@ public class GleSYSComputeServiceAdapter implements ComputeServiceAdapter> creating new Server spec(%s) name(%s) options(%s)", spec, name, createServerOptions); ServerDetails result = client.getServerClient().createServerWithHostnameAndRootPassword(spec, name, password, - createServerOptions); - logger.trace("<< ServerDetails(%s)", result.getId()); + createServerOptions); + logger.trace("<< server(%s)", result.getId()); return new NodeAndInitialCredentials(result, result.getId() + "", LoginCredentials.builder() - .password(password).build()); + .password(password).build()); } @Singleton @@ -145,26 +162,28 @@ public class GleSYSComputeServiceAdapter implements ComputeServiceAdapter images = listImages(); for (Entry platformToArgs : client.getServerClient() - .getAllowedArgumentsForCreateServerByPlatform().entrySet()) + .getAllowedArgumentsForCreateServerByPlatform().entrySet()) for (String datacenter : platformToArgs.getValue().getDataCenters()) for (int diskSizeGB : platformToArgs.getValue().getDiskSizesInGB()) for (int cpuCores : platformToArgs.getValue().getCpuCoreOptions()) for (int memorySizeMB : platformToArgs.getValue().getMemorySizesInMB()) { ImmutableSet.Builder templatesSupportedBuilder = ImmutableSet. builder(); for (OSTemplate template : images) { - if (diskSizeGB >= template.getMinDiskSize() && memorySizeMB >= template.getMinMemSize()) + if (template.getPlatform().equals(platformToArgs.getKey()) + && diskSizeGB >= template.getMinDiskSize() && memorySizeMB >= template.getMinMemSize()) templatesSupportedBuilder.add(template.getName()); } ImmutableSet templatesSupported = templatesSupportedBuilder.build(); if (templatesSupported.size() > 0) - hardwareToReturn.add(new HardwareBuilder().ids( - String.format("datacenter(%s)platform(%s)cpuCores(%d)memorySizeMB(%d)diskSizeGB(%d)", - datacenter, platformToArgs.getKey(), cpuCores, memorySizeMB, diskSizeGB)).ram( - memorySizeMB).processors(ImmutableList.of(new Processor(cpuCores, 1.0))).volumes( - ImmutableList. of(new VolumeImpl((float) diskSizeGB, true, true))).hypervisor( - platformToArgs.getKey()).location( - Iterables.find(locationsSet, LocationPredicates.idEquals(datacenter))).supportsImage( - ImagePredicates.idIn(templatesSupported)).build()); + hardwareToReturn.add(new HardwareBuilder() + .ids(String.format( + "datacenter(%s)platform(%s)cpuCores(%d)memorySizeMB(%d)diskSizeGB(%d)", datacenter, + platformToArgs.getKey(), cpuCores, memorySizeMB, diskSizeGB)).ram(memorySizeMB) + .processors(ImmutableList.of(new Processor(cpuCores, 1.0))) + .volumes(ImmutableList. of(new VolumeImpl((float) diskSizeGB, true, true))) + .hypervisor(platformToArgs.getKey()) + .location(Iterables.find(locationsSet, LocationPredicates.idEquals(datacenter))) + .supportsImage(ImagePredicates.idIn(templatesSupported)).build()); } return hardwareToReturn.build(); @@ -177,21 +196,27 @@ public class GleSYSComputeServiceAdapter implements ComputeServiceAdapter listNodes() { - return ImmutableSet.of(); + return transformParallel(client.getServerClient().listServers(), new Function>() { + @Override + public Future apply(Server from) { + return aclient.getServerClient().getServerDetails(from.getId()); + } + + }, userThreads, null, logger, "server details"); } @Override public Set listLocations() { return ImmutableSet.copyOf(Iterables.concat(Iterables.transform(client.getServerClient() - .getAllowedArgumentsForCreateServerByPlatform().values(), - new Function>() { + .getAllowedArgumentsForCreateServerByPlatform().values(), + new Function>() { - @Override - public Set apply(AllowedArgumentsForCreateServer arg0) { - return arg0.getDataCenters(); - } + @Override + public Set apply(AllowedArgumentsForCreateServer arg0) { + return arg0.getDataCenters(); + } - }))); + }))); } @Override @@ -201,7 +226,19 @@ public class GleSYSComputeServiceAdapter implements ComputeServiceAdapter(new Predicate() { + + @Override + public boolean apply(String arg0) { + try { + client.getServerClient().destroyServer(arg0, DestroyServerOptions.Builder.discardIp()); + return true; + } catch (IllegalStateException e) { + return false; + } + } + + }, timeouts.nodeTerminated).apply(id); } @Override diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/compute/config/GleSYSComputeServiceContextModule.java b/labs/glesys/src/main/java/org/jclouds/glesys/compute/config/GleSYSComputeServiceContextModule.java similarity index 91% rename from sandbox-providers/glesys/src/main/java/org/jclouds/glesys/compute/config/GleSYSComputeServiceContextModule.java rename to labs/glesys/src/main/java/org/jclouds/glesys/compute/config/GleSYSComputeServiceContextModule.java index 4059b4cf9d..7affeedb3f 100644 --- a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/compute/config/GleSYSComputeServiceContextModule.java +++ b/labs/glesys/src/main/java/org/jclouds/glesys/compute/config/GleSYSComputeServiceContextModule.java @@ -18,9 +18,8 @@ */ package org.jclouds.glesys.compute.config; -import java.security.SecureRandom; +import java.util.UUID; -import javax.inject.Inject; import javax.inject.Named; import javax.inject.Provider; import javax.inject.Singleton; @@ -64,7 +63,7 @@ public class GleSYSComputeServiceContextModule super(GleSYSClient.class, GleSYSAsyncClient.class); } - @SuppressWarnings("unchecked") + @SuppressWarnings({ "unchecked", "rawtypes" }) @Override protected void configure() { super.configure(); @@ -89,22 +88,17 @@ public class GleSYSComputeServiceContextModule // 128MB is perhaps too little ram @Override protected TemplateBuilder provideTemplate(Injector injector, TemplateBuilder template) { - return template.minRam(512).osFamily(OsFamily.UBUNTU).osVersionMatches("1[10].[10][04]").os64Bit(true); + return template.minRam(512).osFamily(OsFamily.UBUNTU).hypervisorMatches("OpenVZ").osVersionMatches("1[10].[10][04]").os64Bit(true); } @Named("PASSWORD") @Singleton public static class PasswordProvider implements Provider { - private final SecureRandom random; - - @Inject - protected PasswordProvider() { - this.random = new SecureRandom(); - } @Override public String get() { - return random.nextLong() + ""; + return UUID.randomUUID().toString().replace("-",""); } + } } \ No newline at end of file diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/compute/functions/DatacenterToLocation.java b/labs/glesys/src/main/java/org/jclouds/glesys/compute/functions/DatacenterToLocation.java similarity index 100% rename from sandbox-providers/glesys/src/main/java/org/jclouds/glesys/compute/functions/DatacenterToLocation.java rename to labs/glesys/src/main/java/org/jclouds/glesys/compute/functions/DatacenterToLocation.java diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/compute/functions/FindLocationForServerSpec.java b/labs/glesys/src/main/java/org/jclouds/glesys/compute/functions/FindLocationForServerSpec.java similarity index 100% rename from sandbox-providers/glesys/src/main/java/org/jclouds/glesys/compute/functions/FindLocationForServerSpec.java rename to labs/glesys/src/main/java/org/jclouds/glesys/compute/functions/FindLocationForServerSpec.java diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/compute/functions/OSTemplateToImage.java b/labs/glesys/src/main/java/org/jclouds/glesys/compute/functions/OSTemplateToImage.java similarity index 100% rename from sandbox-providers/glesys/src/main/java/org/jclouds/glesys/compute/functions/OSTemplateToImage.java rename to labs/glesys/src/main/java/org/jclouds/glesys/compute/functions/OSTemplateToImage.java diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/compute/functions/ParseOsFamilyVersion64BitFromImageName.java b/labs/glesys/src/main/java/org/jclouds/glesys/compute/functions/ParseOsFamilyVersion64BitFromImageName.java similarity index 100% rename from sandbox-providers/glesys/src/main/java/org/jclouds/glesys/compute/functions/ParseOsFamilyVersion64BitFromImageName.java rename to labs/glesys/src/main/java/org/jclouds/glesys/compute/functions/ParseOsFamilyVersion64BitFromImageName.java diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/compute/functions/ServerDetailsToNodeMetadata.java b/labs/glesys/src/main/java/org/jclouds/glesys/compute/functions/ServerDetailsToNodeMetadata.java similarity index 81% rename from sandbox-providers/glesys/src/main/java/org/jclouds/glesys/compute/functions/ServerDetailsToNodeMetadata.java rename to labs/glesys/src/main/java/org/jclouds/glesys/compute/functions/ServerDetailsToNodeMetadata.java index 77b6a1ef3f..a52e052e9d 100644 --- a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/compute/functions/ServerDetailsToNodeMetadata.java +++ b/labs/glesys/src/main/java/org/jclouds/glesys/compute/functions/ServerDetailsToNodeMetadata.java @@ -43,10 +43,8 @@ import org.jclouds.compute.domain.Volume; import org.jclouds.compute.domain.internal.VolumeImpl; import org.jclouds.compute.reference.ComputeServiceConstants; import org.jclouds.domain.Location; -import org.jclouds.glesys.GleSYSClient; import org.jclouds.glesys.domain.Ip; import org.jclouds.glesys.domain.ServerDetails; -import org.jclouds.glesys.options.ServerStatusOptions; import org.jclouds.logging.Logger; import org.jclouds.util.InetAddresses2.IsPrivateIPAddress; @@ -68,12 +66,12 @@ public class ServerDetailsToNodeMetadata implements Function serverStateToNodeState = ImmutableMap - . builder().put(ServerDetails.State.STOPPED, NodeState.SUSPENDED).put( - ServerDetails.State.RUNNING, NodeState.RUNNING).put(ServerDetails.State.UNRECOGNIZED, - NodeState.UNRECOGNIZED).build(); + . builder().put(ServerDetails.State.STOPPED, NodeState.SUSPENDED) + .put(ServerDetails.State.LOCKED, NodeState.PENDING) + .put(ServerDetails.State.RUNNING, NodeState.RUNNING) + .put(ServerDetails.State.UNRECOGNIZED, NodeState.UNRECOGNIZED).build(); protected final Supplier> images; - protected final GleSYSClient client; protected final FindLocationForServerDetails findLocationForServerDetails; private static class FindImageForServer implements Predicate { @@ -90,9 +88,8 @@ public class ServerDetailsToNodeMetadata implements Function> images) { - this.client = checkNotNull(client, "client"); + ServerDetailsToNodeMetadata(FindLocationForServerDetails findLocationForServerDetails, + @Memoized Supplier> images) { this.findLocationForServerDetails = checkNotNull(findLocationForServerDetails, "findLocationForServerDetails"); this.images = checkNotNull(images, "images"); } @@ -105,15 +102,14 @@ public class ServerDetailsToNodeMetadata implements Function of(new VolumeImpl((float) from.getDiskSizeGB(), true, true))).hypervisor( - from.getPlatform()).build()); - builder.state(serverStateToNodeState.get(client.getServerClient().getServerStatus(from.getId(), - ServerStatusOptions.Builder.state()).getState())); + builder.hardware(new HardwareBuilder().ids(from.getId() + "").ram(from.getMemorySizeMB()) + .processors(ImmutableList.of(new Processor(from.getCpuCores(), 1.0))) + .volumes(ImmutableList. of(new VolumeImpl((float) from.getDiskSizeGB(), true, true))) + .hypervisor(from.getPlatform()).build()); + builder.state(serverStateToNodeState.get(from.getState())); Iterable addresses = Iterables.filter(Iterables.transform(from.getIps(), new Function() { @Override diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/compute/functions/ServerSpecToHardware.java b/labs/glesys/src/main/java/org/jclouds/glesys/compute/functions/ServerSpecToHardware.java similarity index 100% rename from sandbox-providers/glesys/src/main/java/org/jclouds/glesys/compute/functions/ServerSpecToHardware.java rename to labs/glesys/src/main/java/org/jclouds/glesys/compute/functions/ServerSpecToHardware.java diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/compute/options/GleSYSTemplateOptions.java b/labs/glesys/src/main/java/org/jclouds/glesys/compute/options/GleSYSTemplateOptions.java similarity index 100% rename from sandbox-providers/glesys/src/main/java/org/jclouds/glesys/compute/options/GleSYSTemplateOptions.java rename to labs/glesys/src/main/java/org/jclouds/glesys/compute/options/GleSYSTemplateOptions.java diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/config/GleSYSParserModule.java b/labs/glesys/src/main/java/org/jclouds/glesys/config/GleSYSParserModule.java similarity index 100% rename from sandbox-providers/glesys/src/main/java/org/jclouds/glesys/config/GleSYSParserModule.java rename to labs/glesys/src/main/java/org/jclouds/glesys/config/GleSYSParserModule.java diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/config/GleSYSRestClientModule.java b/labs/glesys/src/main/java/org/jclouds/glesys/config/GleSYSRestClientModule.java similarity index 100% rename from sandbox-providers/glesys/src/main/java/org/jclouds/glesys/config/GleSYSRestClientModule.java rename to labs/glesys/src/main/java/org/jclouds/glesys/config/GleSYSRestClientModule.java diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/AllowedArgumentsForCreateServer.java b/labs/glesys/src/main/java/org/jclouds/glesys/domain/AllowedArgumentsForCreateServer.java similarity index 100% rename from sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/AllowedArgumentsForCreateServer.java rename to labs/glesys/src/main/java/org/jclouds/glesys/domain/AllowedArgumentsForCreateServer.java diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/Archive.java b/labs/glesys/src/main/java/org/jclouds/glesys/domain/Archive.java similarity index 100% rename from sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/Archive.java rename to labs/glesys/src/main/java/org/jclouds/glesys/domain/Archive.java diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/ArchiveAllowedArguments.java b/labs/glesys/src/main/java/org/jclouds/glesys/domain/ArchiveAllowedArguments.java similarity index 100% rename from sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/ArchiveAllowedArguments.java rename to labs/glesys/src/main/java/org/jclouds/glesys/domain/ArchiveAllowedArguments.java diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/ArchiveDetails.java b/labs/glesys/src/main/java/org/jclouds/glesys/domain/ArchiveDetails.java similarity index 100% rename from sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/ArchiveDetails.java rename to labs/glesys/src/main/java/org/jclouds/glesys/domain/ArchiveDetails.java diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/Console.java b/labs/glesys/src/main/java/org/jclouds/glesys/domain/Console.java similarity index 100% rename from sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/Console.java rename to labs/glesys/src/main/java/org/jclouds/glesys/domain/Console.java diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/Cost.java b/labs/glesys/src/main/java/org/jclouds/glesys/domain/Cost.java similarity index 100% rename from sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/Cost.java rename to labs/glesys/src/main/java/org/jclouds/glesys/domain/Cost.java diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/Domain.java b/labs/glesys/src/main/java/org/jclouds/glesys/domain/Domain.java similarity index 100% rename from sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/Domain.java rename to labs/glesys/src/main/java/org/jclouds/glesys/domain/Domain.java diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/DomainRecord.java b/labs/glesys/src/main/java/org/jclouds/glesys/domain/DomainRecord.java similarity index 100% rename from sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/DomainRecord.java rename to labs/glesys/src/main/java/org/jclouds/glesys/domain/DomainRecord.java diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/EmailAccount.java b/labs/glesys/src/main/java/org/jclouds/glesys/domain/EmailAccount.java similarity index 100% rename from sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/EmailAccount.java rename to labs/glesys/src/main/java/org/jclouds/glesys/domain/EmailAccount.java diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/EmailOverview.java b/labs/glesys/src/main/java/org/jclouds/glesys/domain/EmailOverview.java similarity index 100% rename from sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/EmailOverview.java rename to labs/glesys/src/main/java/org/jclouds/glesys/domain/EmailOverview.java diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/EmailOverviewDomain.java b/labs/glesys/src/main/java/org/jclouds/glesys/domain/EmailOverviewDomain.java similarity index 100% rename from sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/EmailOverviewDomain.java rename to labs/glesys/src/main/java/org/jclouds/glesys/domain/EmailOverviewDomain.java diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/EmailOverviewSummary.java b/labs/glesys/src/main/java/org/jclouds/glesys/domain/EmailOverviewSummary.java similarity index 100% rename from sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/EmailOverviewSummary.java rename to labs/glesys/src/main/java/org/jclouds/glesys/domain/EmailOverviewSummary.java diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/Ip.java b/labs/glesys/src/main/java/org/jclouds/glesys/domain/Ip.java similarity index 100% rename from sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/Ip.java rename to labs/glesys/src/main/java/org/jclouds/glesys/domain/Ip.java diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/IpDetails.java b/labs/glesys/src/main/java/org/jclouds/glesys/domain/IpDetails.java similarity index 100% rename from sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/IpDetails.java rename to labs/glesys/src/main/java/org/jclouds/glesys/domain/IpDetails.java diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/OSTemplate.java b/labs/glesys/src/main/java/org/jclouds/glesys/domain/OSTemplate.java similarity index 100% rename from sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/OSTemplate.java rename to labs/glesys/src/main/java/org/jclouds/glesys/domain/OSTemplate.java diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/ResourceUsage.java b/labs/glesys/src/main/java/org/jclouds/glesys/domain/ResourceUsage.java similarity index 100% rename from sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/ResourceUsage.java rename to labs/glesys/src/main/java/org/jclouds/glesys/domain/ResourceUsage.java diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/Server.java b/labs/glesys/src/main/java/org/jclouds/glesys/domain/Server.java similarity index 98% rename from sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/Server.java rename to labs/glesys/src/main/java/org/jclouds/glesys/domain/Server.java index 2de593fb3f..d70db141eb 100644 --- a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/Server.java +++ b/labs/glesys/src/main/java/org/jclouds/glesys/domain/Server.java @@ -34,7 +34,7 @@ public class Server implements Comparable { public static enum State { - RUNNING, STOPPED, UNRECOGNIZED; + RUNNING, LOCKED, STOPPED, UNRECOGNIZED; public String value() { return (CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, name())); diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/ServerDetails.java b/labs/glesys/src/main/java/org/jclouds/glesys/domain/ServerDetails.java similarity index 82% rename from sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/ServerDetails.java rename to labs/glesys/src/main/java/org/jclouds/glesys/domain/ServerDetails.java index 238e8c4b20..c18ce42ce6 100644 --- a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/ServerDetails.java +++ b/labs/glesys/src/main/java/org/jclouds/glesys/domain/ServerDetails.java @@ -28,7 +28,7 @@ import com.google.gson.annotations.SerializedName; /** * Detailed information about a server such as cpuCores, hardware configuration * (cpu, memory and disk), ip adresses, cost, transfer, os and more. - * + * * @author Adrian Cole * @see */ @@ -38,6 +38,7 @@ public class ServerDetails extends Server { } public static class Builder extends Server.Builder { + private Server.State state; private String description; private String templateName; private int cpuCores; @@ -47,6 +48,11 @@ public class ServerDetails extends Server { private Cost cost; private Set ips = ImmutableSet.of(); + public Builder state(Server.State state) { + this.state = state; + return this; + } + public Builder description(String description) { this.description = description; return this; @@ -56,7 +62,7 @@ public class ServerDetails extends Server { this.templateName = templateName; return this; } - + public Builder cpuCores(int cpuCores) { this.cpuCores = cpuCores; return this; @@ -92,11 +98,13 @@ public class ServerDetails extends Server { } public ServerDetails build() { - return new ServerDetails(id, hostname, datacenter, platform, templateName, description, cpuCores, memorySizeMB, diskSizeGB, transferGB, cost, ips); + return new ServerDetails(id, hostname, datacenter, platform, state, templateName, description, cpuCores, + memorySizeMB, diskSizeGB, transferGB, cost, ips); } public Builder fromServerDetails(ServerDetails in) { - return fromServer(in).templateName(in.getTemplateName()).memorySizeMB(in.getMemorySizeMB()).diskSizeGB(in.getDiskSizeGB()).cpuCores(in.getCpuCores()).cost(in.getCost()) + return fromServer(in).templateName(in.getTemplateName()).state(in.getState()).memorySizeMB(in.getMemorySizeMB()) + .diskSizeGB(in.getDiskSizeGB()).cpuCores(in.getCpuCores()).cost(in.getCost()) .transferGB(in.getTransferGB()).description(in.getDescription()).ips(in.getIps()); } @@ -126,6 +134,7 @@ public class ServerDetails extends Server { } } + private final Server.State state; private final String description; @SerializedName("templatename") private final String templateName; @@ -141,9 +150,11 @@ public class ServerDetails extends Server { @SerializedName("iplist") private final Set ips; - public ServerDetails(String id, String hostname, String datacenter, String platform, String templateName, - String description, int cpuCores, int memorySizeMB, int diskSizeGB, int transferGB, Cost cost, Set ips) { + public ServerDetails(String id, String hostname, String datacenter, String platform, Server.State state, + String templateName, String description, int cpuCores, int memorySizeMB, int diskSizeGB, int transferGB, + Cost cost, Set ips) { super(id, hostname, datacenter, platform); + this.state = state; this.templateName = checkNotNull(templateName, "template"); this.description = description; this.cpuCores = cpuCores; @@ -151,7 +162,14 @@ public class ServerDetails extends Server { this.diskSizeGB = diskSizeGB; this.transferGB = transferGB; this.cost = checkNotNull(cost, "cost"); - this.ips = ImmutableSet.copyOf(ips); + this.ips = ImmutableSet. copyOf(ips); + } + + /** + * @return the state of the server (e.g. "running") + */ + public Server.State getState() { + return state; } /** @@ -212,9 +230,11 @@ public class ServerDetails extends Server { @Override public String toString() { - return String.format( - "[id=%s, hostname=%s, datacenter=%s, platform=%s, templateName=%s, description=%s, cpuCores=%d, memorySizeMB=%d, diskSizeGB=%d, transferGB=%d, cost=%s, ips=%s]", id, - hostname, datacenter, platform, templateName, description, cpuCores, memorySizeMB, diskSizeGB, transferGB, cost, ips); + return String + .format( + "[id=%s, hostname=%s, datacenter=%s, platform=%s, templateName=%s, state=%s, description=%s, cpuCores=%d, memorySizeMB=%d, diskSizeGB=%d, transferGB=%d, cost=%s, ips=%s]", + id, hostname, datacenter, platform, templateName, state, description, cpuCores, memorySizeMB, + diskSizeGB, transferGB, cost, ips); } } diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/ServerLimit.java b/labs/glesys/src/main/java/org/jclouds/glesys/domain/ServerLimit.java similarity index 100% rename from sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/ServerLimit.java rename to labs/glesys/src/main/java/org/jclouds/glesys/domain/ServerLimit.java diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/ServerSpec.java b/labs/glesys/src/main/java/org/jclouds/glesys/domain/ServerSpec.java similarity index 99% rename from sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/ServerSpec.java rename to labs/glesys/src/main/java/org/jclouds/glesys/domain/ServerSpec.java index ef505efbdf..3ddb6031a1 100644 --- a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/ServerSpec.java +++ b/labs/glesys/src/main/java/org/jclouds/glesys/domain/ServerSpec.java @@ -186,7 +186,7 @@ public class ServerSpec { @Override public String toString() { return toStringHelper("").add("platform", platform).add("datacenter", datacenter) - .add("templateName", templateName).add("cpuCores", cpuCores).add("cpuCores", cpuCores) + .add("templateName", templateName).add("cpuCores", cpuCores).add("memorySizeMB", memorySizeMB) .add("diskSizeGB", diskSizeGB).add("transferGB", transferGB).toString(); } } diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/ServerStatus.java b/labs/glesys/src/main/java/org/jclouds/glesys/domain/ServerStatus.java similarity index 100% rename from sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/ServerStatus.java rename to labs/glesys/src/main/java/org/jclouds/glesys/domain/ServerStatus.java diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/ServerUptime.java b/labs/glesys/src/main/java/org/jclouds/glesys/domain/ServerUptime.java similarity index 100% rename from sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/ServerUptime.java rename to labs/glesys/src/main/java/org/jclouds/glesys/domain/ServerUptime.java diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/features/ArchiveAsyncClient.java b/labs/glesys/src/main/java/org/jclouds/glesys/features/ArchiveAsyncClient.java similarity index 100% rename from sandbox-providers/glesys/src/main/java/org/jclouds/glesys/features/ArchiveAsyncClient.java rename to labs/glesys/src/main/java/org/jclouds/glesys/features/ArchiveAsyncClient.java diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/features/ArchiveClient.java b/labs/glesys/src/main/java/org/jclouds/glesys/features/ArchiveClient.java similarity index 100% rename from sandbox-providers/glesys/src/main/java/org/jclouds/glesys/features/ArchiveClient.java rename to labs/glesys/src/main/java/org/jclouds/glesys/features/ArchiveClient.java diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/features/DomainAsyncClient.java b/labs/glesys/src/main/java/org/jclouds/glesys/features/DomainAsyncClient.java similarity index 100% rename from sandbox-providers/glesys/src/main/java/org/jclouds/glesys/features/DomainAsyncClient.java rename to labs/glesys/src/main/java/org/jclouds/glesys/features/DomainAsyncClient.java diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/features/DomainClient.java b/labs/glesys/src/main/java/org/jclouds/glesys/features/DomainClient.java similarity index 100% rename from sandbox-providers/glesys/src/main/java/org/jclouds/glesys/features/DomainClient.java rename to labs/glesys/src/main/java/org/jclouds/glesys/features/DomainClient.java diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/features/EmailAsyncClient.java b/labs/glesys/src/main/java/org/jclouds/glesys/features/EmailAsyncClient.java similarity index 100% rename from sandbox-providers/glesys/src/main/java/org/jclouds/glesys/features/EmailAsyncClient.java rename to labs/glesys/src/main/java/org/jclouds/glesys/features/EmailAsyncClient.java diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/features/EmailClient.java b/labs/glesys/src/main/java/org/jclouds/glesys/features/EmailClient.java similarity index 100% rename from sandbox-providers/glesys/src/main/java/org/jclouds/glesys/features/EmailClient.java rename to labs/glesys/src/main/java/org/jclouds/glesys/features/EmailClient.java diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/features/IpAsyncClient.java b/labs/glesys/src/main/java/org/jclouds/glesys/features/IpAsyncClient.java similarity index 100% rename from sandbox-providers/glesys/src/main/java/org/jclouds/glesys/features/IpAsyncClient.java rename to labs/glesys/src/main/java/org/jclouds/glesys/features/IpAsyncClient.java diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/features/IpClient.java b/labs/glesys/src/main/java/org/jclouds/glesys/features/IpClient.java similarity index 100% rename from sandbox-providers/glesys/src/main/java/org/jclouds/glesys/features/IpClient.java rename to labs/glesys/src/main/java/org/jclouds/glesys/features/IpClient.java diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/features/ServerAsyncClient.java b/labs/glesys/src/main/java/org/jclouds/glesys/features/ServerAsyncClient.java similarity index 99% rename from sandbox-providers/glesys/src/main/java/org/jclouds/glesys/features/ServerAsyncClient.java rename to labs/glesys/src/main/java/org/jclouds/glesys/features/ServerAsyncClient.java index 7928b79a67..546277f57c 100644 --- a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/features/ServerAsyncClient.java +++ b/labs/glesys/src/main/java/org/jclouds/glesys/features/ServerAsyncClient.java @@ -85,6 +85,7 @@ public interface ServerAsyncClient { @Path("/server/details/format/json") @SelectJson("server") @Consumes(MediaType.APPLICATION_JSON) + @FormParams(keys = "includestate", values = "true") @ExceptionParser(ReturnNullOnNotFoundOr404.class) ListenableFuture getServerDetails(@FormParam("serverid") String id); diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/features/ServerClient.java b/labs/glesys/src/main/java/org/jclouds/glesys/features/ServerClient.java similarity index 98% rename from sandbox-providers/glesys/src/main/java/org/jclouds/glesys/features/ServerClient.java rename to labs/glesys/src/main/java/org/jclouds/glesys/features/ServerClient.java index 166ad9d8ee..fe7c523fb8 100644 --- a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/features/ServerClient.java +++ b/labs/glesys/src/main/java/org/jclouds/glesys/features/ServerClient.java @@ -166,6 +166,7 @@ public interface ServerClient { * @param options * optional settings ex. description */ + @Timeout(duration = 180, timeUnit = TimeUnit.SECONDS) ServerDetails createServerWithHostnameAndRootPassword(ServerSpec serverSpec, String hostname, String rootPassword, CreateServerOptions... options); @@ -189,6 +190,7 @@ public interface ServerClient { * @param options * the settings to change */ + @Timeout(duration = 180, timeUnit = TimeUnit.SECONDS) ServerDetails cloneServer(String serverid, String hostname, CloneServerOptions... options); /** diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/functions/ParseTemplatesFromHttpResponse.java b/labs/glesys/src/main/java/org/jclouds/glesys/functions/ParseTemplatesFromHttpResponse.java similarity index 100% rename from sandbox-providers/glesys/src/main/java/org/jclouds/glesys/functions/ParseTemplatesFromHttpResponse.java rename to labs/glesys/src/main/java/org/jclouds/glesys/functions/ParseTemplatesFromHttpResponse.java diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/functions/internal/GleSYSTypeAdapters.java b/labs/glesys/src/main/java/org/jclouds/glesys/functions/internal/GleSYSTypeAdapters.java similarity index 100% rename from sandbox-providers/glesys/src/main/java/org/jclouds/glesys/functions/internal/GleSYSTypeAdapters.java rename to labs/glesys/src/main/java/org/jclouds/glesys/functions/internal/GleSYSTypeAdapters.java diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/functions/internal/GlesysDateAdapter.java b/labs/glesys/src/main/java/org/jclouds/glesys/functions/internal/GlesysDateAdapter.java similarity index 100% rename from sandbox-providers/glesys/src/main/java/org/jclouds/glesys/functions/internal/GlesysDateAdapter.java rename to labs/glesys/src/main/java/org/jclouds/glesys/functions/internal/GlesysDateAdapter.java diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/handlers/GleSYSErrorHandler.java b/labs/glesys/src/main/java/org/jclouds/glesys/handlers/GleSYSErrorHandler.java similarity index 90% rename from sandbox-providers/glesys/src/main/java/org/jclouds/glesys/handlers/GleSYSErrorHandler.java rename to labs/glesys/src/main/java/org/jclouds/glesys/handlers/GleSYSErrorHandler.java index 2205123e5b..9f5a37c309 100644 --- a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/handlers/GleSYSErrorHandler.java +++ b/labs/glesys/src/main/java/org/jclouds/glesys/handlers/GleSYSErrorHandler.java @@ -56,14 +56,16 @@ public class GleSYSErrorHandler implements HttpErrorHandler { exception = new AuthorizationException(message, exception); break; case 400: - if (command.getCurrentRequest().getEndpoint().getPath().indexOf("delete") != -1 - && message.indexOf("Could not find") != -1) { + if (message.indexOf("Could not find") != -1) { exception = new ResourceNotFoundException(message, exception); } break; case 404: - if (command.getCurrentRequest().getEndpoint().getPath().indexOf("delete") == -1) { - exception = new ResourceNotFoundException(message, exception); + exception = new ResourceNotFoundException(message, exception); + break; + case 500: + if (message.indexOf("Locked") != -1) { + exception = new IllegalStateException(message, exception); } break; } diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/AddDomainOptions.java b/labs/glesys/src/main/java/org/jclouds/glesys/options/AddDomainOptions.java similarity index 100% rename from sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/AddDomainOptions.java rename to labs/glesys/src/main/java/org/jclouds/glesys/options/AddDomainOptions.java diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/AddRecordOptions.java b/labs/glesys/src/main/java/org/jclouds/glesys/options/AddRecordOptions.java similarity index 100% rename from sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/AddRecordOptions.java rename to labs/glesys/src/main/java/org/jclouds/glesys/options/AddRecordOptions.java diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/CloneServerOptions.java b/labs/glesys/src/main/java/org/jclouds/glesys/options/CloneServerOptions.java similarity index 100% rename from sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/CloneServerOptions.java rename to labs/glesys/src/main/java/org/jclouds/glesys/options/CloneServerOptions.java diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/CreateAccountOptions.java b/labs/glesys/src/main/java/org/jclouds/glesys/options/CreateAccountOptions.java similarity index 100% rename from sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/CreateAccountOptions.java rename to labs/glesys/src/main/java/org/jclouds/glesys/options/CreateAccountOptions.java diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/CreateServerOptions.java b/labs/glesys/src/main/java/org/jclouds/glesys/options/CreateServerOptions.java similarity index 83% rename from sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/CreateServerOptions.java rename to labs/glesys/src/main/java/org/jclouds/glesys/options/CreateServerOptions.java index 437564a0d7..5764e62526 100644 --- a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/CreateServerOptions.java +++ b/labs/glesys/src/main/java/org/jclouds/glesys/options/CreateServerOptions.java @@ -18,11 +18,14 @@ */ package org.jclouds.glesys.options; +import static com.google.common.base.Objects.equal; +import static com.google.common.base.Objects.toStringHelper; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkState; import static com.google.common.base.Predicates.instanceOf; import static com.google.common.collect.Iterables.find; +import static com.google.common.collect.Multimaps.forMap; import java.util.Map; @@ -32,8 +35,8 @@ import org.jclouds.io.payloads.UrlEncodedFormPayload; import org.jclouds.rest.MapBinder; import org.jclouds.rest.internal.GeneratedHttpRequest; +import com.google.common.base.Objects; import com.google.common.collect.ImmutableMultimap; -import com.google.common.collect.Multimaps; /** * @author Adam Lowe @@ -51,7 +54,7 @@ public class CreateServerOptions implements MapBinder { checkState(gRequest.getArgs() != null, "args should be initialized at this point"); ImmutableMultimap.Builder formParams = ImmutableMultimap. builder(); - formParams.putAll(Multimaps.forMap(postParams)); + formParams.putAll(forMap(postParams)); ServerSpec serverSpec = ServerSpec.class.cast(find(gRequest.getArgs(), instanceOf(ServerSpec.class))); formParams.put("datacenter", serverSpec.getDatacenter()); formParams.put("platform", serverSpec.getPlatform()); @@ -109,4 +112,25 @@ public class CreateServerOptions implements MapBinder { public R bindToRequest(R request, Object input) { throw new IllegalArgumentException(); } + + @Override + public int hashCode() { + return Objects.hashCode(ip, description); + } + + @Override + public boolean equals(Object obj) { + if (obj == null) + return false; + if (!(obj instanceof CreateServerOptions)) + return false; + CreateServerOptions that = CreateServerOptions.class.cast(obj); + return equal(this.ip, that.ip) && equal(this.description, that.description); + } + + @Override + public String toString() { + return toStringHelper("").add("ip", ip).add("description", description).toString(); + } + } diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/DestroyServerOptions.java b/labs/glesys/src/main/java/org/jclouds/glesys/options/DestroyServerOptions.java similarity index 100% rename from sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/DestroyServerOptions.java rename to labs/glesys/src/main/java/org/jclouds/glesys/options/DestroyServerOptions.java diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/DomainOptions.java b/labs/glesys/src/main/java/org/jclouds/glesys/options/DomainOptions.java similarity index 100% rename from sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/DomainOptions.java rename to labs/glesys/src/main/java/org/jclouds/glesys/options/DomainOptions.java diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/EditAccountOptions.java b/labs/glesys/src/main/java/org/jclouds/glesys/options/EditAccountOptions.java similarity index 100% rename from sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/EditAccountOptions.java rename to labs/glesys/src/main/java/org/jclouds/glesys/options/EditAccountOptions.java diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/EditRecordOptions.java b/labs/glesys/src/main/java/org/jclouds/glesys/options/EditRecordOptions.java similarity index 100% rename from sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/EditRecordOptions.java rename to labs/glesys/src/main/java/org/jclouds/glesys/options/EditRecordOptions.java diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/EditServerOptions.java b/labs/glesys/src/main/java/org/jclouds/glesys/options/EditServerOptions.java similarity index 100% rename from sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/EditServerOptions.java rename to labs/glesys/src/main/java/org/jclouds/glesys/options/EditServerOptions.java diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/ServerStatusOptions.java b/labs/glesys/src/main/java/org/jclouds/glesys/options/ServerStatusOptions.java similarity index 100% rename from sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/ServerStatusOptions.java rename to labs/glesys/src/main/java/org/jclouds/glesys/options/ServerStatusOptions.java diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/reference/GleSYSConstants.java b/labs/glesys/src/main/java/org/jclouds/glesys/reference/GleSYSConstants.java similarity index 100% rename from sandbox-providers/glesys/src/main/java/org/jclouds/glesys/reference/GleSYSConstants.java rename to labs/glesys/src/main/java/org/jclouds/glesys/reference/GleSYSConstants.java diff --git a/sandbox-providers/glesys/src/main/resources/META-INF/services/org.jclouds.providers.ProviderMetadata b/labs/glesys/src/main/resources/META-INF/services/org.jclouds.providers.ProviderMetadata similarity index 100% rename from sandbox-providers/glesys/src/main/resources/META-INF/services/org.jclouds.providers.ProviderMetadata rename to labs/glesys/src/main/resources/META-INF/services/org.jclouds.providers.ProviderMetadata diff --git a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/GleSYSAsyncClientTest.java b/labs/glesys/src/test/java/org/jclouds/glesys/GleSYSAsyncClientTest.java similarity index 100% rename from sandbox-providers/glesys/src/test/java/org/jclouds/glesys/GleSYSAsyncClientTest.java rename to labs/glesys/src/test/java/org/jclouds/glesys/GleSYSAsyncClientTest.java diff --git a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/GleSYSErrorHandlerTest.java b/labs/glesys/src/test/java/org/jclouds/glesys/GleSYSErrorHandlerTest.java similarity index 86% rename from sandbox-providers/glesys/src/test/java/org/jclouds/glesys/GleSYSErrorHandlerTest.java rename to labs/glesys/src/test/java/org/jclouds/glesys/GleSYSErrorHandlerTest.java index e67832f236..2db8980551 100644 --- a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/GleSYSErrorHandlerTest.java +++ b/labs/glesys/src/test/java/org/jclouds/glesys/GleSYSErrorHandlerTest.java @@ -50,7 +50,16 @@ public class GleSYSErrorHandlerTest { public void test401MakesAuthorizationException() { assertCodeMakes("GET", URI.create("https://api.glesys.com/foo"), 401, "", "Unauthorized", AuthorizationException.class); - + } + @Test + public void test500LockedMakesIllegalStateException() { + assertCodeMakes( + "POST", + URI.create("https://api.glesys.com/server/destroy/format/json"), + 500, + "", + "{\"response\":{\"status\":{\"code\":606,\"timestamp\":\"2012-02-14T15:48:39+01:00\",\"text\":\"Server Locked\"},\"debug\":{\"input\":{\"serverid\":\"xm3270596\",\"keepip\":\"0\"}}}}", + IllegalStateException.class); } @Test @@ -60,10 +69,10 @@ public class GleSYSErrorHandlerTest { URI.create("https://api.glesys.com/domain/delete/format/json"), 400, "", - "{\"response\":{\"status\":{\"code\":400,\"timestamp\":\"2012-02-10T12:07:56+01:00\",\"text\":\"Could not find domain on this account.\n\"},\"debug\":{\"input\":{\"domainname\":\"email-test.jclouds.org\"}}}}", + "{\"response\":{\"status\":{\"code\":400,\"timestamp\":\"2012-02-10T12:07:56+01:00\",\"text\":\"Could not find server with this id on this account.\n\"},\"debug\":{\"input\":{\"domainname\":\"email-test.jclouds.org\"}}}}", ResourceNotFoundException.class); } - + @Test public void test404MakesResourceNotFoundException() { assertCodeMakes("GET", URI.create("https://api.glesys.com/foo"), 404, "", "Not Found", diff --git a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/GleSYSProviderTest.java b/labs/glesys/src/test/java/org/jclouds/glesys/GleSYSProviderTest.java similarity index 100% rename from sandbox-providers/glesys/src/test/java/org/jclouds/glesys/GleSYSProviderTest.java rename to labs/glesys/src/test/java/org/jclouds/glesys/GleSYSProviderTest.java diff --git a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/compute/GleSYSComputeServiceAdapterExpectTest.java b/labs/glesys/src/test/java/org/jclouds/glesys/compute/GleSYSComputeServiceAdapterExpectTest.java similarity index 100% rename from sandbox-providers/glesys/src/test/java/org/jclouds/glesys/compute/GleSYSComputeServiceAdapterExpectTest.java rename to labs/glesys/src/test/java/org/jclouds/glesys/compute/GleSYSComputeServiceAdapterExpectTest.java diff --git a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/compute/GleSYSComputeServiceLiveTest.java b/labs/glesys/src/test/java/org/jclouds/glesys/compute/GleSYSComputeServiceLiveTest.java similarity index 91% rename from sandbox-providers/glesys/src/test/java/org/jclouds/glesys/compute/GleSYSComputeServiceLiveTest.java rename to labs/glesys/src/test/java/org/jclouds/glesys/compute/GleSYSComputeServiceLiveTest.java index 33cd8cc808..70bdfb25f3 100644 --- a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/compute/GleSYSComputeServiceLiveTest.java +++ b/labs/glesys/src/test/java/org/jclouds/glesys/compute/GleSYSComputeServiceLiveTest.java @@ -40,6 +40,8 @@ import com.google.inject.Module; public class GleSYSComputeServiceLiveTest extends BaseComputeServiceLiveTest { public GleSYSComputeServiceLiveTest() { provider = "glesys"; + // ensure hyphens work + group = "gle-sys"; } @Override @@ -49,10 +51,10 @@ public class GleSYSComputeServiceLiveTest extends BaseComputeServiceLiveTest { public void testAssignability() throws Exception { @SuppressWarnings("unused") - RestContext tmContext = new ComputeServiceContextFactory() - .createContext(provider, identity, credential).getProviderSpecificContext(); + RestContext tmContext = new ComputeServiceContextFactory().createContext( + provider, identity, credential).getProviderSpecificContext(); } - + // GleSYS does not support metadata @Override protected void checkUserMetadataInNodeEquals(NodeMetadata node, ImmutableMap userMetadata) { diff --git a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/compute/GleSYSExperimentExpectTest.java b/labs/glesys/src/test/java/org/jclouds/glesys/compute/GleSYSExperimentExpectTest.java similarity index 100% rename from sandbox-providers/glesys/src/test/java/org/jclouds/glesys/compute/GleSYSExperimentExpectTest.java rename to labs/glesys/src/test/java/org/jclouds/glesys/compute/GleSYSExperimentExpectTest.java diff --git a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/compute/GleSYSExperimentLiveTest.java b/labs/glesys/src/test/java/org/jclouds/glesys/compute/GleSYSExperimentLiveTest.java similarity index 100% rename from sandbox-providers/glesys/src/test/java/org/jclouds/glesys/compute/GleSYSExperimentLiveTest.java rename to labs/glesys/src/test/java/org/jclouds/glesys/compute/GleSYSExperimentLiveTest.java diff --git a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/compute/GleSYSTemplateBuilderLiveTest.java b/labs/glesys/src/test/java/org/jclouds/glesys/compute/GleSYSTemplateBuilderLiveTest.java similarity index 99% rename from sandbox-providers/glesys/src/test/java/org/jclouds/glesys/compute/GleSYSTemplateBuilderLiveTest.java rename to labs/glesys/src/test/java/org/jclouds/glesys/compute/GleSYSTemplateBuilderLiveTest.java index fe644358f2..7e5edad7b2 100644 --- a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/compute/GleSYSTemplateBuilderLiveTest.java +++ b/labs/glesys/src/test/java/org/jclouds/glesys/compute/GleSYSTemplateBuilderLiveTest.java @@ -82,13 +82,13 @@ public class GleSYSTemplateBuilderLiveTest extends BaseTemplateBuilderLiveTest { @Test public void testDefaultTemplateBuilder() throws IOException { Template defaultTemplate = context.getComputeService().templateBuilder().build(); - assertEquals(defaultTemplate.getImage().getId(), "Ubuntu 11.04 x64"); + assertEquals(defaultTemplate.getImage().getId(), "Ubuntu 11.04 64-bit"); assertEquals(defaultTemplate.getImage().getOperatingSystem().getVersion(), "11.04"); assertEquals(defaultTemplate.getImage().getOperatingSystem().is64Bit(), true); assertEquals(defaultTemplate.getImage().getOperatingSystem().getFamily(), OsFamily.UBUNTU); assertEquals(getCores(defaultTemplate.getHardware()), 1.0d); assertEquals(defaultTemplate.getHardware().getRam(), 512); - assertEquals(defaultTemplate.getHardware().getHypervisor(), "Xen"); + assertEquals(defaultTemplate.getHardware().getHypervisor(), "OpenVZ"); assertEquals(getSpace(defaultTemplate.getHardware()), 5.0d); assertEquals(defaultTemplate.getHardware().getVolumes().get(0).getType(), Volume.Type.LOCAL); // test that we bound the correct templateoptions in guice diff --git a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/compute/functions/ParseOsFamilyVersion64BitFromImageNameTest.java b/labs/glesys/src/test/java/org/jclouds/glesys/compute/functions/ParseOsFamilyVersion64BitFromImageNameTest.java similarity index 100% rename from sandbox-providers/glesys/src/test/java/org/jclouds/glesys/compute/functions/ParseOsFamilyVersion64BitFromImageNameTest.java rename to labs/glesys/src/test/java/org/jclouds/glesys/compute/functions/ParseOsFamilyVersion64BitFromImageNameTest.java diff --git a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/compute/functions/ServerDetailsToNodeMetadataTest.java b/labs/glesys/src/test/java/org/jclouds/glesys/compute/functions/ServerDetailsToNodeMetadataTest.java similarity index 78% rename from sandbox-providers/glesys/src/test/java/org/jclouds/glesys/compute/functions/ServerDetailsToNodeMetadataTest.java rename to labs/glesys/src/test/java/org/jclouds/glesys/compute/functions/ServerDetailsToNodeMetadataTest.java index d51519ed06..c48ed8c28f 100644 --- a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/compute/functions/ServerDetailsToNodeMetadataTest.java +++ b/labs/glesys/src/test/java/org/jclouds/glesys/compute/functions/ServerDetailsToNodeMetadataTest.java @@ -68,20 +68,7 @@ public class ServerDetailsToNodeMetadataTest extends BaseGleSYSComputeServiceExp HttpResponse .builder() .statusCode(200) - .payload( - payloadFromString("{\"response\":{\"status\":{\"code\":200,\"timestamp\":\"2012-02-10T11:28:50+01:00\",\"text\":\"OK\"},\"server\":{\"state\":\"running\"},\"debug\":{\"input\":{\"serverid\":\"xm3276891\",\"statustype\":\"state\"}}}}")) - .build()) - .put(HttpRequest - .builder() - .method("POST") - .endpoint(URI.create("https://api.glesys.com/server/status/format/json")) - .headers( - ImmutableMultimap. builder().put("Accept", "application/json") - .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build()) - .payload( - newUrlEncodedFormPayload(ImmutableMultimap. builder() - .put("serverid", "xm3276891").put("statustype", "state").build())).build(), - HttpResponse.builder().statusCode(206).payload(payloadFromResource("/server_status.json")) + .payload(payloadFromResource("/server_details.json")) .build()).build() ).getInstance(ServerDetailsToNodeMetadata.class); diff --git a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/compute/functions/ServerSpecToHardwareTest.java b/labs/glesys/src/test/java/org/jclouds/glesys/compute/functions/ServerSpecToHardwareTest.java similarity index 100% rename from sandbox-providers/glesys/src/test/java/org/jclouds/glesys/compute/functions/ServerSpecToHardwareTest.java rename to labs/glesys/src/test/java/org/jclouds/glesys/compute/functions/ServerSpecToHardwareTest.java diff --git a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/compute/internal/BaseGleSYSComputeServiceExpectTest.java b/labs/glesys/src/test/java/org/jclouds/glesys/compute/internal/BaseGleSYSComputeServiceExpectTest.java similarity index 100% rename from sandbox-providers/glesys/src/test/java/org/jclouds/glesys/compute/internal/BaseGleSYSComputeServiceExpectTest.java rename to labs/glesys/src/test/java/org/jclouds/glesys/compute/internal/BaseGleSYSComputeServiceExpectTest.java diff --git a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/compute/options/GleSYSTemplateOptionsTest.java b/labs/glesys/src/test/java/org/jclouds/glesys/compute/options/GleSYSTemplateOptionsTest.java similarity index 100% rename from sandbox-providers/glesys/src/test/java/org/jclouds/glesys/compute/options/GleSYSTemplateOptionsTest.java rename to labs/glesys/src/test/java/org/jclouds/glesys/compute/options/GleSYSTemplateOptionsTest.java diff --git a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/ArchiveClientExpectTest.java b/labs/glesys/src/test/java/org/jclouds/glesys/features/ArchiveClientExpectTest.java similarity index 100% rename from sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/ArchiveClientExpectTest.java rename to labs/glesys/src/test/java/org/jclouds/glesys/features/ArchiveClientExpectTest.java diff --git a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/ArchiveClientLiveTest.java b/labs/glesys/src/test/java/org/jclouds/glesys/features/ArchiveClientLiveTest.java similarity index 100% rename from sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/ArchiveClientLiveTest.java rename to labs/glesys/src/test/java/org/jclouds/glesys/features/ArchiveClientLiveTest.java diff --git a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/DomainClientExpectTest.java b/labs/glesys/src/test/java/org/jclouds/glesys/features/DomainClientExpectTest.java similarity index 98% rename from sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/DomainClientExpectTest.java rename to labs/glesys/src/test/java/org/jclouds/glesys/features/DomainClientExpectTest.java index d5b90e14b0..60a9f448be 100644 --- a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/DomainClientExpectTest.java +++ b/labs/glesys/src/test/java/org/jclouds/glesys/features/DomainClientExpectTest.java @@ -18,12 +18,13 @@ */ package org.jclouds.glesys.features; -import com.google.common.collect.ImmutableMultimap; -import com.google.common.collect.ImmutableSet; -import com.google.common.collect.ImmutableSortedSet; -import com.google.common.collect.Iterables; -import com.google.inject.Inject; -import org.apache.log4j.helpers.ISO8601DateFormat; +import static org.jclouds.io.Payloads.newUrlEncodedFormPayload; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; + +import java.net.URI; +import java.util.Set; + import org.jclouds.date.DateService; import org.jclouds.date.internal.SimpleDateFormatDateService; import org.jclouds.glesys.GleSYSClient; @@ -32,18 +33,13 @@ import org.jclouds.glesys.domain.DomainRecord; import org.jclouds.glesys.options.AddDomainOptions; import org.jclouds.http.HttpRequest; import org.jclouds.http.HttpResponse; -import org.jclouds.json.config.GsonModule; import org.jclouds.rest.BaseRestClientExpectTest; import org.jclouds.rest.ResourceNotFoundException; import org.testng.annotations.Test; -import java.net.URI; -import java.text.SimpleDateFormat; -import java.util.Set; - -import static org.jclouds.io.Payloads.newUrlEncodedFormPayload; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertTrue; +import com.google.common.collect.ImmutableMultimap; +import com.google.common.collect.ImmutableSortedSet; +import com.google.common.collect.Iterables; /** * Tests annotation parsing of {@code DomainAsyncClient} diff --git a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/DomainClientLiveTest.java b/labs/glesys/src/test/java/org/jclouds/glesys/features/DomainClientLiveTest.java similarity index 100% rename from sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/DomainClientLiveTest.java rename to labs/glesys/src/test/java/org/jclouds/glesys/features/DomainClientLiveTest.java diff --git a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/EmailClientExpectTest.java b/labs/glesys/src/test/java/org/jclouds/glesys/features/EmailClientExpectTest.java similarity index 100% rename from sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/EmailClientExpectTest.java rename to labs/glesys/src/test/java/org/jclouds/glesys/features/EmailClientExpectTest.java diff --git a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/EmailClientLiveTest.java b/labs/glesys/src/test/java/org/jclouds/glesys/features/EmailClientLiveTest.java similarity index 100% rename from sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/EmailClientLiveTest.java rename to labs/glesys/src/test/java/org/jclouds/glesys/features/EmailClientLiveTest.java diff --git a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/IpAsyncClientTest.java b/labs/glesys/src/test/java/org/jclouds/glesys/features/IpAsyncClientTest.java similarity index 100% rename from sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/IpAsyncClientTest.java rename to labs/glesys/src/test/java/org/jclouds/glesys/features/IpAsyncClientTest.java diff --git a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/IpClientExpectTest.java b/labs/glesys/src/test/java/org/jclouds/glesys/features/IpClientExpectTest.java similarity index 100% rename from sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/IpClientExpectTest.java rename to labs/glesys/src/test/java/org/jclouds/glesys/features/IpClientExpectTest.java diff --git a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/IpClientLiveTest.java b/labs/glesys/src/test/java/org/jclouds/glesys/features/IpClientLiveTest.java similarity index 100% rename from sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/IpClientLiveTest.java rename to labs/glesys/src/test/java/org/jclouds/glesys/features/IpClientLiveTest.java diff --git a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/ServerClientExpectTest.java b/labs/glesys/src/test/java/org/jclouds/glesys/features/ServerClientExpectTest.java similarity index 99% rename from sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/ServerClientExpectTest.java rename to labs/glesys/src/test/java/org/jclouds/glesys/features/ServerClientExpectTest.java index ce0c6acb91..d381f08314 100644 --- a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/ServerClientExpectTest.java +++ b/labs/glesys/src/test/java/org/jclouds/glesys/features/ServerClientExpectTest.java @@ -146,6 +146,7 @@ public class ServerClientExpectTest extends BaseRestClientExpectTestbuilder() + .put("includestate", "true") .put("serverid", "xm3276891").build())).build(), HttpResponse.builder().statusCode(200).payload(payloadFromResource("/server_details.json")).build()).getServerClient(); @@ -158,7 +159,7 @@ public class ServerClientExpectTest extends BaseRestClientExpectTestbuilder() + .put("includestate", "true") .put("serverid", "xm3276891").build())).build(), HttpResponse.builder().statusCode(404).build()).getServerClient(); diff --git a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/ServerClientLiveTest.java b/labs/glesys/src/test/java/org/jclouds/glesys/features/ServerClientLiveTest.java similarity index 100% rename from sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/ServerClientLiveTest.java rename to labs/glesys/src/test/java/org/jclouds/glesys/features/ServerClientLiveTest.java diff --git a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/internal/BaseGleSYSAsyncClientTest.java b/labs/glesys/src/test/java/org/jclouds/glesys/internal/BaseGleSYSAsyncClientTest.java similarity index 100% rename from sandbox-providers/glesys/src/test/java/org/jclouds/glesys/internal/BaseGleSYSAsyncClientTest.java rename to labs/glesys/src/test/java/org/jclouds/glesys/internal/BaseGleSYSAsyncClientTest.java diff --git a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/internal/BaseGleSYSClientLiveTest.java b/labs/glesys/src/test/java/org/jclouds/glesys/internal/BaseGleSYSClientLiveTest.java similarity index 88% rename from sandbox-providers/glesys/src/test/java/org/jclouds/glesys/internal/BaseGleSYSClientLiveTest.java rename to labs/glesys/src/test/java/org/jclouds/glesys/internal/BaseGleSYSClientLiveTest.java index 11f6bb9dfb..52ca98a804 100644 --- a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/internal/BaseGleSYSClientLiveTest.java +++ b/labs/glesys/src/test/java/org/jclouds/glesys/internal/BaseGleSYSClientLiveTest.java @@ -23,6 +23,7 @@ import static org.testng.Assert.assertFalse; import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertTrue; +import java.util.UUID; import java.util.concurrent.TimeUnit; import org.jclouds.compute.BaseVersionedServiceLiveTest; @@ -62,14 +63,13 @@ public class BaseGleSYSClientLiveTest extends BaseVersionedServiceLiveTest { public BaseGleSYSClientLiveTest() { provider = "glesys"; } - + @BeforeGroups(groups = { "live" }) public void setupClient() { setupCredentials(); - computeContext = new ComputeServiceContextFactory(setupRestProperties()). - createContext(provider, ImmutableSet. of( - new Log4JLoggingModule(), new SshjSshClientModule()), setupProperties()); + computeContext = new ComputeServiceContextFactory(setupRestProperties()).createContext(provider, + ImmutableSet. of(new Log4JLoggingModule(), new SshjSshClientModule()), setupProperties()); context = computeContext.getProviderSpecificContext(); } @@ -85,29 +85,29 @@ public class BaseGleSYSClientLiveTest extends BaseVersionedServiceLiveTest { final DomainClient client = context.getApi().getDomainClient(); int before = client.listDomains().size(); client.addDomain(domain); - RetryablePredicate result = new RetryablePredicate( - new Predicate() { - public boolean apply(Integer value) { - return client.listDomains().size() == value; - } - }, 30, 1, TimeUnit.SECONDS); + RetryablePredicate result = new RetryablePredicate(new Predicate() { + public boolean apply(Integer value) { + return client.listDomains().size() == value; + } + }, 30, 1, TimeUnit.SECONDS); assertTrue(result.apply(before + 1)); } - protected ServerStatusChecker createServer(String hostName) { ServerClient client = context.getApi().getServerClient(); - + ServerDetails testServer = client.createServerWithHostnameAndRootPassword( ServerSpec.builder().datacenter("Falkenberg").platform("OpenVZ").templateName("Ubuntu 10.04 LTS 32-bit") - .diskSizeGB(5).memorySizeMB(512).cpuCores(1).transferGB(50).build(), hostName, "password"); + .diskSizeGB(5).memorySizeMB(512).cpuCores(1).transferGB(50).build(), hostName, UUID.randomUUID() + .toString().replace("-","")); assertNotNull(testServer.getId()); assertEquals(testServer.getHostname(), hostName); assertFalse(testServer.getIps().isEmpty()); - ServerStatusChecker runningServerCounter = new ServerStatusChecker(client, testServer.getId(), 180, 10, TimeUnit.SECONDS); + ServerStatusChecker runningServerCounter = new ServerStatusChecker(client, testServer.getId(), 180, 10, + TimeUnit.SECONDS); assertTrue(runningServerCounter.apply(Server.State.RUNNING)); return runningServerCounter; @@ -115,10 +115,13 @@ public class BaseGleSYSClientLiveTest extends BaseVersionedServiceLiveTest { public static class ServerStatusChecker extends RetryablePredicate { private final String serverId; + public String getServerId() { return serverId; } - public ServerStatusChecker(final ServerClient client, final String serverId, long maxWait, long period, TimeUnit unit) { + + public ServerStatusChecker(final ServerClient client, final String serverId, long maxWait, long period, + TimeUnit unit) { super(new Predicate() { public boolean apply(Server.State value) { diff --git a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/parse/ParseFullIpDetailsTest.java b/labs/glesys/src/test/java/org/jclouds/glesys/parse/ParseFullIpDetailsTest.java similarity index 100% rename from sandbox-providers/glesys/src/test/java/org/jclouds/glesys/parse/ParseFullIpDetailsTest.java rename to labs/glesys/src/test/java/org/jclouds/glesys/parse/ParseFullIpDetailsTest.java diff --git a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/parse/ParseIpAddressFromResponseTest.java b/labs/glesys/src/test/java/org/jclouds/glesys/parse/ParseIpAddressFromResponseTest.java similarity index 100% rename from sandbox-providers/glesys/src/test/java/org/jclouds/glesys/parse/ParseIpAddressFromResponseTest.java rename to labs/glesys/src/test/java/org/jclouds/glesys/parse/ParseIpAddressFromResponseTest.java diff --git a/sandbox-providers/glesys/src/test/resources/archive_allowed_arguments.json b/labs/glesys/src/test/resources/archive_allowed_arguments.json similarity index 100% rename from sandbox-providers/glesys/src/test/resources/archive_allowed_arguments.json rename to labs/glesys/src/test/resources/archive_allowed_arguments.json diff --git a/sandbox-providers/glesys/src/test/resources/archive_details.json b/labs/glesys/src/test/resources/archive_details.json similarity index 100% rename from sandbox-providers/glesys/src/test/resources/archive_details.json rename to labs/glesys/src/test/resources/archive_details.json diff --git a/sandbox-providers/glesys/src/test/resources/archive_list.json b/labs/glesys/src/test/resources/archive_list.json similarity index 100% rename from sandbox-providers/glesys/src/test/resources/archive_list.json rename to labs/glesys/src/test/resources/archive_list.json diff --git a/sandbox-providers/glesys/src/test/resources/domain_list.json b/labs/glesys/src/test/resources/domain_list.json similarity index 100% rename from sandbox-providers/glesys/src/test/resources/domain_list.json rename to labs/glesys/src/test/resources/domain_list.json diff --git a/sandbox-providers/glesys/src/test/resources/domain_list_records.json b/labs/glesys/src/test/resources/domain_list_records.json similarity index 100% rename from sandbox-providers/glesys/src/test/resources/domain_list_records.json rename to labs/glesys/src/test/resources/domain_list_records.json diff --git a/sandbox-providers/glesys/src/test/resources/email_list.json b/labs/glesys/src/test/resources/email_list.json similarity index 100% rename from sandbox-providers/glesys/src/test/resources/email_list.json rename to labs/glesys/src/test/resources/email_list.json diff --git a/sandbox-providers/glesys/src/test/resources/email_overview.json b/labs/glesys/src/test/resources/email_overview.json similarity index 100% rename from sandbox-providers/glesys/src/test/resources/email_overview.json rename to labs/glesys/src/test/resources/email_overview.json diff --git a/sandbox-providers/glesys/src/test/resources/ip_get_details.json b/labs/glesys/src/test/resources/ip_get_details.json similarity index 100% rename from sandbox-providers/glesys/src/test/resources/ip_get_details.json rename to labs/glesys/src/test/resources/ip_get_details.json diff --git a/sandbox-providers/glesys/src/test/resources/ip_get_details_xen.json b/labs/glesys/src/test/resources/ip_get_details_xen.json similarity index 100% rename from sandbox-providers/glesys/src/test/resources/ip_get_details_xen.json rename to labs/glesys/src/test/resources/ip_get_details_xen.json diff --git a/sandbox-providers/glesys/src/test/resources/ip_list_free.json b/labs/glesys/src/test/resources/ip_list_free.json similarity index 100% rename from sandbox-providers/glesys/src/test/resources/ip_list_free.json rename to labs/glesys/src/test/resources/ip_list_free.json diff --git a/sandbox-providers/glesys/src/test/resources/ip_release.json b/labs/glesys/src/test/resources/ip_release.json similarity index 100% rename from sandbox-providers/glesys/src/test/resources/ip_release.json rename to labs/glesys/src/test/resources/ip_release.json diff --git a/sandbox-providers/glesys/src/test/resources/ip_take.json b/labs/glesys/src/test/resources/ip_take.json similarity index 100% rename from sandbox-providers/glesys/src/test/resources/ip_take.json rename to labs/glesys/src/test/resources/ip_take.json diff --git a/sandbox-providers/glesys/src/test/resources/log4j.xml b/labs/glesys/src/test/resources/log4j.xml similarity index 100% rename from sandbox-providers/glesys/src/test/resources/log4j.xml rename to labs/glesys/src/test/resources/log4j.xml diff --git a/sandbox-providers/glesys/src/test/resources/osmatches.json b/labs/glesys/src/test/resources/osmatches.json similarity index 100% rename from sandbox-providers/glesys/src/test/resources/osmatches.json rename to labs/glesys/src/test/resources/osmatches.json diff --git a/sandbox-providers/glesys/src/test/resources/server_allowed_arguments.json b/labs/glesys/src/test/resources/server_allowed_arguments.json similarity index 100% rename from sandbox-providers/glesys/src/test/resources/server_allowed_arguments.json rename to labs/glesys/src/test/resources/server_allowed_arguments.json diff --git a/sandbox-providers/glesys/src/test/resources/server_console.json b/labs/glesys/src/test/resources/server_console.json similarity index 100% rename from sandbox-providers/glesys/src/test/resources/server_console.json rename to labs/glesys/src/test/resources/server_console.json diff --git a/sandbox-providers/glesys/src/test/resources/server_created.json b/labs/glesys/src/test/resources/server_created.json similarity index 100% rename from sandbox-providers/glesys/src/test/resources/server_created.json rename to labs/glesys/src/test/resources/server_created.json diff --git a/sandbox-providers/glesys/src/test/resources/server_details.json b/labs/glesys/src/test/resources/server_details.json similarity index 83% rename from sandbox-providers/glesys/src/test/resources/server_details.json rename to labs/glesys/src/test/resources/server_details.json index bf7f594928..2083d23c54 100644 --- a/sandbox-providers/glesys/src/test/resources/server_details.json +++ b/labs/glesys/src/test/resources/server_details.json @@ -1 +1 @@ -{"response":{"status":{"code":200,"timestamp":"2012-02-10T11:11:05+01:00","text":"OK"},"server":{"serverid":"xm3276891","hostname":"glesys-s-6dd","description":"glesys-s-6dd","cpucores":1,"memorysize":512,"disksize":5,"transfer":50,"templatename":"Ubuntu 11.04 x64","datacenter":"Falkenberg","managedhosting":"no","platform":"Xen","cost":{"amount":13.22,"currency":"EUR","timeperiod":"month"},"iplist":[{"ipaddress":"109.74.10.45","version":4,"cost":2,"currency":"EUR"}]},"debug":{"input":{"serverid":"xm3276891"}}}} \ No newline at end of file +{"response":{"status":{"code":200,"timestamp":"2012-02-10T11:11:05+01:00","text":"OK"},"server":{"serverid":"xm3276891","hostname":"glesys-s-6dd","description":"glesys-s-6dd","cpucores":1,"memorysize":512,"disksize":5,"transfer":50,"templatename":"Ubuntu 11.04 x64","datacenter":"Falkenberg","managedhosting":"no","platform":"Xen","cost":{"amount":13.22,"currency":"EUR","timeperiod":"month"},"iplist":[{"ipaddress":"109.74.10.45","version":4,"cost":2,"currency":"EUR"}], "state":"locked"},"debug":{"input":{"serverid":"xm3276891"}}}} \ No newline at end of file diff --git a/sandbox-providers/glesys/src/test/resources/server_limits.json b/labs/glesys/src/test/resources/server_limits.json similarity index 100% rename from sandbox-providers/glesys/src/test/resources/server_limits.json rename to labs/glesys/src/test/resources/server_limits.json diff --git a/sandbox-providers/glesys/src/test/resources/server_list.json b/labs/glesys/src/test/resources/server_list.json similarity index 100% rename from sandbox-providers/glesys/src/test/resources/server_list.json rename to labs/glesys/src/test/resources/server_list.json diff --git a/sandbox-providers/glesys/src/test/resources/server_noip.json b/labs/glesys/src/test/resources/server_noip.json similarity index 100% rename from sandbox-providers/glesys/src/test/resources/server_noip.json rename to labs/glesys/src/test/resources/server_noip.json diff --git a/sandbox-providers/glesys/src/test/resources/server_status.json b/labs/glesys/src/test/resources/server_status.json similarity index 100% rename from sandbox-providers/glesys/src/test/resources/server_status.json rename to labs/glesys/src/test/resources/server_status.json diff --git a/sandbox-providers/glesys/src/test/resources/server_templates.json b/labs/glesys/src/test/resources/server_templates.json similarity index 100% rename from sandbox-providers/glesys/src/test/resources/server_templates.json rename to labs/glesys/src/test/resources/server_templates.json diff --git a/labs/openstack-nova/pom.xml b/labs/openstack-nova/pom.xml index 6cf1725990..6ad9c82ab2 100644 --- a/labs/openstack-nova/pom.xml +++ b/labs/openstack-nova/pom.xml @@ -1,157 +1,157 @@ - - - - 4.0.0 - - org.jclouds - jclouds-project - 1.5.0-SNAPSHOT - ../../project/pom.xml - - org.jclouds.labs - openstack-nova - jcloud openstack-nova api - jclouds components to access an implementation of OpenStack Nova - bundle - - - - http://localhost:5000 - - 1.1 - - FIXME_IDENTITY - FIXME_CREDENTIALS - - - - - - - - org.jclouds.common - openstack-common - ${project.version} - - - org.jclouds - jclouds-compute - ${project.version} - - - org.jclouds - jclouds-core - ${project.version} - test-jar - test - - - org.jclouds.common - openstack-common - ${project.version} - test-jar - test - - - org.jclouds - jclouds-compute - ${project.version} - test-jar - test - - - org.jclouds.driver - jclouds-sshj - ${project.version} - test - - - org.jclouds.driver - jclouds-slf4j - ${project.version} - test - - - ch.qos.logback - logback-classic - 0.9.29 - test - - - - - - live - - - - org.apache.maven.plugins - maven-surefire-plugin - - - integration - integration-test - - test - - - - ${test.openstack-nova.endpoint} - ${test.openstack-nova.api-version} - ${test.openstack-nova.build-version} - ${test.openstack-nova.identity} - ${test.openstack-nova.credential} - ${test.openstack-nova.image-id} - ${test.openstack-nova.image.login-user} - ${test.openstack-nova.image.authenticate-sudo} - - - - - - - - - - - - - - org.apache.felix - maven-bundle-plugin - - - ${project.artifactId} - org.jclouds.openstack.nova.v1_1.*;version="${project.version}" - - org.jclouds.compute.internal;version="${project.version}", - org.jclouds.rest.internal;version="${project.version}", - org.jclouds.*;version="${project.version}", - * - - - - - - - - + + + + 4.0.0 + + org.jclouds + jclouds-project + 1.5.0-SNAPSHOT + ../../project/pom.xml + + org.jclouds.labs + openstack-nova + jcloud openstack-nova api + jclouds components to access an implementation of OpenStack Nova + bundle + + + + http://localhost:5000 + + 1.1 + + FIXME_IDENTITY + FIXME_CREDENTIALS + + + + + + + + org.jclouds.common + openstack-common + ${project.version} + + + org.jclouds + jclouds-compute + ${project.version} + + + org.jclouds + jclouds-core + ${project.version} + test-jar + test + + + org.jclouds.common + openstack-common + ${project.version} + test-jar + test + + + org.jclouds + jclouds-compute + ${project.version} + test-jar + test + + + org.jclouds.driver + jclouds-sshj + ${project.version} + test + + + org.jclouds.driver + jclouds-slf4j + ${project.version} + test + + + ch.qos.logback + logback-classic + 0.9.29 + test + + + + + + live + + + + org.apache.maven.plugins + maven-surefire-plugin + + + integration + integration-test + + test + + + + ${test.openstack-nova.endpoint} + ${test.openstack-nova.api-version} + ${test.openstack-nova.build-version} + ${test.openstack-nova.identity} + ${test.openstack-nova.credential} + ${test.openstack-nova.image-id} + ${test.openstack-nova.image.login-user} + ${test.openstack-nova.image.authenticate-sudo} + + + + + + + + + + + + + + org.apache.felix + maven-bundle-plugin + + + ${project.artifactId} + org.jclouds.openstack.nova.v1_1*;version="${project.version}" + + org.jclouds.compute.internal;version="${project.version}", + org.jclouds.rest.internal;version="${project.version}", + org.jclouds*;version="${project.version}", + * + + + + + + + + diff --git a/labs/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/NovaAsyncClient.java b/labs/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/NovaAsyncClient.java index d86c1fb03e..cd8dd41502 100644 --- a/labs/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/NovaAsyncClient.java +++ b/labs/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/NovaAsyncClient.java @@ -23,6 +23,7 @@ import java.util.Set; import org.jclouds.javax.annotation.Nullable; import org.jclouds.location.Region; import org.jclouds.location.functions.RegionToEndpointOrProviderIfNull; +import org.jclouds.openstack.nova.v1_1.features.FlavorClient; import org.jclouds.openstack.nova.v1_1.features.ServerAsyncClient; import org.jclouds.rest.annotations.Delegate; import org.jclouds.rest.annotations.EndpointParam; @@ -53,5 +54,12 @@ public interface NovaAsyncClient { @Delegate ServerAsyncClient getServerClientForRegion( @EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region); + + /** + * Provides asynchronous access to Flavor features. + */ + @Delegate + FlavorClient getFlavorClientForRegion( + @EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region); } diff --git a/labs/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/NovaClient.java b/labs/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/NovaClient.java index 2f0d14086a..8ac771a4d2 100644 --- a/labs/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/NovaClient.java +++ b/labs/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/NovaClient.java @@ -25,6 +25,7 @@ import org.jclouds.concurrent.Timeout; import org.jclouds.javax.annotation.Nullable; import org.jclouds.location.Region; import org.jclouds.location.functions.RegionToEndpointOrProviderIfNull; +import org.jclouds.openstack.nova.v1_1.features.FlavorClient; import org.jclouds.openstack.nova.v1_1.features.ServerClient; import org.jclouds.rest.annotations.Delegate; import org.jclouds.rest.annotations.EndpointParam; @@ -56,4 +57,11 @@ public interface NovaClient { ServerClient getServerClientForRegion( @EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region); + /** + * Provides synchronous access to Flavor features. + */ + @Delegate + FlavorClient getFlavorClientForRegion( + @EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region); + } diff --git a/labs/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/config/NovaRestClientModule.java b/labs/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/config/NovaRestClientModule.java index 50179ebd29..6e3b72e097 100644 --- a/labs/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/config/NovaRestClientModule.java +++ b/labs/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/config/NovaRestClientModule.java @@ -28,6 +28,8 @@ import org.jclouds.http.annotation.ServerError; import org.jclouds.openstack.keystone.v2_0.config.KeystoneAuthenticationModule; import org.jclouds.openstack.nova.v1_1.NovaAsyncClient; import org.jclouds.openstack.nova.v1_1.NovaClient; +import org.jclouds.openstack.nova.v1_1.features.FlavorAsyncClient; +import org.jclouds.openstack.nova.v1_1.features.FlavorClient; import org.jclouds.openstack.nova.v1_1.features.ServerAsyncClient; import org.jclouds.openstack.nova.v1_1.features.ServerClient; import org.jclouds.openstack.nova.v1_1.handlers.NovaErrorHandler; @@ -47,6 +49,7 @@ public class NovaRestClientModule extends RestClientModule, Class> DELEGATE_MAP = ImmutableMap., Class> builder()// .put(ServerClient.class, ServerAsyncClient.class)// + .put(FlavorClient.class, FlavorAsyncClient.class) .build(); public NovaRestClientModule() { diff --git a/labs/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/domain/Flavor.java b/labs/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/domain/Flavor.java new file mode 100644 index 0000000000..a9d97767aa --- /dev/null +++ b/labs/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/domain/Flavor.java @@ -0,0 +1,139 @@ +/** + * 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.openstack.nova.v1_1.domain; + +import static com.google.common.base.Objects.toStringHelper; + +import java.util.Set; + +import org.jclouds.openstack.domain.Link; +import org.jclouds.openstack.domain.Resource; + +/** + * A flavor is an available hardware configuration for a server. Each flavor has + * a unique combination of disk space and memory capacity. + * + * @author Jeremy Daggett + * @see + */ +public class Flavor extends Resource { + public static Builder builder() { + return new Builder(); + } + + public Builder toBuilder() { + return builder().fromFlavor(this); + } + + public static class Builder extends Resource.Builder { + + private int ram; + private int disk; + private int vcpus; + + public Builder ram(int ram) { + this.ram = ram; + return this; + } + + public Builder disk(int disk) { + this.disk = disk; + return this; + } + + public Builder vcpus(int vcpus) { + this.vcpus = vcpus; + return this; + } + + public Flavor build() { + return new Flavor(id, name, links, ram, disk, vcpus); + } + + public Builder fromFlavor(Flavor in) { + return fromResource(in).ram(in.getRam()).disk(in.getDisk()).vcpus(in.getVcpus()); + } + + /** + * {@inheritDoc} + */ + @Override + public Builder id(String id) { + return Builder.class.cast(super.id(id)); + } + + /** + * {@inheritDoc} + */ + @Override + public Builder name(String name) { + return Builder.class.cast(super.name(name)); + } + + /** + * {@inheritDoc} + */ + @Override + public Builder links(Set links) { + return Builder.class.cast(super.links(links)); + } + + /** + * {@inheritDoc} + */ + @Override + public Builder fromResource(Resource in) { + return Builder.class.cast(super.fromResource(in)); + } + } + + private int ram; + private int disk; + private int vcpus; + + protected Flavor(String id, String name, Set links, int ram, int disk, + int vcpus) { + super(id, name, links); + this.ram = ram; + this.disk = disk; + this.vcpus = vcpus; + } + + public int getRam() { + return this.ram; + } + + public int getDisk() { + return this.disk; + } + + public int getVcpus() { + return this.vcpus; + } + + @Override + public String toString() { + return toStringHelper("").add("id", id).add("name", name) + .add("links", links).add("ram", ram).add("disk", disk) + .add("vcpus", vcpus).toString(); + } + +} diff --git a/labs/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/features/FlavorAsyncClient.java b/labs/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/features/FlavorAsyncClient.java new file mode 100644 index 0000000000..dccc23d220 --- /dev/null +++ b/labs/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/features/FlavorAsyncClient.java @@ -0,0 +1,85 @@ +/** + * 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.openstack.nova.v1_1.features; + +import java.util.Set; + +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.core.MediaType; + +import org.jclouds.openstack.domain.Resource; +import org.jclouds.openstack.filters.AuthenticateRequest; +import org.jclouds.openstack.nova.v1_1.domain.Flavor; +import org.jclouds.rest.annotations.ExceptionParser; +import org.jclouds.rest.annotations.RequestFilters; +import org.jclouds.rest.annotations.SelectJson; +import org.jclouds.rest.annotations.SkipEncoding; +import org.jclouds.rest.functions.ReturnEmptySetOnNotFoundOr404; +import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404; + +import com.google.common.util.concurrent.ListenableFuture; + +/** + * Provides asynchronous access to Flavors via their REST API. + *

+ * + * @see FlavorClient + * @see + * @author Jeremy Daggett + * TODO: Need a ListFlavorOptions class minDisk=minDiskInGB& minRam=minRamInMB& marker=markerID&limit=int + */ +@SkipEncoding({ '/', '=' }) +@RequestFilters(AuthenticateRequest.class) +public interface FlavorAsyncClient { + + /** + * @see FlavorClient#listFlavors + */ + @GET + @SelectJson("flavors") + @Consumes(MediaType.APPLICATION_JSON) + @Path("/flavors") + @ExceptionParser(ReturnEmptySetOnNotFoundOr404.class) + ListenableFuture> listFlavors(); + + /** + * @see FlavorClient#listFlavorsInDetail + */ + @GET + @SelectJson("flavors") + @Consumes(MediaType.APPLICATION_JSON) + @Path("/flavors/detail") + @ExceptionParser(ReturnEmptySetOnNotFoundOr404.class) + ListenableFuture> listFlavorsInDetail(); + + /** + * @see FlavorClient#getFlavor + */ + @GET + @SelectJson("flavor") + @Consumes(MediaType.APPLICATION_JSON) + @Path("/flavors/{id}") + @ExceptionParser(ReturnNullOnNotFoundOr404.class) + ListenableFuture getFlavor(@PathParam("id") String id); + +} diff --git a/labs/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/features/FlavorClient.java b/labs/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/features/FlavorClient.java new file mode 100644 index 0000000000..3fb7059934 --- /dev/null +++ b/labs/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/features/FlavorClient.java @@ -0,0 +1,66 @@ +/** + * 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.openstack.nova.v1_1.features; + +import java.util.Set; +import java.util.concurrent.TimeUnit; + +import org.jclouds.concurrent.Timeout; +import org.jclouds.openstack.domain.Resource; +import org.jclouds.openstack.filters.AuthenticateRequest; +import org.jclouds.openstack.nova.v1_1.domain.Flavor; +import org.jclouds.rest.annotations.RequestFilters; +import org.jclouds.rest.annotations.SkipEncoding; + +/** + * Provides asynchronous access to Flavors via their REST API. + *

+ * + * @see FlavorClient + * @see + * @author Jeremy Daggett + */ +@Timeout(duration = 30, timeUnit = TimeUnit.SECONDS) +public interface FlavorClient { + + /** + * List all flavors (IDs, names, links) + * + * @return all flavors (IDs, names, links) + */ + Set listFlavors(); + + /** + * List all flavors (all details) + * + * @return all flavors (all details) + */ + Set listFlavorsInDetail(); + + /** + * List details of the specified flavor + * + * @param id + * id of the flavor + * @return flavorr or null if not found + */ + Flavor getFlavor(String id); + +} diff --git a/labs/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/features/FlavorClientExpectTest.java b/labs/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/features/FlavorClientExpectTest.java new file mode 100644 index 0000000000..3073a2699d --- /dev/null +++ b/labs/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/features/FlavorClientExpectTest.java @@ -0,0 +1,76 @@ +package org.jclouds.openstack.nova.v1_1.features; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; + +import java.net.URI; + +import org.jclouds.http.HttpRequest; +import org.jclouds.http.HttpResponse; +import org.jclouds.openstack.nova.v1_1.NovaClient; +import org.jclouds.openstack.nova.v1_1.internal.BaseNovaRestClientExpectTest; +import org.jclouds.openstack.nova.v1_1.parse.ParseFlavorListTest; +import org.jclouds.openstack.nova.v1_1.parse.ParseFlavorTest; +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableMultimap; +import com.google.common.collect.ImmutableSet; + +/** + * Tests annotation parsing of {@code FlavorAsyncClient} + * + * @author Jeremy Daggett + */ +@Test(groups = "unit", testName = "FlavorAsyncClientTest") +public class FlavorClientExpectTest extends BaseNovaRestClientExpectTest { + + public void testListFlavorsWhenResponseIs2xx() throws Exception { + HttpRequest listServers = HttpRequest.builder().method("GET").endpoint( + URI.create("https://compute.north.host/v1.1/3456/flavors")).headers( + ImmutableMultimap. builder().put("Accept", "application/json").put("X-Auth-Token", + authToken).build()).build(); + + HttpResponse listFlavorsResponse = HttpResponse.builder().statusCode(200).payload( + payloadFromResource("/flavor_list.json")).build(); + + NovaClient clientWhenFlavorsExist = requestsSendResponses(keystoneAuthWithAccessKeyAndSecretKey, + responseWithKeystoneAccess, listServers, listFlavorsResponse); + + assertEquals(clientWhenFlavorsExist.getConfiguredRegions(), ImmutableSet.of("North")); + + assertEquals(clientWhenFlavorsExist.getFlavorClientForRegion("North").listFlavors().toString(), + new ParseFlavorListTest().expected().toString()); + } + + public void testListFlavorsWhenReponseIs404IsEmpty() throws Exception { + HttpRequest listFlavors = HttpRequest.builder().method("GET").endpoint( + URI.create("https://compute.north.host/v1.1/3456/flavors")).headers( + ImmutableMultimap. builder().put("Accept", "application/json").put("X-Auth-Token", + authToken).build()).build(); + + HttpResponse listFlavorsResponse = HttpResponse.builder().statusCode(404).build(); + + NovaClient clientWhenNoServersExist = requestsSendResponses(keystoneAuthWithAccessKeyAndSecretKey, + responseWithKeystoneAccess, listFlavors, listFlavorsResponse); + + assertTrue(clientWhenNoServersExist.getFlavorClientForRegion("North").listFlavors().isEmpty()); + } + + // TODO: gson deserializer for Multimap + public void testGetFlavorWhenResponseIs2xx() throws Exception { + HttpRequest getFlavor = HttpRequest.builder().method("GET").endpoint( + URI.create("https://compute.north.host/v1.1/3456/flavors/foo")).headers( + ImmutableMultimap. builder().put("Accept", "application/json").put("X-Auth-Token", + authToken).build()).build(); + + HttpResponse getFlavorResponse = HttpResponse.builder().statusCode(200).payload( + payloadFromResource("/flavor_details.json")).build(); + + NovaClient clientWhenServersExist = requestsSendResponses(keystoneAuthWithAccessKeyAndSecretKey, + responseWithKeystoneAccess, getFlavor, getFlavorResponse); + + assertEquals(clientWhenServersExist.getFlavorClientForRegion("North").getFlavor("foo").toString(), + new ParseFlavorTest().expected().toString()); + } + +} diff --git a/labs/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/features/FlavorClientLiveTest.java b/labs/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/features/FlavorClientLiveTest.java new file mode 100644 index 0000000000..0aa307116a --- /dev/null +++ b/labs/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/features/FlavorClientLiveTest.java @@ -0,0 +1,56 @@ +/** + * 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.openstack.nova.v1_1.features; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; + +import java.util.Set; + +import org.jclouds.openstack.domain.Resource; +import org.jclouds.openstack.nova.v1_1.domain.Flavor; +import org.jclouds.openstack.nova.v1_1.internal.BaseNovaClientLiveTest; +import org.testng.annotations.Test; + +/** + * Tests behavior of {@code FlavorClient} + * + * @author Jeremy Daggett + */ +@Test(groups = "live", testName = "FlavorClientLiveTest") +public class FlavorClientLiveTest extends BaseNovaClientLiveTest { + + + @Test + public void testListFlavors() throws Exception { + for (String regionId : context.getApi().getConfiguredRegions()) { + FlavorClient client = context.getApi().getFlavorClientForRegion(regionId); + Set response = client.listFlavors(); + assert null != response; + assertTrue(response.size() >= 0); + for (Resource flavor : response) { + Flavor newDetails = client.getFlavor(flavor.getId()); + assertEquals(newDetails.getId(), flavor.getId()); + assertEquals(newDetails.getName(), flavor.getName()); + assertEquals(newDetails.getLinks(), flavor.getLinks()); + } + } + } + +} diff --git a/labs/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/parse/ParseFlavorListTest.java b/labs/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/parse/ParseFlavorListTest.java new file mode 100644 index 0000000000..eb78746d73 --- /dev/null +++ b/labs/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/parse/ParseFlavorListTest.java @@ -0,0 +1,87 @@ +/** + * 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.openstack.nova.v1_1.parse; + +import java.net.URI; +import java.util.Set; + +import javax.ws.rs.Consumes; +import javax.ws.rs.core.MediaType; + +import org.jclouds.json.BaseSetParserTest; +import org.jclouds.json.config.GsonModule; +import org.jclouds.openstack.domain.Link; +import org.jclouds.openstack.domain.Resource; +import org.jclouds.openstack.domain.Link.Relation; +import org.jclouds.openstack.nova.v1_1.config.NovaParserModule; +import org.jclouds.rest.annotations.SelectJson; +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableSet; +import com.google.inject.Guice; +import com.google.inject.Injector; + +/** + * + * @author Jeremy Daggett + */ +@Test(groups = "unit", testName = "ParseFlavorListTest") +public class ParseFlavorListTest extends BaseSetParserTest { + + @Override + public String resource() { + return "/flavor_list.json"; + } + + @Override + @SelectJson("flavors") + @Consumes(MediaType.APPLICATION_JSON) + public Set expected() { + return ImmutableSet + .of(Resource + .builder() + .id("52415800-8b69-11e0-9b19-734f1195ff37") + .name("256 MB Server") + .links( + Link.create( + Relation.SELF, + URI.create("http://servers.api.openstack.org/v1.1/1234/flavors/52415800-8b69-11e0-9b19-734f1195ff37")), + Link.create( + Relation.BOOKMARK, + URI.create("http://servers.api.openstack.org/1234/flavors/52415800-8b69-11e0-9b19-734f1195ff37"))) + .build(), + Resource + .builder() + .id("52415800-8b69-11e0-9b19-734f216543fd") + .name("512 MB Server") + .links( + Link.create( + Relation.SELF, + URI.create("http://servers.api.openstack.org/v1.1/1234/flavors/52415800-8b69-11e0-9b19-734f216543fd")), + Link.create( + Relation.BOOKMARK, + URI.create("http://servers.api.openstack.org/1234/flavors/52415800-8b69-11e0-9b19-734f216543fd"))) + .build()); + } + + protected Injector injector() { + return Guice.createInjector(new NovaParserModule(), new GsonModule()); + } + +} diff --git a/labs/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/parse/ParseFlavorTest.java b/labs/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/parse/ParseFlavorTest.java new file mode 100644 index 0000000000..0ac3393673 --- /dev/null +++ b/labs/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/parse/ParseFlavorTest.java @@ -0,0 +1,73 @@ +/** + * 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.openstack.nova.v1_1.parse; + +import java.net.URI; + +import javax.ws.rs.Consumes; +import javax.ws.rs.core.MediaType; + +import org.jclouds.json.BaseItemParserTest; +import org.jclouds.json.config.GsonModule; +import org.jclouds.openstack.domain.Link; +import org.jclouds.openstack.domain.Resource; +import org.jclouds.openstack.domain.Link.Relation; +import org.jclouds.openstack.nova.v1_1.config.NovaParserModule; +import org.jclouds.openstack.nova.v1_1.domain.Flavor; +import org.jclouds.rest.annotations.SelectJson; +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableSet; +import com.google.inject.Guice; +import com.google.inject.Injector; + +/** + * @author Jeremy Daggett + */ +@Test(groups = "unit", testName = "ParseFlavorTest") +public class ParseFlavorTest extends BaseItemParserTest { + + @Override + public String resource() { + return "/flavor_details.json"; + } + + @Override + @SelectJson("flavor") + @Consumes(MediaType.APPLICATION_JSON) + public Flavor expected() { + return Flavor + .builder() + .id("52415800-8b69-11e0-9b19-734f1195ff37") + .name("256 MB Server") + .links( + ImmutableSet.of( + Link.create( + Relation.SELF, + URI.create("http://servers.api.openstack.org/v1.1/1234/flavors/52415800-8b69-11e0-9b19-734f1195ff37")), + Link.create( + Relation.BOOKMARK, + URI.create("http://servers.api.openstack.org/1234/flavors/52415800-8b69-11e0-9b19-734f1195ff37")))) + .ram(256).disk(10).vcpus(1).build(); + } + + protected Injector injector() { + return Guice.createInjector(new NovaParserModule(), new GsonModule()); + } +} diff --git a/labs/openstack-nova/src/test/resources/flavor_details.json b/labs/openstack-nova/src/test/resources/flavor_details.json new file mode 100644 index 0000000000..b2a3556077 --- /dev/null +++ b/labs/openstack-nova/src/test/resources/flavor_details.json @@ -0,0 +1,19 @@ +{ + "flavor" : { + "id" : "52415800-8b69-11e0-9b19-734f1195ff37", + "name" : "256 MB Server", + "ram" : 256, + "disk" : 10, + "vcpus" : 1, + "links": [ + { + "rel" : "self", + "href" : "http://servers.api.openstack.org/v1.1/1234/flavors/52415800-8b69-11e0-9b19-734f1195ff37" + }, + { + "rel" : "bookmark", + "href" : "http://servers.api.openstack.org/1234/flavors/52415800-8b69-11e0-9b19-734f1195ff37" + } + ] + } +} \ No newline at end of file diff --git a/labs/openstack-nova/src/test/resources/flavor_list.json b/labs/openstack-nova/src/test/resources/flavor_list.json new file mode 100644 index 0000000000..1e4cdebebd --- /dev/null +++ b/labs/openstack-nova/src/test/resources/flavor_list.json @@ -0,0 +1,32 @@ +{ + "flavors": [ + { + "id": "52415800-8b69-11e0-9b19-734f1195ff37", + "name": "256 MB Server", + "links": [ + { + "rel": "self", + "href": "http://servers.api.openstack.org/v1.1/1234/flavors/52415800-8b69-11e0-9b19-734f1195ff37" + }, + { + "rel": "bookmark", + "href": "http://servers.api.openstack.org/1234/flavors/52415800-8b69-11e0-9b19-734f1195ff37" + } + ] + }, + { + "id": "52415800-8b69-11e0-9b19-734f216543fd", + "name": "512 MB Server", + "links": [ + { + "rel": "self", + "href": "http://servers.api.openstack.org/v1.1/1234/flavors/52415800-8b69-11e0-9b19-734f216543fd" + }, + { + "rel": "bookmark", + "href": "http://servers.api.openstack.org/1234/flavors/52415800-8b69-11e0-9b19-734f216543fd" + } + ] + } + ] +} \ No newline at end of file diff --git a/labs/pom.xml b/labs/pom.xml index 177d38778b..62213128e1 100644 --- a/labs/pom.xml +++ b/labs/pom.xml @@ -35,5 +35,6 @@ openstack-nova virtualbox vcloud-director + glesys diff --git a/labs/vcloud-director/pom.xml b/labs/vcloud-director/pom.xml index b55770a777..5cf8bca690 100644 --- a/labs/vcloud-director/pom.xml +++ b/labs/vcloud-director/pom.xml @@ -1,143 +1,153 @@ - - - - 4.0.0 - - org.jclouds - jclouds-project - 1.5.0-SNAPSHOT - ../../project/pom.xml - - org.jclouds.labs - vcloud-director - jcloud vcloud-director api - jclouds components to access an implementation of VMware vCloud Director 1.5+ - bundle - - - https://vcloudbeta.bluelock.com/api - 1.5 - 1.5.0.464915 - FIXME_USERNAME_WHICH_MIGHT_BE_EMAIL@JClouds - FIXME_PASSWORD - - - - - - - - org.jclouds - jclouds-compute - ${project.version} - - - org.jclouds - jclouds-core - ${project.version} - test-jar - test - - - org.jclouds - jclouds-compute - ${project.version} - test-jar - test - - - org.jclouds.driver - jclouds-sshj - ${project.version} - test - - - org.jclouds.driver - jclouds-slf4j - ${project.version} - test - - - ch.qos.logback - logback-classic - 0.9.29 - test - - - - - - live - - - - org.apache.maven.plugins - maven-surefire-plugin - - - integration - integration-test - - test - - - - ${test.vcloud-director.endpoint} - ${test.vcloud-director.api-version} - ${test.vcloud-director.build-version} - ${test.vcloud-director.identity} - ${test.vcloud-director.credential} - ${test.vcloud-director.image-id} - ${test.vcloud-director.image.login-user} - ${test.vcloud-director.image.authenticate-sudo} - - - - - - - - - - - - - - org.apache.felix - maven-bundle-plugin - - - ${project.artifactId} - org.jclouds.vcloud.director.v1_5.*;version="${project.version}" - - org.jclouds.compute.internal;version="${project.version}", - org.jclouds.rest.internal;version="${project.version}", - org.jclouds.*;version="${project.version}", - * - - - - - - - - + + + + 4.0.0 + + org.jclouds + jclouds-project + 1.5.0-SNAPSHOT + ../../project/pom.xml + + org.jclouds.labs + vcloud-director + jcloud vcloud-director api + jclouds components to access an implementation of VMware vCloud Director 1.5+ + bundle + + + https://vcloudbeta.bluelock.com/api + 1.5 + 1.5.0.464915 + FIXME_USERNAME_WHICH_MIGHT_BE_EMAIL@JClouds + FIXME_PASSWORD + + + + + + + + + + + + + org.jclouds + jclouds-compute + ${project.version} + + + org.jclouds + jclouds-core + ${project.version} + test-jar + test + + + org.jclouds + jclouds-compute + ${project.version} + test-jar + test + + + org.jclouds.driver + jclouds-sshj + ${project.version} + test + + + org.jclouds.driver + jclouds-log4j + ${project.version} + test + + + ch.qos.logback + logback-classic + 0.9.29 + test + + + + + + live + + + + org.apache.maven.plugins + maven-surefire-plugin + + + integration + integration-test + + test + + + + ${test.vcloud-director.endpoint} + ${test.vcloud-director.api-version} + ${test.vcloud-director.build-version} + ${test.vcloud-director.identity} + ${test.vcloud-director.credential} + ${test.vcloud-director.image-id} + ${test.vcloud-director.image.login-user} + ${test.vcloud-director.image.authenticate-sudo} + ${test.vcloud-director.catalog-name} + ${test.vcloud-director.media-id} + ${test.vcloud-director.vapptemplate-id} + ${test.vcloud-director.network-id} + ${test.vcloud-director.vdc-id} + + + + + + + + + + + + + + org.apache.felix + maven-bundle-plugin + + + ${project.artifactId} + org.jclouds.vcloud.director.v1_5*;version="${project.version}" + + org.jclouds.compute.internal;version="${project.version}", + org.jclouds.rest.internal;version="${project.version}", + org.jclouds*;version="${project.version}", + * + + + + + + + + diff --git a/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/VCloudDirectorAsyncClient.java b/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/VCloudDirectorAsyncClient.java index 9eb3e15dc4..d52451b1b9 100644 --- a/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/VCloudDirectorAsyncClient.java +++ b/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/VCloudDirectorAsyncClient.java @@ -43,26 +43,32 @@ public interface VCloudDirectorAsyncClient { Session getCurrentSession(); /** - * @return asynchronous access to Org features + * @return asynchronous access to {@link Org} features */ @Delegate OrgAsyncClient getOrgClient(); /** - * @return asynchronous access to Task features + * @return asynchronous access to {@link Task} features */ @Delegate TaskAsyncClient getTaskClient(); /** - * @return asynchronous access to Network features + * @return asynchronous access to {@link Network} features */ @Delegate NetworkAsyncClient getNetworkClient(); /** - * @return asynchronous access to Catalog features + * @return asynchronous access to {@link Catalog} features */ @Delegate CatalogAsyncClient getCatalogClient(); + + /** + * @return asynchronous access to {@link Media} features + */ + @Delegate + CatalogAsyncClient getMediaClient(); } diff --git a/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/VCloudDirectorClient.java b/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/VCloudDirectorClient.java index 4ac6d277b0..096e0737c5 100644 --- a/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/VCloudDirectorClient.java +++ b/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/VCloudDirectorClient.java @@ -24,6 +24,7 @@ import org.jclouds.concurrent.Timeout; import org.jclouds.rest.annotations.Delegate; import org.jclouds.vcloud.director.v1_5.domain.Session; import org.jclouds.vcloud.director.v1_5.features.CatalogClient; +import org.jclouds.vcloud.director.v1_5.features.MediaClient; import org.jclouds.vcloud.director.v1_5.features.NetworkClient; import org.jclouds.vcloud.director.v1_5.features.OrgClient; import org.jclouds.vcloud.director.v1_5.features.TaskClient; @@ -59,7 +60,7 @@ public interface VCloudDirectorClient { TaskClient getTaskClient(); /** - * @return synchronous access to Network features + * @return synchronous access to {@link Network} features */ @Delegate NetworkClient getNetworkClient(); @@ -70,4 +71,9 @@ public interface VCloudDirectorClient { @Delegate CatalogClient getCatalogClient(); + /** + * @return synchronous access to {@link Media} features + */ + @Delegate + MediaClient getMediaClient(); } diff --git a/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/VCloudDirectorMediaType.java b/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/VCloudDirectorMediaType.java index 8a24111ebc..4fdf6a892d 100644 --- a/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/VCloudDirectorMediaType.java +++ b/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/VCloudDirectorMediaType.java @@ -18,6 +18,9 @@ */ package org.jclouds.vcloud.director.v1_5; +import java.util.Arrays; +import java.util.List; + /** * Resource Types used in VCloud. * @@ -47,6 +50,8 @@ public class VCloudDirectorMediaType { public static final String TASKS_LIST = "application/vnd.vmware.vcloud.tasksList+xml"; public static final String TASK = "application/vnd.vmware.vcloud.task+xml"; + + public static final String NETWORK = "application/vnd.vmware.vcloud.network+xml"; public static final String ORG_NETWORK = "application/vnd.vmware.vcloud.orgNetwork+xml"; @@ -60,4 +65,18 @@ public class VCloudDirectorMediaType { public static final String PROPERTY = "application/vnd.vmware.vcloud.property+xml"; + public static final String MEDIA = "application/vnd.vmware.vcloud.media+xml"; + + public static final String OWNER = "application/vnd.vmware.vcloud.owner+xml"; + + public static final String VDC = "application/vnd.vmware.vcloud.vdc+xml"; + + public static final String ADMIN_USER = "application/vnd.vmware.admin.user+xml"; + + public static final List ALL = Arrays.asList( + SESSION, ERROR, ORG_LIST, METADATA, METADATA_ENTRY, + METADATA_VALUE, ORG, TASKS_LIST, TASK, NETWORK, ORG_NETWORK, + CATALOG, CATALOG_ITEM, CATALOG_ITEMS, CATALOGS_LIST, PROPERTY, + MEDIA, OWNER, VDC, ADMIN_USER + ); } diff --git a/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/config/VCloudDirectorRestClientModule.java b/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/config/VCloudDirectorRestClientModule.java index 522137d648..104fb3f359 100644 --- a/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/config/VCloudDirectorRestClientModule.java +++ b/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/config/VCloudDirectorRestClientModule.java @@ -44,6 +44,8 @@ import org.jclouds.vcloud.director.v1_5.domain.Session; import org.jclouds.vcloud.director.v1_5.domain.SessionWithToken; import org.jclouds.vcloud.director.v1_5.features.CatalogAsyncClient; import org.jclouds.vcloud.director.v1_5.features.CatalogClient; +import org.jclouds.vcloud.director.v1_5.features.MediaAsyncClient; +import org.jclouds.vcloud.director.v1_5.features.MediaClient; import org.jclouds.vcloud.director.v1_5.features.NetworkAsyncClient; import org.jclouds.vcloud.director.v1_5.features.NetworkClient; import org.jclouds.vcloud.director.v1_5.features.OrgAsyncClient; @@ -80,6 +82,7 @@ public class VCloudDirectorRestClientModule extends RestClientModule> extends ResourceType { /** * {@inheritDoc} */ + @SuppressWarnings("unchecked") @Override public Builder fromResourceType(ResourceType in) { return Builder.class.cast(super.fromResourceType(in)); @@ -161,7 +162,7 @@ public class EntityType> extends ResourceType { private TasksInProgress tasksInProgress; @XmlAttribute private String id; - @XmlAttribute + @XmlAttribute(required = true) private String name; protected EntityType(URI href, String name) { @@ -215,6 +216,10 @@ public class EntityType> extends ResourceType { public String getName() { return name; } + + public void setName(String name) { + this.name = name; + } @Override public boolean equals(Object o) { diff --git a/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/domain/File.java b/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/domain/File.java new file mode 100644 index 0000000000..ea9369ecb1 --- /dev/null +++ b/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/domain/File.java @@ -0,0 +1,300 @@ +/** + * 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.vcloud.director.v1_5.domain; + +import static com.google.common.base.Objects.equal; +import static com.google.common.base.Preconditions.checkNotNull; + +import java.net.URI; +import java.util.Set; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlAttribute; +import javax.xml.bind.annotation.XmlSchemaType; +import javax.xml.bind.annotation.XmlType; +import javax.xml.bind.annotation.adapters.NormalizedStringAdapter; +import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; + +import com.google.common.base.Objects; +import com.google.common.collect.Sets; + + +/** + * + * Represents a file to be transferred (uploaded or downloaded). + * + * + *

Java class for File complex type. + * + *

The following schema fragment specifies the expected content contained within this class. + * + *

+ * <complexType name="File">
+ *   <complexContent>
+ *     <extension base="{http://www.vmware.com/vcloud/v1.5}EntityType">
+ *       <attribute name="size" type="{http://www.w3.org/2001/XMLSchema}long" />
+ *       <attribute name="bytesTransferred" type="{http://www.w3.org/2001/XMLSchema}long" />
+ *       <attribute name="checksum" type="{http://www.w3.org/2001/XMLSchema}normalizedString" />
+ *       <anyAttribute processContents='lax' namespace='##other'/>
+ *     </extension>
+ *   </complexContent>
+ * </complexType>
+ * 
+ * + * + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "File") +public class File + extends EntityType + +{ + @SuppressWarnings("unchecked") + public static Builder builder() { + return new Builder(); + } + + public Builder toBuilder() { + return new Builder().fromFile(this); + } + + public static class Builder extends EntityType.Builder { + + private Long size; + private Long bytesTransferred; + private String checksum; + + /** + * @see File#getSize() + */ + public Builder size(Long size) { + this.size = size; + return this; + } + + /** + * @see File#getBytesTransferred() + */ + public Builder bytesTransferred(Long bytesTransferred) { + this.bytesTransferred = bytesTransferred; + return this; + } + + /** + * @see File#getChecksum() + */ + public Builder checksum(String checksum) { + this.checksum = checksum; + return this; + } + + + public File build() { + File file = new File(); + file.setSize(size); + file.setBytesTransferred(bytesTransferred); + file.setChecksum(checksum); + return file; + } + + + /** + * @see EntityType#getId() + */ + @Override + public Builder id(String id) { + this.id = id; + return this; + } + + /** + * @see EntityType#getTasksInProgress() + */ + @Override + public Builder tasksInProgress(TasksInProgress tasksInProgress) { + this.tasksInProgress = tasksInProgress; + return this; + } + + /** + * @see ReferenceType#getHref() + */ + @Override + public Builder href(URI href) { + this.href = href; + return this; + } + + /** + * @see ReferenceType#getType() + */ + @Override + public Builder type(String type) { + this.type = type; + return this; + } + + /** + * @see ReferenceType#getLinks() + */ + @Override + public Builder links(Set links) { + this.links = Sets.newLinkedHashSet(checkNotNull(links, "links")); + return this; + } + + /** + * @see ReferenceType#getLinks() + */ + @Override + public Builder link(Link link) { + this.links.add(checkNotNull(link, "link")); + return this; + } + + + @Override + public Builder fromEntityType(EntityType in) { + return Builder.class.cast(super.fromEntityType(in)); + } + public Builder fromFile(File in) { + return fromEntityType(in) + .size(in.getSize()) + .bytesTransferred(in.getBytesTransferred()) + .checksum(in.getChecksum()); + } + } + + private File() { + // For JAXB and builder use + } + + + + @XmlAttribute + protected Long size; + @XmlAttribute + protected Long bytesTransferred; + @XmlAttribute + @XmlJavaTypeAdapter(NormalizedStringAdapter.class) + @XmlSchemaType(name = "normalizedString") + protected String checksum; + + /** + * Gets the value of the size property. + * + * @return + * possible object is + * {@link Long } + * + */ + public Long getSize() { + return size; + } + + /** + * Sets the value of the size property. + * + * @param value + * allowed object is + * {@link Long } + * + */ + public void setSize(Long value) { + this.size = value; + } + + /** + * Gets the value of the bytesTransferred property. + * + * @return + * possible object is + * {@link Long } + * + */ + public Long getBytesTransferred() { + return bytesTransferred; + } + + /** + * Sets the value of the bytesTransferred property. + * + * @param value + * allowed object is + * {@link Long } + * + */ + public void setBytesTransferred(Long value) { + this.bytesTransferred = value; + } + + /** + * Gets the value of the checksum property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getChecksum() { + return checksum; + } + + /** + * Sets the value of the checksum property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setChecksum(String value) { + this.checksum = value; + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + File that = File.class.cast(o); + return equal(size, that.size) && + equal(bytesTransferred, that.bytesTransferred) && + equal(checksum, that.checksum); + } + + @Override + public int hashCode() { + return Objects.hashCode(size, + bytesTransferred, + checksum); + } + + @Override + public String toString() { + return Objects.toStringHelper("") + .add("size", size) + .add("bytesTransferred", bytesTransferred) + .add("checksum", checksum).toString(); + } + +} diff --git a/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/domain/FilesList.java b/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/domain/FilesList.java new file mode 100644 index 0000000000..6a196bde57 --- /dev/null +++ b/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/domain/FilesList.java @@ -0,0 +1,159 @@ +/** + * 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.vcloud.director.v1_5.domain; + +import static com.google.common.base.Objects.equal; + +import java.util.ArrayList; +import java.util.List; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlType; + +import com.google.common.base.Objects; + + +/** + * + * Represents a list of files to be transferred (uploaded + * or downloaded). + * + * + *

Java class for FilesList complex type. + * + *

The following schema fragment specifies the expected content contained within this class. + * + *

+ * <complexType name="FilesList">
+ *   <complexContent>
+ *     <extension base="{http://www.vmware.com/vcloud/v1.5}VCloudExtensibleType">
+ *       <sequence>
+ *         <element name="File" type="{http://www.vmware.com/vcloud/v1.5}FileType" maxOccurs="unbounded"/>
+ *       </sequence>
+ *       <anyAttribute processContents='lax' namespace='##other'/>
+ *     </extension>
+ *   </complexContent>
+ * </complexType>
+ * 
+ * + * + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "FilesList", propOrder = { + "files" +}) +public class FilesList { + public static Builder builder() { + return new Builder(); + } + + public Builder toBuilder() { + return new Builder().fromFilesList(this); + } + + public static class Builder { + + private List files; + + /** + * @see FilesList#getFiles() + */ + public Builder file(List file) { + this.files = file; + return this; + } + + + public FilesList build() { + FilesList filesList = new FilesList(files); + return filesList; + } + + + public Builder fromFilesList(FilesList in) { + return file(in.getFiles()); + } + } + + private FilesList() { + // For JAXB and builder use + } + + private FilesList(List files) { + this.files = files; + } + + + @XmlElement(name = "File", required = true) + protected List files; + + /** + * Gets the value of the file property. + * + *

+ * This accessor method returns a reference to the live list, + * not a snapshot. Therefore any modification you make to the + * returned list will be present inside the JAXB object. + * This is why there is not a set method for the file property. + * + *

+ * For example, to add a new item, do as follows: + *

+     *    getFile().add(newItem);
+     * 
+ * + * + *

+ * Objects of the following type(s) are allowed in the list + * {@link FileType } + * + * + */ + public List getFiles() { + if (files == null) { + files = new ArrayList(); + } + return this.files; + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + FilesList that = FilesList.class.cast(o); + return equal(files, that.files); + } + + @Override + public int hashCode() { + return Objects.hashCode(files); + } + + @Override + public String toString() { + return Objects.toStringHelper("") + .add("file", files).toString(); + } + +} diff --git a/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/domain/Link.java b/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/domain/Link.java index ed4d5de848..c56c8ed202 100644 --- a/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/domain/Link.java +++ b/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/domain/Link.java @@ -22,6 +22,8 @@ import static com.google.common.base.Objects.*; import static com.google.common.base.Preconditions.*; import java.net.URI; +import java.util.Arrays; +import java.util.List; import java.util.Map; import javax.xml.bind.annotation.XmlAttribute; @@ -40,6 +42,21 @@ import com.google.common.base.Objects.ToStringHelper; */ public class Link extends ReferenceType { + public static final class Rel { + public static final String UP = "up"; + public static final String DOWN = "down"; + public static final String EDIT = "edit"; + public static final String DELETE = "delete"; + public static final String ADD = "add"; + public static final String REMOVE = "remove"; + public static final String CATALOG_ITEM = "catalogItem"; + public static final String TASK_CANCEL = "task:cancel"; + + public static final List ALL = Arrays.asList( + UP, DOWN, EDIT, DELETE, ADD, REMOVE, CATALOG_ITEM, TASK_CANCEL + ); + } + @SuppressWarnings("unchecked") public static Builder builder() { return new Builder(); @@ -133,7 +150,7 @@ public class Link extends ReferenceType { } } - @XmlAttribute + @XmlAttribute(required = true) private String rel; private Link(URI href, String rel) { diff --git a/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/domain/Media.java b/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/domain/Media.java new file mode 100644 index 0000000000..5a26d952ef --- /dev/null +++ b/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/domain/Media.java @@ -0,0 +1,333 @@ +/** + * 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.vcloud.director.v1_5.domain; + +import static com.google.common.base.Objects.equal; +import static org.jclouds.vcloud.director.v1_5.VCloudDirectorConstants.VCLOUD_1_5_NS; + +import java.net.URI; +import java.util.Arrays; +import java.util.List; +import java.util.Set; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlAttribute; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; +import javax.xml.bind.annotation.XmlType; + +import com.google.common.base.Objects; + + +/** + * + * Represents a media. + * + * + *

Java class for Media complex type. + * + *

The following schema fragment specifies the expected content contained within this class. + * + *

+ * <complexType name="Media">
+ *   <complexContent>
+ *     <extension base="{http://www.vmware.com/vcloud/v1.5}ResourceEntityType">
+ *       <sequence>
+ *         <element name="Owner" type="{http://www.vmware.com/vcloud/v1.5}OwnerType" minOccurs="0"/>
+ *       </sequence>
+ *       <attribute name="imageType" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
+ *       <attribute name="size" use="required" type="{http://www.w3.org/2001/XMLSchema}long" />
+ *       <anyAttribute processContents='lax' namespace='##other'/>
+ *     </extension>
+ *   </complexContent>
+ * </complexType>
+ * 
+ * + * + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlRootElement(namespace = VCLOUD_1_5_NS, name = "Media") +@XmlType(propOrder = {"owner"}) +public class Media + extends ResourceEntityType + +{ + public static final class ImageType { + public static final String ISO = "iso"; + public static final String FLOPPY = "floppy"; + + public static final List ALL = Arrays.asList( + ISO, FLOPPY + ); + } + + @SuppressWarnings("unchecked") + public static Builder builder() { + return new Builder(); + } + + public Builder toBuilder() { + return new Builder().fromMedia(this); + } + + public static class Builder extends ResourceEntityType.Builder { + + private Owner owner; + private String imageType; + private long size; + + /** + * @see Media#getOwner() + */ + public Builder owner(Owner owner) { + this.owner = owner; + return this; + } + + /** + * @see Media#getImageType() + */ + public Builder imageType(String imageType) { + this.imageType = imageType; + return this; + } + + /** + * @see Media#getSize() + */ + public Builder size(long size) { + this.size = size; + return this; + } + + + public Media build() { + Media media = new Media(); + media.setOwner(owner); + media.setImageType(imageType); + media.setSize(size); + return media; + } + + /** + * @see ResourceEntityType#getFiles() + */ + public Builder files(FilesList files) { + super.files(files); + return this; + } + + /** + * @see ResourceEntityType#getStatus() + */ + public Builder status(Integer status) { + super.status(status); + return this; + } + + /** + * @see EntityType#getName() + */ + @Override + public Builder name(String name) { + super.name(name); + return this; + } + + /** + * @see EntityType#getDescription() + */ + @Override + public Builder description(String description) { + super.description(description); + return this; + } + + /** + * @see EntityType#getId() + */ + @Override + public Builder id(String id) { + super.id(id); + return this; + } + + /** + * @see EntityType#getTasksInProgress() + */ + @Override + public Builder tasksInProgress(TasksInProgress tasksInProgress) { + super.tasksInProgress(tasksInProgress); + return this; + } + + /** + * @see ReferenceType#getHref() + */ + @Override + public Builder href(URI href) { + super.href(href); + return this; + } + + /** + * @see ReferenceType#getType() + */ + @Override + public Builder type(String type) { + super.type(type); + return this; + } + + /** + * @see ReferenceType#getLinks() + */ + @Override + public Builder links(Set links) { + super.links(links); + return this; + } + + /** + * @see ReferenceType#getLinks() + */ + @Override + public Builder link(Link link) { + super.link(link); + return this; + } + + + @Override + public Builder fromResourceEntityType(ResourceEntityType in) { + return Builder.class.cast(super.fromResourceEntityType(in)); + } + public Builder fromMedia(Media in) { + return fromResourceEntityType(in) + .owner(in.getOwner()) + .imageType(in.getImageType()) + .size(in.getSize()); + } + } + + public Media() { + super(); + } + + @XmlElement(namespace = VCLOUD_1_5_NS, name = "Owner") + protected Owner owner; + @XmlAttribute(required = true) + protected String imageType; + @XmlAttribute(required = true) + protected long size; + + /** + * Gets the value of the owner property. + * + * @return + * possible object is + * {@link Owner } + * + */ + public Owner getOwner() { + return owner; + } + + /** + * Sets the value of the owner property. + * + * @param value + * allowed object is + * {@link Owner } + * + */ + public void setOwner(Owner value) { + this.owner = value; + } + + /** + * Gets the value of the imageType property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getImageType() { + return imageType; + } + + /** + * Sets the value of the imageType property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setImageType(String value) { + this.imageType = value; + } + + /** + * Gets the value of the size property. + * + */ + public long getSize() { + return size; + } + + /** + * Sets the value of the size property. + * + */ + public void setSize(long value) { + this.size = value; + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + Media that = Media.class.cast(o); + return equal(owner, that.owner) && + equal(imageType, that.imageType) && + equal(size, that.size); + } + + @Override + public int hashCode() { + return Objects.hashCode(owner, + imageType, + size); + } + + @Override + public String toString() { + return Objects.toStringHelper("") + .add("owner", owner) + .add("imageType", imageType) + .add("size", size).toString(); + } + +} diff --git a/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/domain/Metadata.java b/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/domain/Metadata.java index baee875246..2b59c1ae76 100644 --- a/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/domain/Metadata.java +++ b/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/domain/Metadata.java @@ -18,9 +18,9 @@ */ package org.jclouds.vcloud.director.v1_5.domain; -import static com.google.common.base.Objects.*; -import static com.google.common.base.Preconditions.*; -import static org.jclouds.vcloud.director.v1_5.VCloudDirectorConstants.*; +import static com.google.common.base.Objects.equal; +import static com.google.common.base.Preconditions.checkNotNull; +import static org.jclouds.vcloud.director.v1_5.VCloudDirectorConstants.VCLOUD_1_5_NS; import java.net.URI; import java.util.Set; @@ -29,7 +29,6 @@ import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; import org.jclouds.vcloud.director.v1_5.VCloudDirectorMediaType; -import org.jclouds.vcloud.director.v1_5.domain.MetadataEntry.Builder; import com.google.common.base.Objects; import com.google.common.base.Objects.ToStringHelper; @@ -65,21 +64,21 @@ public class Metadata extends ResourceType { private Set metadataEntries = Sets.newLinkedHashSet(); /** - * @see Metadata#getMetadata() + * @see Metadata#getMetadataEntries() */ - public Builder metadata(Set metadataEntries) { + public Builder entries(Set metadataEntries) { this.metadataEntries = Sets.newLinkedHashSet(checkNotNull(metadataEntries, "metadataEntries")); return this; } /** - * @see Metadata#getMetadata() + * @see Metadata#getMetadataEntries() */ public Builder entry(MetadataEntry metadataEntry) { metadataEntries.add(checkNotNull(metadataEntry, "metadataEntry")); return this; } - + @Override public Metadata build() { Metadata metadata = new Metadata(href, metadataEntries); @@ -125,7 +124,7 @@ public class Metadata extends ResourceType { } public Builder fromMetadata(Metadata in) { - return fromResourceType(in).metadata(in.getMetadata()); + return fromResourceType(in).entries(in.getMetadataEntries()); } /** @@ -149,7 +148,7 @@ public class Metadata extends ResourceType { @XmlElement(namespace = VCLOUD_1_5_NS, name = "MetadataEntry") private Set metadataEntries = Sets.newLinkedHashSet(); - public Set getMetadata() { + public Set getMetadataEntries() { return ImmutableSet.copyOf(metadataEntries); } diff --git a/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/domain/NetworkType.java b/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/domain/NetworkType.java new file mode 100644 index 0000000000..528a30f825 --- /dev/null +++ b/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/domain/NetworkType.java @@ -0,0 +1,197 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + *(Link.builder().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(Link.builder().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.vcloud.director.v1_5.domain; + +import static com.google.common.base.Objects.equal; +import static com.google.common.base.Preconditions.checkNotNull; +import static org.jclouds.vcloud.director.v1_5.VCloudDirectorConstants.VCLOUD_1_5_NS; + +import java.net.URI; +import java.util.Set; + +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +import com.google.common.base.Objects; +import com.google.common.base.Objects.ToStringHelper; +import com.google.common.collect.Sets; + +@XmlRootElement(namespace = VCLOUD_1_5_NS, name = "NetworkType") +public class NetworkType> extends EntityType { + + public static > Builder builder() { + return new Builder(); + } + + @Override + public Builder toBuilder() { + return new Builder().fromNetworkType(this); + } + + public static class Builder> extends EntityType.Builder { + + protected NetworkConfiguration networkConfiguration; + + /** + * @see NetworkType#getConfiguration() + */ + public Builder configuration(NetworkConfiguration networkConfiguration) { + this.networkConfiguration = networkConfiguration; + return this; + } + + @Override + public NetworkType build() { + NetworkType network = new NetworkType(href, name); + network.setConfiguration(networkConfiguration); + network.setDescription(description); + network.setId(id); + network.setType(type); + network.setLinks(links); + network.setTasksInProgress(tasksInProgress); + return network; + } + + /** + * @see EntityType#getName() + */ + @Override + public Builder name(String name) { + this.name = name; + return this; + } + + /** + * @see EntityType#getDescription() + */ + @Override + public Builder description(String description) { + this.description = description; + return this; + } + + /** + * @see EntityType#getId() + */ + @Override + public Builder id(String id) { + this.id = id; + return this; + } + + /** + * @see EntityType#getTasksInProgress() + */ + @Override + public Builder tasksInProgress(TasksInProgress tasksInProgress) { + this.tasksInProgress = tasksInProgress; + return this; + } + + /** + * @see ReferenceType#getHref() + */ + @Override + public Builder href(URI href) { + this.href = href; + return this; + } + + /** + * @see ReferenceType#getType() + */ + @Override + public Builder type(String type) { + this.type = type; + return this; + } + + /** + * @see ReferenceType#getLinks() + */ + @Override + public Builder links(Set links) { + this.links = Sets.newLinkedHashSet(checkNotNull(links, "links")); + return this; + } + + /** + * @see ReferenceType#getLinks() + */ + @Override + public Builder link(Link link) { + this.links.add(checkNotNull(link, "link")); + return this; + } + + /** + * {@inheritDoc} + */ + @SuppressWarnings("unchecked") + @Override + public Builder fromEntityType(EntityType in) { + return Builder.class.cast(super.fromEntityType(in)); + } + + public Builder fromNetworkType(NetworkType in) { + return fromEntityType(in).configuration(in.getConfiguration()); + } + } + + protected NetworkType() { + // For JAXB and builder use + } + + protected NetworkType(URI href, String name) { + super(href, name); + } + + @XmlElement(namespace = VCLOUD_1_5_NS, name = "Configuration") + private NetworkConfiguration networkConfiguration; + + /** + * @return optional configuration + */ + public NetworkConfiguration getConfiguration() { + return networkConfiguration; + } + + public void setConfiguration(NetworkConfiguration networkConfiguration) { + this.networkConfiguration = networkConfiguration; + } + + @Override + public boolean equals(Object o) { + if (!super.equals(o)) + return false; + NetworkType that = NetworkType.class.cast(o); + return super.equals(that) && equal(networkConfiguration, that.networkConfiguration); + } + + @Override + public int hashCode() { + return super.hashCode() + Objects.hashCode(networkConfiguration); + } + + @Override + public ToStringHelper string() { + return super.string().add("configuration", networkConfiguration); + } + +} diff --git a/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/domain/OrgNetwork.java b/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/domain/OrgNetwork.java index f2e72fac77..3e56987900 100644 --- a/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/domain/OrgNetwork.java +++ b/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/domain/OrgNetwork.java @@ -18,9 +18,9 @@ */ package org.jclouds.vcloud.director.v1_5.domain; -import static com.google.common.base.Objects.*; -import static com.google.common.base.Preconditions.*; -import static org.jclouds.vcloud.director.v1_5.VCloudDirectorConstants.*; +import static com.google.common.base.Objects.equal; +import static com.google.common.base.Preconditions.checkNotNull; +import static org.jclouds.vcloud.director.v1_5.VCloudDirectorConstants.VCLOUD_1_5_NS; import java.net.URI; import java.util.Set; @@ -33,7 +33,7 @@ import com.google.common.base.Objects.ToStringHelper; import com.google.common.collect.Sets; @XmlRootElement(namespace = VCLOUD_1_5_NS, name = "OrgNetwork") -public class OrgNetwork extends EntityType { +public class OrgNetwork extends NetworkType { @SuppressWarnings("unchecked") public static Builder builder() { @@ -45,20 +45,11 @@ public class OrgNetwork extends EntityType { return new Builder().fromOrgNetwork(this); } - public static class Builder extends EntityType.Builder { + public static class Builder extends NetworkType.Builder { - private NetworkConfiguration networkConfiguration; private ReferenceType networkPool; private IpAddresses allowedExternalIpAddresses; - /** - * @see OrgNetwork#getConfiguration() - */ - public Builder configuration(NetworkConfiguration networkConfiguration) { - this.networkConfiguration = networkConfiguration; - return this; - } - /** * @see OrgNetwork#getNetworkPool() */ @@ -88,6 +79,14 @@ public class OrgNetwork extends EntityType { network.setTasksInProgress(tasksInProgress); return network; } + + /** + * @see NetworkType#getConfiguration() + */ + public Builder configuration(NetworkConfiguration networkConfiguration) { + this.networkConfiguration = networkConfiguration; + return this; + } /** * @see EntityType#getName() @@ -181,24 +180,11 @@ public class OrgNetwork extends EntityType { super(href, name); } - @XmlElement(namespace = VCLOUD_1_5_NS, name = "Configuration") - private NetworkConfiguration networkConfiguration; @XmlElement(namespace = VCLOUD_1_5_NS, name = "NetworkPool") private ReferenceType networkPool; @XmlElement(namespace = VCLOUD_1_5_NS, name = "AllowedExternalIpAddresses") private IpAddresses allowedExternalIpAddresses; - /** - * @return optional configuration - */ - public NetworkConfiguration getConfiguration() { - return networkConfiguration; - } - - public void setConfiguration(NetworkConfiguration networkConfiguration) { - this.networkConfiguration = networkConfiguration; - } - /** * @return optional network pool */ @@ -226,20 +212,18 @@ public class OrgNetwork extends EntityType { if (!super.equals(o)) return false; OrgNetwork that = OrgNetwork.class.cast(o); - return super.equals(that) && equal(networkConfiguration, that.networkConfiguration) && - equal(networkPool, that.networkPool) && + return super.equals(that) && equal(networkPool, that.networkPool) && equal(allowedExternalIpAddresses, that.allowedExternalIpAddresses); } @Override public int hashCode() { - return super.hashCode() + Objects.hashCode(networkConfiguration, - networkPool, allowedExternalIpAddresses); + return super.hashCode() + Objects.hashCode(networkPool, allowedExternalIpAddresses); } @Override public ToStringHelper string() { - return super.string().add("configuration", networkConfiguration).add("networkPool", networkPool) + return super.string().add("networkPool", networkPool) .add("allowedExternalIpAddresses", allowedExternalIpAddresses); } diff --git a/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/domain/Owner.java b/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/domain/Owner.java new file mode 100644 index 0000000000..88e392cfd3 --- /dev/null +++ b/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/domain/Owner.java @@ -0,0 +1,199 @@ +/** + * 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.vcloud.director.v1_5.domain; + +import static com.google.common.base.Objects.equal; +import static com.google.common.base.Preconditions.checkNotNull; + +import java.net.URI; +import java.util.Set; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; +import javax.xml.bind.annotation.XmlType; + +import com.google.common.base.Objects; +import com.google.common.collect.Sets; + + +/** + * + * Represents the owner of this entity. + * + * + *

Java class for Owner complex type. + * + *

The following schema fragment specifies the expected content contained within this class. + * + *

+ * <complexType name="Owner">
+ *   <complexContent>
+ *     <extension base="{http://www.vmware.com/vcloud/v1.5}ResourceType">
+ *       <sequence>
+ *         <element name="User" type="{http://www.vmware.com/vcloud/v1.5}ReferenceType"/>
+ *       </sequence>
+ *       <anyAttribute processContents='lax' namespace='##other'/>
+ *     </extension>
+ *   </complexContent>
+ * </complexType>
+ * 
+ * + * + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlRootElement(name = "Owner") +@XmlType(propOrder = {"user"}) +public class Owner + extends ResourceType + +{ + @SuppressWarnings("unchecked") + public static Builder builder() { + return new Builder(); + } + + public Builder toBuilder() { + return new Builder().fromOwner(this); + } + + public static class Builder extends ResourceType.Builder { + + private Reference user; + + /** + * @see Owner#getUser() + */ + public Builder user(Reference user) { + this.user = user; + return this; + } + + + public Owner build() { + Owner owner = new Owner(); + owner.setUser(user); + return owner; + } + + + /** + * @see ResourceType#getHref() + */ + @Override + public Builder href(URI href) { + super.href(href); + return this; + } + + /** + * @see ResourceType#getType() + */ + @Override + public Builder type(String type) { + super.type(type); + return this; + } + + /** + * @see ResourceType#getLinks() + */ + @Override + public Builder links(Set links) { + super.links(Sets.newLinkedHashSet(checkNotNull(links, "links"))); + return this; + } + + /** + * @see ResourceType#getLinks() + */ + @Override + public Builder link(Link link) { + super.link(link); + return this; + } + + + @Override + public Builder fromResourceType(ResourceType in) { + return Builder.class.cast(super.fromResourceType(in)); + } + public Builder fromOwner(Owner in) { + return fromResourceType(in) + .user(in.getUser()); + } + } + + private Owner() { + // For JAXB and builder use + } + + + + @XmlElement(name = "User", required = true) + protected Reference user; + + /** + * Gets the value of the user property. + * + * @return + * possible object is + * {@link Reference } + * + */ + public Reference getUser() { + return user; + } + + /** + * Sets the value of the user property. + * + * @param value + * allowed object is + * {@link Reference } + * + */ + public void setUser(Reference value) { + this.user = value; + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + Owner that = Owner.class.cast(o); + return equal(user, that.user); + } + + @Override + public int hashCode() { + return Objects.hashCode(user); + } + + @Override + public String toString() { + return Objects.toStringHelper("") + .add("user", user).toString(); + } + +} diff --git a/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/domain/ReferenceType.java b/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/domain/ReferenceType.java index e9444d8ef7..4992ba8e54 100644 --- a/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/domain/ReferenceType.java +++ b/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/domain/ReferenceType.java @@ -108,7 +108,7 @@ public class ReferenceType> implements URISupplier { } } - @XmlAttribute + @XmlAttribute(required = true) private URI href; @XmlAttribute private String id; diff --git a/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/domain/ResourceEntityType.java b/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/domain/ResourceEntityType.java new file mode 100644 index 0000000000..56c9ac6ea0 --- /dev/null +++ b/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/domain/ResourceEntityType.java @@ -0,0 +1,265 @@ +/** + * 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.vcloud.director.v1_5.domain; + +import static com.google.common.base.Objects.equal; +import static com.google.common.base.Preconditions.checkNotNull; + +import java.net.URI; +import java.util.Set; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlAttribute; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlType; + +import com.google.common.base.Objects; +import com.google.common.collect.Sets; + + +/** + * + * Base type that represents a resource entity such as a vApp + * template or virtual media. + * + * + *

Java class for ResourceEntity complex type. + * + *

The following schema fragment specifies the expected content contained within this class. + * + *

+ * <complexType name="ResourceEntity">
+ *   <complexContent>
+ *     <extension base="{http://www.vmware.com/vcloud/v1.5}EntityType">
+ *       <sequence>
+ *         <element name="Files" type="{http://www.vmware.com/vcloud/v1.5}FilesListType" minOccurs="0"/>
+ *       </sequence>
+ *       <attribute name="status" type="{http://www.w3.org/2001/XMLSchema}int" />
+ *       <anyAttribute processContents='lax' namespace='##other'/>
+ *     </extension>
+ *   </complexContent>
+ * </complexType>
+ * 
+ * + * + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "ResourceEntity", propOrder = { + "files" +}) +//@XmlSeeAlso({ +// MediaType.class, +// VAppTemplateType.class, +// AbstractVAppType.class, +// NetworkPoolType.class +//}) +public class ResourceEntityType> extends EntityType { + + public static > Builder builder() { + return new Builder(); + } + + @Override + public Builder toBuilder() { + return new Builder().fromResourceEntityType(this); + } + + public static class Builder> extends EntityType.Builder { + + private FilesList files; + private Integer status; + + /** + * @see ResourceEntityType#getFiles() + */ + public Builder files(FilesList files) { + this.files = files; + return this; + } + + /** + * @see ResourceEntityType#getStatus() + */ + public Builder status(Integer status) { + this.status = status; + return this; + } + + + public ResourceEntityType build() { + ResourceEntityType resourceEntity = new ResourceEntityType(); + resourceEntity.setFiles(files); + resourceEntity.setStatus(status); + return resourceEntity; + } + + + /** + * @see EntityType#getId() + */ + @Override + public Builder id(String id) { + this.id = id; + return this; + } + + /** + * @see EntityType#getTasksInProgress() + */ + @Override + public Builder tasksInProgress(TasksInProgress tasksInProgress) { + this.tasksInProgress = tasksInProgress; + return this; + } + + /** + * @see ReferenceType#getHref() + */ + @Override + public Builder href(URI href) { + this.href = href; + return this; + } + + /** + * @see ReferenceType#getType() + */ + @Override + public Builder type(String type) { + this.type = type; + return this; + } + + /** + * @see ReferenceType#getLinks() + */ + @Override + public Builder links(Set links) { + this.links = Sets.newLinkedHashSet(checkNotNull(links, "links")); + return this; + } + + /** + * @see ReferenceType#getLinks() + */ + @Override + public Builder link(Link link) { + this.links.add(checkNotNull(link, "link")); + return this; + } + + /** + * {@inheritDoc} + */ + @SuppressWarnings("unchecked") + @Override + public Builder fromResourceType(ResourceType in) { + return Builder.class.cast(super.fromResourceType(in)); + } + + public Builder fromResourceEntityType(ResourceEntityType in) { + return fromResourceType(in) + .files(in.getFiles()) + .status(in.getStatus()); + } + } + + public ResourceEntityType() { + } + + @XmlElement(name = "Files") + protected FilesList files; + @XmlAttribute + protected Integer status; + + /** + * Gets the value of the files property. + * + * @return + * possible object is + * {@link FilesList } + * + */ + public FilesList getFiles() { + return files; + } + + /** + * Sets the value of the files property. + * + * @param value + * allowed object is + * {@link FilesList } + * + */ + public void setFiles(FilesList value) { + this.files = value; + } + + /** + * Gets the value of the status property. + * + * @return + * possible object is + * {@link Integer } + * + */ + public Integer getStatus() { + return status; + } + + /** + * Sets the value of the status property. + * + * @param value + * allowed object is + * {@link Integer } + * + */ + public void setStatus(Integer value) { + this.status = value; + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + ResourceEntityType that = ResourceEntityType.class.cast(o); + return equal(files, that.files) && + equal(status, that.status); + } + + @Override + public int hashCode() { + return Objects.hashCode(files, + status); + } + + @Override + public String toString() { + return Objects.toStringHelper("") + .add("files", files) + .add("status", status).toString(); + } + +} diff --git a/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/domain/Task.java b/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/domain/Task.java index 11d79f6143..8c270c8441 100644 --- a/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/domain/Task.java +++ b/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/domain/Task.java @@ -23,7 +23,9 @@ import static com.google.common.base.Preconditions.*; import static org.jclouds.vcloud.director.v1_5.VCloudDirectorConstants.*; import java.net.URI; +import java.util.Arrays; import java.util.Date; +import java.util.List; import java.util.Set; import javax.xml.bind.annotation.XmlAttribute; @@ -49,6 +51,21 @@ import com.google.common.collect.Sets; public class Task extends EntityType { public static final String MEDIA_TYPE = VCloudDirectorMediaType.TASK; + + public static class Status { + public static final String QUEUED = "queued"; + public static final String PRE_RUNNING = "preRunning"; + public static final String RUNNING = "running"; + public static final String SUCCESS = "success"; + public static final String ERROR = "error"; + public static final String CANCELED = "canceled"; + public static final String ABORTED = "aborted"; + + public static final List ALL = Arrays.asList( + QUEUED, PRE_RUNNING, RUNNING, SUCCESS, + ERROR, CANCELED, ABORTED + ); + } @SuppressWarnings("unchecked") public static Builder builder() { @@ -130,6 +147,13 @@ public class Task extends EntityType { this.status = status; return this; } + + /** + * @see Task#getStatus() + */ + public Builder status(TaskStatus status) { + return this.status(status.toString()); + } /** * @see Task#getOperation() @@ -394,8 +418,12 @@ public class Task extends EntityType { *
  • aborted - The task was aborted by an administrative action. * */ - public String getStatus() { - return status; + public TaskStatus getStatus() { + return TaskStatus.fromValue(status); + } + + public void setStatus(TaskStatus status) { + this.setStatus(status.toString()); } public void setStatus(String status) { diff --git a/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/domain/TaskInErrorStateException.java b/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/domain/TaskInErrorStateException.java new file mode 100644 index 0000000000..5b8fe5a272 --- /dev/null +++ b/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/domain/TaskInErrorStateException.java @@ -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.vcloud.director.v1_5.domain; + +/** + * + * @author Adrian Cole + * + */ +public class TaskInErrorStateException extends RuntimeException { + + private static final long serialVersionUID = 1L; + + private final Task task; + + public TaskInErrorStateException(Task task) { + super("error on task: " + task + " error: " + task.getError()); + this.task = task; + } + + public Task getTask() { + return task; + } + +} diff --git a/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/domain/TaskStatus.java b/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/domain/TaskStatus.java new file mode 100644 index 0000000000..ebef2f5218 --- /dev/null +++ b/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/domain/TaskStatus.java @@ -0,0 +1,73 @@ +/** + * 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.vcloud.director.v1_5.domain; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * @author Adrian Cole + */ +public enum TaskStatus { + /** + * The task has completed and returned a value indicating success. + */ + SUCCESS, + /** + * The task is running. + */ + RUNNING, + + /** + * The task has been queued for execution. + */ + QUEUED, + /** + * The task has completed and returned a value indicating an error. + */ + ERROR, + /** + * not an official status, temporarily in. + */ + CANCELLED, UNRECOGNIZED; + public String value() { + return name().toLowerCase(); + } + + @Override + public String toString() { + return value(); + } + + public static TaskStatus fromValue(String status) { + if ("CANCELED".equals(status.toUpperCase())) { + // TODO: ecloud hack + status = "CANCELLED"; + } else if ("FAILED".equals(status.toUpperCase())) { + status = "ERROR"; + } else if ("COMPLETED".equals(status.toUpperCase())) { + status = "SUCCESS"; + } + try { + return valueOf(checkNotNull(status, "status").toUpperCase()); + } catch (IllegalArgumentException e) { + return UNRECOGNIZED; + } + } + +} \ No newline at end of file diff --git a/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/domain/TasksList.java b/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/domain/TasksList.java index 7ffd1550d5..de51ef357d 100644 --- a/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/domain/TasksList.java +++ b/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/domain/TasksList.java @@ -7,7 +7,7 @@ * "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.task/licenses/LICENSE-2.0 + * 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 diff --git a/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/features/CatalogAsyncClient.java b/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/features/CatalogAsyncClient.java index e3b8815d23..b250c47b05 100644 --- a/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/features/CatalogAsyncClient.java +++ b/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/features/CatalogAsyncClient.java @@ -140,8 +140,8 @@ public interface CatalogAsyncClient { */ @POST @Path("/metadata") - @Consumes(VCloudDirectorMediaType.METADATA) - @Produces(VCloudDirectorMediaType.TASK) + @Consumes(VCloudDirectorMediaType.TASK) + @Produces(VCloudDirectorMediaType.METADATA) @JAXBResponseParser @ExceptionParser(ThrowVCloudErrorOn4xx.class) ListenableFuture mergeCatalogItemMetadata(@EndpointParam(parser = ReferenceToEndpoint.class) ReferenceType catalogItemRef, @@ -163,8 +163,8 @@ public interface CatalogAsyncClient { */ @PUT @Path("/metadata/{key}") - @Consumes(VCloudDirectorMediaType.METADATA_VALUE) - @Produces(VCloudDirectorMediaType.TASK) + @Consumes(VCloudDirectorMediaType.TASK) + @Produces(VCloudDirectorMediaType.METADATA_VALUE) @JAXBResponseParser @ExceptionParser(ThrowVCloudErrorOn4xx.class) ListenableFuture setCatalogItemMetadataEntry(@EndpointParam(parser = ReferenceToEndpoint.class) ReferenceType catalogItemRef, diff --git a/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/features/MediaAsyncClient.java b/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/features/MediaAsyncClient.java new file mode 100644 index 0000000000..3a1a0420f8 --- /dev/null +++ b/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/features/MediaAsyncClient.java @@ -0,0 +1,152 @@ +/** + * 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.vcloud.director.v1_5.features; + +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; + +import org.jclouds.rest.annotations.BinderParam; +import org.jclouds.rest.annotations.EndpointParam; +import org.jclouds.rest.annotations.ExceptionParser; +import org.jclouds.rest.annotations.JAXBResponseParser; +import org.jclouds.rest.annotations.RequestFilters; +import org.jclouds.rest.binders.BindToXMLPayload; +import org.jclouds.vcloud.director.v1_5.VCloudDirectorMediaType; +import org.jclouds.vcloud.director.v1_5.domain.Media; +import org.jclouds.vcloud.director.v1_5.domain.Metadata; +import org.jclouds.vcloud.director.v1_5.domain.MetadataValue; +import org.jclouds.vcloud.director.v1_5.domain.Owner; +import org.jclouds.vcloud.director.v1_5.domain.Reference; +import org.jclouds.vcloud.director.v1_5.domain.Task; +import org.jclouds.vcloud.director.v1_5.filters.AddVCloudAuthorizationToRequest; +import org.jclouds.vcloud.director.v1_5.functions.ReferenceToEndpoint; +import org.jclouds.vcloud.director.v1_5.functions.ThrowVCloudErrorOn4xx; + +import com.google.common.util.concurrent.ListenableFuture; + +/** + * @see MediaClient + * @author danikov + */ +@RequestFilters(AddVCloudAuthorizationToRequest.class) +public interface MediaAsyncClient { + + /** + * @see MediaClient#getMedia(Reference) + */ + @GET + @Consumes + @JAXBResponseParser + @ExceptionParser(ThrowVCloudErrorOn4xx.class) + ListenableFuture getMedia(@EndpointParam(parser = ReferenceToEndpoint.class) Reference mediaRef); + + /** + * @see MediaClient#updateMedia(Reference, Media)) + */ + @PUT + @Consumes(VCloudDirectorMediaType.TASK) + @Produces(VCloudDirectorMediaType.MEDIA) + @JAXBResponseParser + @ExceptionParser(ThrowVCloudErrorOn4xx.class) + ListenableFuture updateMedia(@EndpointParam(parser = ReferenceToEndpoint.class) Reference mediaRef, + @BinderParam(BindToXMLPayload.class) Media media); + + /** + * @see MediaClient#deleteMedia(Reference)) + */ + @DELETE + @Consumes(VCloudDirectorMediaType.TASK) + @JAXBResponseParser + @ExceptionParser(ThrowVCloudErrorOn4xx.class) + ListenableFuture deleteMedia(@EndpointParam(parser = ReferenceToEndpoint.class) Reference mediaRef); + + /** + * @see MediaClient#getOwner(Reference) + */ + @GET + @Path("/owner") + @Consumes + @JAXBResponseParser + @ExceptionParser(ThrowVCloudErrorOn4xx.class) + ListenableFuture getOwner(@EndpointParam(parser = ReferenceToEndpoint.class) Reference mediaRef); + + /** + * @see MediaClient#getMetadata(Reference)) + */ + @GET + @Path("/metadata") + @Consumes + @JAXBResponseParser + @ExceptionParser(ThrowVCloudErrorOn4xx.class) + ListenableFuture getMetadata(@EndpointParam(parser = ReferenceToEndpoint.class) Reference mediaRef); + + /** + * @see MediaClient#mergeMetadata(Reference, Metadata)) + */ + @POST + @Path("/metadata") + @Consumes(VCloudDirectorMediaType.TASK) + @Produces(VCloudDirectorMediaType.METADATA) + @JAXBResponseParser + @ExceptionParser(ThrowVCloudErrorOn4xx.class) + ListenableFuture mergeMetadata(@EndpointParam(parser = ReferenceToEndpoint.class) Reference mediaRef, + @BinderParam(BindToXMLPayload.class) Metadata metadata); + + /** + * @see MediaClient#getMetadataEntry(Reference, String)) + */ + @GET + @Path("/metadata/{key}") + @Consumes + @JAXBResponseParser + @ExceptionParser(ThrowVCloudErrorOn4xx.class) + ListenableFuture getMetadataValue(@EndpointParam(parser = ReferenceToEndpoint.class) Reference mediaRef, + @PathParam("key") String key); + + /** + * @see MediaClient#setMetadata(Reference, String, MetadataEntry)) + */ + @PUT + @Path("/metadata/{key}") + @Consumes(VCloudDirectorMediaType.TASK) + @Produces(VCloudDirectorMediaType.METADATA_VALUE) + @JAXBResponseParser + @ExceptionParser(ThrowVCloudErrorOn4xx.class) + ListenableFuture setMetadata(@EndpointParam(parser = ReferenceToEndpoint.class) Reference metaDataRef, + @PathParam("key") String key, + @BinderParam(BindToXMLPayload.class) MetadataValue metadataValue); + + /** + * @see MediaClient#deleteMetadataEntry(Reference, String)) + */ + @DELETE + @Path("/metadata/{key}") + @Consumes(VCloudDirectorMediaType.TASK) + @JAXBResponseParser + @ExceptionParser(ThrowVCloudErrorOn4xx.class) + ListenableFuture deleteMetadataEntry(@EndpointParam(parser = ReferenceToEndpoint.class) Reference metaDataRef, + @PathParam("key") String key); + +} diff --git a/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/features/MediaClient.java b/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/features/MediaClient.java new file mode 100644 index 0000000000..70efcab0d5 --- /dev/null +++ b/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/features/MediaClient.java @@ -0,0 +1,108 @@ +/** + * 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.vcloud.director.v1_5.features; + +import java.util.concurrent.TimeUnit; + +import org.jclouds.concurrent.Timeout; +import org.jclouds.vcloud.director.v1_5.domain.Media; +import org.jclouds.vcloud.director.v1_5.domain.Metadata; +import org.jclouds.vcloud.director.v1_5.domain.MetadataValue; +import org.jclouds.vcloud.director.v1_5.domain.Owner; +import org.jclouds.vcloud.director.v1_5.domain.Reference; +import org.jclouds.vcloud.director.v1_5.domain.Task; + +/** + * Provides synchronous access to Media. + *

    + * + * @see MediaAsyncClient + * @see + * @author danikov + */ +@Timeout(duration = 180, timeUnit = TimeUnit.SECONDS) +public interface MediaClient { + + /** + * Retrieves a media. + * + * @return the media or null if not found + */ + Media getMedia(Reference mediaRef); + + /** + * Updates the name/description of a media. + * + * @return a task. This operation is asynchronous and the user should monitor the returned + * task status in order to check when it is completed. + */ + Task updateMedia(Reference mediaRef, Media media); + + /** + * Deletes a media. + */ + Task deleteMedia(Reference mediaRef); + + /** + * Retrieves an owner. + * + * @return the owner or null if not found + */ + Owner getOwner(Reference mediaRef); + + /** + * Retrieves an list of the media's metadata + * + * @return a list of metadata + */ + Metadata getMetadata(Reference mediaRef); + /** + * Merges the metadata for a media with the information provided. + * + * @return a task. This operation is asynchronous and the user should monitor the returned + * task status in order to check when it is completed. + */ + Task mergeMetadata(Reference mediaRef, Metadata metadata); + + /** + * Retrieves a metadata value + * + * @return the metadata value, or null if not found + */ + MetadataValue getMetadataValue(Reference mediaRef, String key); + + /** + * Sets the metadata for the particular key for the media to the value provided. + * Note: this will replace any existing metadata information + * + * @return a task. This operation is asynchronous and the user should monitor the returned + * task status in order to check when it is completed. + */ + Task setMetadata(Reference mediaRef, String key, MetadataValue metadataValue); + + /** + * Deletes a metadata entry. + * + * @return a task. This operation is asynchronous and the user should monitor the returned + * task status in order to check when it is completed. + */ + Task deleteMetadataEntry(Reference mediaRef, String key); + + +} diff --git a/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/features/NetworkAsyncClient.java b/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/features/NetworkAsyncClient.java index aea399dbb4..34fa61183d 100644 --- a/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/features/NetworkAsyncClient.java +++ b/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/features/NetworkAsyncClient.java @@ -18,21 +18,22 @@ */ package org.jclouds.vcloud.director.v1_5.features; -import java.net.URI; - import javax.ws.rs.Consumes; import javax.ws.rs.GET; import javax.ws.rs.Path; +import javax.ws.rs.PathParam; import org.jclouds.rest.annotations.EndpointParam; import org.jclouds.rest.annotations.ExceptionParser; import org.jclouds.rest.annotations.JAXBResponseParser; import org.jclouds.rest.annotations.RequestFilters; -import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404; import org.jclouds.vcloud.director.v1_5.domain.Metadata; -import org.jclouds.vcloud.director.v1_5.domain.MetadataEntry; +import org.jclouds.vcloud.director.v1_5.domain.MetadataValue; import org.jclouds.vcloud.director.v1_5.domain.OrgNetwork; +import org.jclouds.vcloud.director.v1_5.domain.Reference; import org.jclouds.vcloud.director.v1_5.filters.AddVCloudAuthorizationToRequest; +import org.jclouds.vcloud.director.v1_5.functions.ReferenceToEndpoint; +import org.jclouds.vcloud.director.v1_5.functions.ThrowVCloudErrorOn4xx; import com.google.common.util.concurrent.ListenableFuture; @@ -45,30 +46,33 @@ import com.google.common.util.concurrent.ListenableFuture; public interface NetworkAsyncClient { /** - * @see NeworkClient#getNetwork() + * @see NeworkClient#getNetwork(Reference) */ @GET @Consumes @JAXBResponseParser - @ExceptionParser(ReturnNullOnNotFoundOr404.class) - ListenableFuture getNetwork(@EndpointParam URI uri); + @ExceptionParser(ThrowVCloudErrorOn4xx.class) + ListenableFuture getNetwork(@EndpointParam(parser = ReferenceToEndpoint.class) Reference networkRef); /** - * @see NeworkClient#getMetadata() + * @see NeworkClient#getMetadata(Reference) */ @GET - @Path("/metadata/") + @Path("/metadata") @Consumes @JAXBResponseParser - @ExceptionParser(ReturnNullOnNotFoundOr404.class) - ListenableFuture getMetadata(@EndpointParam URI orgRef); + @ExceptionParser(ThrowVCloudErrorOn4xx.class) + ListenableFuture getMetadata(@EndpointParam(parser = ReferenceToEndpoint.class) Reference networkRef); /** - * @see NeworkClient#getMetadataEntry() + * @see NeworkClient#getMetadataValue(Reference, String) */ @GET + @Path("/metadata/{key}") @Consumes @JAXBResponseParser - @ExceptionParser(ReturnNullOnNotFoundOr404.class) - ListenableFuture getMetadataEntry(@EndpointParam URI metaDataRef); + @ExceptionParser(ThrowVCloudErrorOn4xx.class) + ListenableFuture getMetadataValue(@EndpointParam(parser = ReferenceToEndpoint.class) Reference networkRef , + @PathParam("key") String key); + } diff --git a/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/features/NetworkClient.java b/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/features/NetworkClient.java index c10ddd07b1..88cb290aea 100644 --- a/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/features/NetworkClient.java +++ b/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/features/NetworkClient.java @@ -18,13 +18,13 @@ */ package org.jclouds.vcloud.director.v1_5.features; -import java.net.URI; import java.util.concurrent.TimeUnit; import org.jclouds.concurrent.Timeout; import org.jclouds.vcloud.director.v1_5.domain.Metadata; -import org.jclouds.vcloud.director.v1_5.domain.MetadataEntry; +import org.jclouds.vcloud.director.v1_5.domain.MetadataValue; import org.jclouds.vcloud.director.v1_5.domain.OrgNetwork; +import org.jclouds.vcloud.director.v1_5.domain.Reference; /** * Provides synchronous access to Network. @@ -42,20 +42,20 @@ public interface NetworkClient { * * @return the network or null if not found */ - OrgNetwork getNetwork(URI networkRef); + OrgNetwork getNetwork(Reference networkRef); /** * Retrieves an list of the network's metadata * * @return a list of metadata */ - Metadata getMetadata(URI networkRef); + Metadata getMetadata(Reference networkRef); /** - * Retrieves a metadata entry + * Retrieves a metadata value * - * @return the metadata entry, or null if not found + * @return the metadata value, or null if not found */ - MetadataEntry getMetadataEntry(URI metaDataRef); + MetadataValue getMetadataValue(Reference networkRef, String key); } diff --git a/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/features/OrgAsyncClient.java b/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/features/OrgAsyncClient.java index 75c82d4acc..9fda1f293a 100644 --- a/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/features/OrgAsyncClient.java +++ b/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/features/OrgAsyncClient.java @@ -49,7 +49,7 @@ public interface OrgAsyncClient { * @see OrgClient#getOrgList() */ @GET - @Path("/org") + @Path("/org/") @Consumes @JAXBResponseParser ListenableFuture getOrgList(); @@ -71,7 +71,7 @@ public interface OrgAsyncClient { @Consumes @JAXBResponseParser @ExceptionParser(ThrowVCloudErrorOn4xx.class) - ListenableFuture getMetadata(@EndpointParam(parser = ReferenceToEndpoint.class) ReferenceType orgRef); + ListenableFuture getOrgMetadata(@EndpointParam(parser = ReferenceToEndpoint.class) ReferenceType orgRef); /** * @see OrgClient#getMetadataEntry(ReferenceType, String) @@ -81,6 +81,6 @@ public interface OrgAsyncClient { @Consumes @JAXBResponseParser @ExceptionParser(ThrowVCloudErrorOn4xx.class) - ListenableFuture getMetadataEntry(@EndpointParam(parser = ReferenceToEndpoint.class) ReferenceType orgRef, + ListenableFuture getOrgMetadataEntry(@EndpointParam(parser = ReferenceToEndpoint.class) ReferenceType orgRef, @PathParam("key") String key); } diff --git a/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/features/OrgClient.java b/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/features/OrgClient.java index e52ac68748..96125cca70 100644 --- a/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/features/OrgClient.java +++ b/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/features/OrgClient.java @@ -69,7 +69,7 @@ public interface OrgClient { * * @return a list of metadata */ - Metadata getMetadata(ReferenceType orgRef); + Metadata getOrgMetadata(ReferenceType orgRef); /** * Retrieves a metadata entry. @@ -80,6 +80,6 @@ public interface OrgClient { * * @return the metadata entry or null if not found */ - MetadataEntry getMetadataEntry(ReferenceType orgRef, String key); + MetadataEntry getOrgMetadataEntry(ReferenceType orgRef, String key); // FIXME throws exception on not found currently } diff --git a/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/features/TaskAsyncClient.java b/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/features/TaskAsyncClient.java index 41050aee94..1c39d7f7ef 100644 --- a/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/features/TaskAsyncClient.java +++ b/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/features/TaskAsyncClient.java @@ -18,6 +18,8 @@ */ package org.jclouds.vcloud.director.v1_5.features; +import java.net.URI; + import javax.ws.rs.Consumes; import javax.ws.rs.GET; import javax.ws.rs.POST; @@ -27,12 +29,11 @@ import org.jclouds.rest.annotations.EndpointParam; import org.jclouds.rest.annotations.ExceptionParser; import org.jclouds.rest.annotations.JAXBResponseParser; import org.jclouds.rest.annotations.RequestFilters; -import org.jclouds.vcloud.director.v1_5.domain.ReferenceType; +import org.jclouds.vcloud.director.v1_5.domain.Reference; import org.jclouds.vcloud.director.v1_5.domain.Task; import org.jclouds.vcloud.director.v1_5.domain.TasksList; import org.jclouds.vcloud.director.v1_5.filters.AddVCloudAuthorizationToRequest; import org.jclouds.vcloud.director.v1_5.functions.OrgReferenceToTaskListEndpoint; -import org.jclouds.vcloud.director.v1_5.functions.ReferenceToEndpoint; import org.jclouds.vcloud.director.v1_5.functions.ThrowVCloudErrorOn4xx; import com.google.common.util.concurrent.ListenableFuture; @@ -51,16 +52,16 @@ public interface TaskAsyncClient { @Consumes @JAXBResponseParser @ExceptionParser(ThrowVCloudErrorOn4xx.class) - ListenableFuture getTaskList(@EndpointParam(parser = OrgReferenceToTaskListEndpoint.class) ReferenceType orgRef); + ListenableFuture getTaskList(@EndpointParam(parser = OrgReferenceToTaskListEndpoint.class) Reference orgRef); /** - * @see TaskClient#getTask(ReferenceType) + * @see TaskClient#getTask(URI) */ @GET @Consumes @JAXBResponseParser @ExceptionParser(ThrowVCloudErrorOn4xx.class) - ListenableFuture getTask(@EndpointParam(parser = ReferenceToEndpoint.class) ReferenceType taskRef); + ListenableFuture getTask(@EndpointParam URI taskUri); /** * @see TaskClient#cancelTask(URI) @@ -70,5 +71,5 @@ public interface TaskAsyncClient { @Consumes @JAXBResponseParser @ExceptionParser(ThrowVCloudErrorOn4xx.class) - ListenableFuture cancelTask(@EndpointParam(parser = ReferenceToEndpoint.class) ReferenceType taskRef); + ListenableFuture cancelTask(@EndpointParam URI taskUri); } diff --git a/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/features/TaskClient.java b/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/features/TaskClient.java index 9682316877..c3790eb412 100644 --- a/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/features/TaskClient.java +++ b/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/features/TaskClient.java @@ -18,10 +18,11 @@ */ package org.jclouds.vcloud.director.v1_5.features; +import java.net.URI; import java.util.concurrent.TimeUnit; import org.jclouds.concurrent.Timeout; -import org.jclouds.vcloud.director.v1_5.domain.ReferenceType; +import org.jclouds.vcloud.director.v1_5.domain.Reference; import org.jclouds.vcloud.director.v1_5.domain.Task; import org.jclouds.vcloud.director.v1_5.domain.TasksList; @@ -44,7 +45,7 @@ public interface TaskClient { * @param orgId the unique id for the organization * @return a list of tasks */ - TasksList getTaskList(ReferenceType orgRef); + TasksList getTaskList(Reference orgRef); /** * Retrieves a task. @@ -55,7 +56,7 @@ public interface TaskClient { * * @return the task or null if not found */ - Task getTask(ReferenceType taskRef); + Task getTask(URI taskUri); /** * Cancels a task. @@ -64,5 +65,5 @@ public interface TaskClient { * POST /task/{id}/action/cancel * */ - void cancelTask(ReferenceType taskRef); + void cancelTask(URI taskUri); } diff --git a/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/functions/ThrowVCloudErrorOn4xx.java b/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/functions/ThrowVCloudErrorOn4xx.java index 9de694e36b..89d959711c 100644 --- a/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/functions/ThrowVCloudErrorOn4xx.java +++ b/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/functions/ThrowVCloudErrorOn4xx.java @@ -45,7 +45,7 @@ public class ThrowVCloudErrorOn4xx implements Function { public Object apply(Exception from) { Iterable throwables = Iterables.filter(Throwables.getCausalChain(from), HttpResponseException.class); HttpResponseException exception = Iterables.getFirst(throwables, null); - if (exception != null && exception.getResponse().getStatusCode() >= 400 && exception.getResponse().getStatusCode() < 500) { + if (exception != null && exception.getResponse() != null && exception.getResponse().getStatusCode() >= 400 && exception.getResponse().getStatusCode() < 500) { try { Error error = JAXB.unmarshal(InputSuppliers.of(exception.getContent()).getInput(), Error.class); throw new VCloudDirectorException(error); diff --git a/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/predicates/TaskSuccess.java b/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/predicates/TaskSuccess.java new file mode 100644 index 0000000000..df0015def3 --- /dev/null +++ b/labs/vcloud-director/src/main/java/org/jclouds/vcloud/director/v1_5/predicates/TaskSuccess.java @@ -0,0 +1,70 @@ +/** + * 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.vcloud.director.v1_5.predicates; + +import java.net.URI; + +import javax.annotation.Resource; +import javax.inject.Singleton; + +import org.jclouds.logging.Logger; +import org.jclouds.rest.RestContext; +import org.jclouds.vcloud.director.v1_5.VCloudDirectorAsyncClient; +import org.jclouds.vcloud.director.v1_5.VCloudDirectorClient; +import org.jclouds.vcloud.director.v1_5.domain.Task; +import org.jclouds.vcloud.director.v1_5.domain.TaskInErrorStateException; +import org.jclouds.vcloud.director.v1_5.domain.TaskStatus; +import org.jclouds.vcloud.director.v1_5.features.TaskClient; + +import com.google.common.base.Predicate; +import com.google.inject.Inject; + +/** + * + * Tests to see if a task succeeds. + * + * @author Adrian Cole + */ +@Singleton +public class TaskSuccess implements Predicate { + + private final TaskClient taskClient; + + @Resource + protected Logger logger = Logger.NULL; + + @Inject + public TaskSuccess(RestContext context) { + this.taskClient = context.getApi().getTaskClient(); + } + + public boolean apply(URI taskUri) { + logger.trace("looking for status on task %s", taskUri); + + Task task = taskClient.getTask(taskUri); + // perhaps task isn't available, yet + if (task == null) + return false; + logger.trace("%s: looking for status %s: currently: %s", task, TaskStatus.SUCCESS, task.getStatus()); + if (task.getStatus() == TaskStatus.ERROR) + throw new TaskInErrorStateException(task); + return task.getStatus() == TaskStatus.SUCCESS; + } + +} diff --git a/labs/vcloud-director/src/test/java/org/jclouds/vcloud/director/v1_5/VCloudDirectorClientExpectTest.java b/labs/vcloud-director/src/test/java/org/jclouds/vcloud/director/v1_5/VCloudDirectorClientExpectTest.java index 2806e74726..3aa3533b34 100644 --- a/labs/vcloud-director/src/test/java/org/jclouds/vcloud/director/v1_5/VCloudDirectorClientExpectTest.java +++ b/labs/vcloud-director/src/test/java/org/jclouds/vcloud/director/v1_5/VCloudDirectorClientExpectTest.java @@ -1,4 +1,4 @@ -/** +/* * Licensed to jclouds, Inc. (jclouds) under one or more * contributor license agreements. See the NOTICE file * distributed with this work for additional information @@ -25,7 +25,6 @@ import org.jclouds.vcloud.director.v1_5.login.SessionClientExpectTest; import org.testng.annotations.Test; /** - * * @author Adrian Cole */ @Test(groups = "unit", testName = "VCloudDirectorClient") diff --git a/labs/vcloud-director/src/test/java/org/jclouds/vcloud/director/v1_5/VCloudDirectorLiveTestConstants.java b/labs/vcloud-director/src/test/java/org/jclouds/vcloud/director/v1_5/VCloudDirectorLiveTestConstants.java new file mode 100644 index 0000000000..c58b863299 --- /dev/null +++ b/labs/vcloud-director/src/test/java/org/jclouds/vcloud/director/v1_5/VCloudDirectorLiveTestConstants.java @@ -0,0 +1,43 @@ +/** + * 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.vcloud.director.v1_5; + +/** + * @author grkvlt@apache.org + */ +public class VCloudDirectorLiveTestConstants { + + public static final String REF_REQ_LIVE = "%s reference required to perform live tests"; + public static final String OBJ_REQ_LIVE = "%s instance required to perform live tests"; + public static final String OBJ_FIELD_REQ_LIVE = "%s must have a non-null \"%s\" to perform live tests"; + public static final String OBJ_FIELD_REQ = "%s must always have a non-null field \"%s\""; + public static final String OBJ_FIELD_ATTRB_REQ = "%s %s (%s) must always have a non-null field \"%s\""; + public static final String OBJ_FIELD_EQ = "%s %s must have the value \"%s\" (%s)"; + public static final String OBJ_FIELD_CONTAINS = "%s %s must contain the values \"%s\" (%s)"; + public static final String OBJ_FIELD_GTE_0 = "%s field %s must be greater than to equal to 0 (%d)"; + public static final String GETTER_RETURNS_SAME_OBJ = "%s should return the same %s as %s (%s, %s)"; + public static final String OBJ_FIELD_UPDATABLE = "%s field %s should be updatable"; + public static final String OBJ_FIELD_ATTRB_DEL = "%s %s (%s) should have deleted field \"%s\" (%s)"; + public static final String OBJ_DEL = "%s (%s) should have been deleted"; + public static final String TASK_COMPLETE_TIMELY = "Task %s should complete in a timely fashion"; + + @Deprecated + public static final String FIELD_NOT_NULL_FMT = "The %s field of the %s must not be null"; + +} diff --git a/labs/vcloud-director/src/test/java/org/jclouds/vcloud/director/v1_5/domain/Checks.java b/labs/vcloud-director/src/test/java/org/jclouds/vcloud/director/v1_5/domain/Checks.java new file mode 100644 index 0000000000..2bed1482d6 --- /dev/null +++ b/labs/vcloud-director/src/test/java/org/jclouds/vcloud/director/v1_5/domain/Checks.java @@ -0,0 +1,314 @@ +/** + * 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.vcloud.director.v1_5.domain; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; +import static org.testng.Assert.fail; + +import java.net.URI; +import java.util.Set; +import java.util.UUID; + +import org.jclouds.vcloud.director.v1_5.VCloudDirectorMediaType; + +import com.google.common.base.Splitter; +import com.google.common.collect.Iterables; +import com.google.common.net.InetAddresses; + +/** + * @author grkvlt@apache.org + */ +public class Checks { + + public static void checkResourceEntityType(ResourceEntityType resourceEntity) { + // Check optional fields + // NOTE status cannot be checked (TODO: doesn't status have a range of valid values?) + FilesList files = resourceEntity.getFiles(); + if (files != null && files.getFiles() != null && !files.getFiles().isEmpty()) { + for (File file : files.getFiles()) checkFile(file); + } + + // Check parent type + checkEntityType(resourceEntity); + } + + public static void checkEntityType(EntityType entity) { + // Check required fields + assertNotNull(entity.getName(), "The Name attribute of an EntityType must be set"); + + // Check optional fields + // NOTE description cannot be checked + TasksInProgress tasksInProgress = entity.getTasksInProgress(); + if (tasksInProgress != null && tasksInProgress.getTasks() != null && !tasksInProgress.getTasks().isEmpty()) { + for (Task task : tasksInProgress.getTasks()) checkTask(task); + } + + // Check parent type + checkResourceType(entity); + } + + public static void checkReferenceType(ReferenceType reference) { + // Check required fields + assertNotNull(reference.getHref(), "The Href attribute of a ReferenceType must be set"); + + // Check optional fields + String id = reference.getId(); + if (id != null) checkId(id); + String type = reference.getType(); + if (type != null) checkType(type); + // NOTE name cannot be checked + } + + public static void checkResourceType(ResourceType resource) { + // Check optional fields + URI href = resource.getHref(); + if (href != null) checkHref(href); + String type = resource.getType(); + if (type != null) checkType(type); + Set links = resource.getLinks(); + if (links != null && !links.isEmpty()) { + for (Link link : links) checkLink(link); + } + } + + public static void checkId(String id) { + Iterable parts = Splitter.on(':').split(id); + assertEquals(Iterables.size(parts), 4, "The Id must be well formed"); + assertEquals(Iterables.get(parts, 0), "urn", "The Id must start with 'urn'"); + assertEquals(Iterables.get(parts, 1), "vcloud", "The Id must include 'vcloud'"); + try { + UUID uuid = UUID.fromString(Iterables.get(parts, 3)); + assertNotNull(uuid, "The UUID part of an Id must be well formed"); + } catch (IllegalArgumentException iae) { + fail("The UUID part of an Id must be well formed"); + } + } + + public static void checkType(String type) { + assertTrue(VCloudDirectorMediaType.ALL.contains(type), + String.format("The Type (%s) must be a valid media type - %s", type, + Iterables.toString(VCloudDirectorMediaType.ALL))); + } + + // NOTE this does not currently check anything + public static void checkHref(URI href) { + String uri = href.toASCIIString(); + String auth = href.getAuthority(); + String host = href.getHost(); + String path = href.getPath(); + // TODO inject the endpoint of the provider here for rudimentary checks as below + // assertEquals(auth + "://" + host + path, endpoint, "The Href must contain the provider endpoint"); + // assertTrue(uri.startsWith(endpoint), "The Href must contain the provider endpoint"); + } + + public static void checkLink(Link link) { + // Check required fields + assertNotNull(link.getRel(), "The Rel attribute of a Link must be set"); + assertTrue(Link.Rel.ALL.contains(link.getRel()), + String.format("The Rel attribute (%s) of a Link must be one of the allowed list - %s", + link.getRel(), Iterables.toString(Link.Rel.ALL))); + + // Check parent type + checkReferenceType(link); + } + + public static void checkTask(Task task) { + // Check required fields + assertNotNull(task.getStatus(), "The Status attribute of a Task must be set"); + assertTrue(Task.Status.ALL.contains(task.getStatus().toString()), + String.format("The Status of a Task (%s) must be one of the allowed list - %s", + task.getStatus().toString(), Iterables.toString(Task.Status.ALL))); + + // Check optional fields + // NOTE operation cannot be checked + // NOTE operationName cannot be checked + // NOTE startTime cannot be checked + // NOTE endTime cannot be checked + // NOTE expiryTimecannot be checked + ReferenceType owner = task.getOwner(); + if (owner != null) checkReferenceType(owner); + Error error = task.getError(); + if (error != null) checkError(error); + ReferenceType user = task.getUser(); + if (user != null) checkReferenceType(user); + ReferenceType org = task.getOrg(); + if (org != null) checkReferenceType(org); + Integer progress = task.getProgress(); + if (progress != null) checkProgress(progress); + // NOTE params cannot be checked + + // Check parent type + checkEntityType(task); + } + + public static void checkFile(File file) { + // Check optional fields + // NOTE checksum be checked + Long size = file.getSize(); + if(size != null) { + assertTrue(file.size >= 0, "File size must be greater than or equal to 0"); + } + Long bytesTransferred = file.getBytesTransferred(); + if(bytesTransferred != null) { + assertTrue(bytesTransferred >= 0, "Bytes transferred must be greater than or equal to 0"); + } + + // Check parent type + checkEntityType(file); + } + + public static void checkProgress(Integer progress) { + assertTrue(progress >= 0 && progress <= 100, "The Progress attribute must be between 0 and 100"); + } + + public static void checkError(Error error) { + // Check required fields + assertNotNull(error.getMessage(), "The Message attribute of an Error must be set"); + assertNotNull(error.getMajorErrorCode(), "The MajorErrorCode attribute of an Error must be set"); + assertNotNull(error.getMinorErrorCode(), "The MinorErrorCode attribute of an Error must be set"); + + // NOTE vendorSpecificErrorCode cannot be checked + // NOTE stackTrace cannot be checked + } + + public static void checkImageType(String imageType) { + assertTrue(Media.ImageType.ALL.contains(imageType), + "The Image type of a Media must be one of the allowed list"); + } + + public static void checkNetworkType(NetworkType network) { + // Check optional fields + NetworkConfiguration config = network.getConfiguration(); + if (config != null) { + checkNetworkConfiguration(config); + } + + // Check parent type + checkEntityType(network); + } + + public static void checkNetworkConfiguration(NetworkConfiguration config) { + // Check optional fields + if (config.getIpScope() != null) { + checkIpScope(config.getIpScope()); + } + + if (config.getParentNetwork() != null) { + checkReferenceType(config.getParentNetwork()); + } + + if (config.getNetworkFeatures() != null) { + checkNetworkFeatures(config.getNetworkFeatures()); + } + + if (config.getSyslogServerSettings() != null) { + checkSyslogServerSettings(config.getSyslogServerSettings()); + } + + if (config.getRouterInfo() != null) { + checkRouterInfo(config.getRouterInfo()); + } + } + + public static void checkIpScope(IpScope ipScope) { + // Check required fields + assertNotNull(ipScope.isInherited(), "isInherited attribute of IpScope must be set"); + + // Check optional fields + // NOTE dnsSuffix cannot be checked + if (ipScope.getGateway() != null) { + checkIpAddress(ipScope.getGateway()); + } + if (ipScope.getNetmask() != null) { + checkIpAddress(ipScope.getNetmask()); + } + if (ipScope.getDns1() != null) { + checkIpAddress(ipScope.getDns1()); + } + if (ipScope.getDns2() != null) { + checkIpAddress(ipScope.getDns2()); + } + if (ipScope.getIpRanges() != null) { + checkIpRanges(ipScope.getIpRanges()); + } + if (ipScope.getAllocatedIpAddresses() != null) { + checkIpAddresses(ipScope.getAllocatedIpAddresses()); + } + } + + public static void checkNetworkFeatures(NetworkFeatures features) { + // Check optional fields + if (features.getNetworkServices() != null) { + for (NetworkService service : features.getNetworkServices()) { + checkNetworkService(service); + } + } + } + + public static void checkSyslogServerSettings(SyslogServerSettings settings) { + // Check optional fields + if (settings.getSyslogServerIp1() != null) { + checkIpAddress(settings.getSyslogServerIp1()); + } + + if (settings.getSyslogServerIp2() != null) { + checkIpAddress(settings.getSyslogServerIp2()); + } + + } + + public static void checkRouterInfo(RouterInfo routerInfo) { + // Check required fields + assertNotNull(routerInfo.getExternalIp(), "The external IP attribute of a Router Info must be set"); + checkIpAddress(routerInfo.getExternalIp()); + } + + public static void checkNetworkService(NetworkService service) { + // NOTE isEnabled cannot be checked + } + + public static void checkIpRanges(IpRanges ipRanges) { + // Check optional fields + for (IpRange range : ipRanges.getIpRanges()) { + checkIpRange(range); + } + } + + public static void checkIpRange(IpRange range) { + // Check required fields + assertNotNull(range.getStartAddress(), "The start address attribute of an IP Range must be set"); + checkIpAddress(range.getStartAddress()); + + assertNotNull(range.getEndAddress(), "The end address attribute of an IP Range must be set"); + checkIpAddress(range.getEndAddress()); + } + + public static void checkIpAddresses(IpAddresses ipAddresses) { + // Check optional fields + for (String address : ipAddresses.getIpAddresses()) { + checkIpAddress(address); + } + } + + public static void checkIpAddress(String ip) { + InetAddresses.isInetAddress(ip); + } +} diff --git a/labs/vcloud-director/src/test/java/org/jclouds/vcloud/director/v1_5/features/CatalogClientExpectTest.java b/labs/vcloud-director/src/test/java/org/jclouds/vcloud/director/v1_5/features/CatalogClientExpectTest.java index 31590b21bd..9bf2121484 100644 --- a/labs/vcloud-director/src/test/java/org/jclouds/vcloud/director/v1_5/features/CatalogClientExpectTest.java +++ b/labs/vcloud-director/src/test/java/org/jclouds/vcloud/director/v1_5/features/CatalogClientExpectTest.java @@ -1,15 +1,15 @@ -/** +/* * Licensed to jclouds, Inc. (jclouds) under one or more * contributor license agreements. See the NOTICE file * distributed with this work for additional information - *(Link.builder().regarding copyright ownership. jclouds licenses this file + * 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(Link.builder().required by applicable law or agreed to in writing, + * 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 @@ -34,6 +34,7 @@ import org.jclouds.vcloud.director.v1_5.domain.Metadata; import org.jclouds.vcloud.director.v1_5.domain.MetadataEntry; import org.jclouds.vcloud.director.v1_5.domain.MetadataValue; import org.jclouds.vcloud.director.v1_5.domain.Reference; +import org.jclouds.vcloud.director.v1_5.domain.Task; import org.jclouds.vcloud.director.v1_5.internal.BaseVCloudDirectorRestClientExpectTest; import org.testng.annotations.Test; @@ -66,40 +67,7 @@ public class CatalogClientExpectTest extends BaseVCloudDirectorRestClientExpectT VCloudDirectorClient client = requestsSendResponses(loginRequest, sessionResponse, catalogRequest, catalogResponse); - Catalog expected = Catalog.builder() - .name("QunyingTestCatalog") - .type("application/vnd.vmware.vcloud.catalog+xml") - .id("urn:vcloud:catalog:7212e451-76e1-4631-b2de-ba1dfd8080e4") - .href(URI.create("https://vcloudbeta.bluelock.com/api/catalog/7212e451-76e1-4631-b2de-ba1dfd8080e4")) - .link(Link.builder() - .rel("up") - .type("application/vnd.vmware.vcloud.org+xml") - .href(URI.create("https://vcloudbeta.bluelock.com/api/org/6f312e42-cd2b-488d-a2bb-97519cd57ed0")) - .build()) - .link(Link.builder() - .rel("add") - .type("application/vnd.vmware.vcloud.catalogItem+xml") - .href(URI.create("https://vcloudbeta.bluelock.com/api/catalog/7212e451-76e1-4631-b2de-ba1dfd8080e4/catalogItems")) - .build()) - .link(Link.builder() - .rel("down") - .type("application/vnd.vmware.vcloud.metadata+xml") - .href(URI.create("https://vcloudbeta.bluelock.com/api/catalog/7212e451-76e1-4631-b2de-ba1dfd8080e4/metadata")) - .build()) - .catalogItems(CatalogItems.builder() - .item(Reference.builder() - .type("application/vnd.vmware.vcloud.catalogItem+xml") - .name("ubuntu10") - .href(URI.create("https://vcloudbeta.bluelock.com/api/catalogItem/a36fdac9-b8c2-43e2-9a4c-2ffaf3ee13df")) - .build()) - .item(Reference.builder() - .type("application/vnd.vmware.vcloud.catalogItem+xml") - .name("imageTesting") - .href(URI.create("https://vcloudbeta.bluelock.com/api/catalogItem/a9e0afdb-a42b-4688-8409-2ac68cf22939")) - .build()) - .build()) - .description("Testing") - .build(); + Catalog expected = catalog(); Reference catalogRef = Reference.builder() .type("application/vnd.vmware.vcloud.catalog+xml") @@ -124,7 +92,7 @@ public class CatalogClientExpectTest extends BaseVCloudDirectorRestClientExpectT HttpResponse catalogItemResponse = HttpResponse.builder() .statusCode(200) - .payload(payloadFromResourceWithContentType("/catalog/catalogItem.xml", VCloudDirectorMediaType.CATALOG_ITEM + ";version=1.5")) + .payload(payloadFromResourceWithContentType("/catalog/createdCatalogItem.xml", VCloudDirectorMediaType.CATALOG_ITEM + ";version=1.5")) .build(); VCloudDirectorClient client = requestsSendResponses(loginRequest, sessionResponse, catalogItemRequest, catalogItemResponse); @@ -135,20 +103,431 @@ public class CatalogClientExpectTest extends BaseVCloudDirectorRestClientExpectT .href(URI.create(endpoint + "/catalog/7212e451-76e1-4631-b2de-ba1dfd8080e4")) .build(); - Reference ubuntu = Reference.builder() - .type("application/vnd.vmware.vcloud.vAppTemplate+xml") - .name("ubuntu10") - .href(URI.create("https://vcloudbeta.bluelock.com/api/vAppTemplate/vappTemplate-ef4415e6-d413-4cbb-9262-f9bbec5f2ea9")) - .build(); - CatalogItem newItem = CatalogItem.builder() .name("newCatalogItem") .description("New Catalog Item") - .entity(ubuntu) + .entity(ubuntuVappTemplateReference()) .build(); - CatalogItem expected = CatalogItem.builder() - .name("newCatalogItem") + CatalogItem expected = createdCatalogItem(); + + assertEquals(client.getCatalogClient().addCatalogItem(catalogRef, newItem), expected); + } + + @Test + public void testGetCatalogMetadata() { + HttpRequest catalogRequest = HttpRequest.builder() + .method("GET") + .endpoint(URI.create(endpoint + "/catalog/7212e451-76e1-4631-b2de-ba1dfd8080e4/metadata")) + .headers(ImmutableMultimap. builder() + .put("Accept", "*/*") + .put("x-vcloud-authorization", token) + .build()) + .build(); + + HttpResponse catalogResponse = HttpResponse.builder() + .statusCode(200) + .payload(payloadFromResourceWithContentType("/catalog/catalogMetadata.xml", VCloudDirectorMediaType.METADATA)) + .build(); + + VCloudDirectorClient client = requestsSendResponses(loginRequest, sessionResponse, catalogRequest, catalogResponse); + + Reference catalogRef = Reference.builder() + .type("application/vnd.vmware.vcloud.catalog+xml") + .name("QunyingTestCatalog") + .href(URI.create(endpoint + "/catalog/7212e451-76e1-4631-b2de-ba1dfd8080e4")) + .build(); + + Metadata expected = Metadata.builder() + .type("application/vnd.vmware.vcloud.metadata+xml") + .href(URI.create("https://vcloudbeta.bluelock.com/api/catalog/7212e451-76e1-4631-b2de-ba1dfd8080e4/metadata")) + .link(Link.builder() + .rel("up") + .type("application/vnd.vmware.vcloud.catalog+xml") + .href(URI.create("https://vcloudbeta.bluelock.com/api/catalog/7212e451-76e1-4631-b2de-ba1dfd8080e4")) + .build()) + .entries(ImmutableSet.of(metadataEntry())) + .build(); + + assertEquals(client.getCatalogClient().getCatalogMetadata(catalogRef), expected); + } + + @Test + public void testGetCatalogMetadataEntry() { + HttpRequest catalogRequest = HttpRequest.builder() + .method("GET") + .endpoint(URI.create(endpoint + "/catalog/7212e451-76e1-4631-b2de-ba1dfd8080e4/metadata/KEY")) + .headers(ImmutableMultimap. builder() + .put("Accept", "*/*") + .put("x-vcloud-authorization", token) + .build()) + .build(); + + HttpResponse catalogResponse = HttpResponse.builder() + .statusCode(200) + .payload(payloadFromResourceWithContentType("/catalog/catalogMetadataEntry.xml", VCloudDirectorMediaType.METADATA_ENTRY)) + .build(); + + VCloudDirectorClient client = requestsSendResponses(loginRequest, sessionResponse, catalogRequest, catalogResponse); + + Reference catalogRef = Reference.builder() + .type("application/vnd.vmware.vcloud.catalog+xml") + .name("QunyingTestCatalog") + .href(URI.create(endpoint + "/catalog/7212e451-76e1-4631-b2de-ba1dfd8080e4")) + .build(); + + MetadataEntry expected = metadataEntry(); + + assertEquals(client.getCatalogClient().getCatalogMetadataEntry(catalogRef, "KEY"), expected); + } + + @Test + public void testGetCatalogItem() { + HttpRequest catalogItemRequest = HttpRequest.builder() + .method("GET") + .endpoint(URI.create(endpoint + "/catalogItem/a36fdac9-b8c2-43e2-9a4c-2ffaf3ee13df")) + .headers(ImmutableMultimap. builder() + .put("Accept", "*/*") + .put("x-vcloud-authorization", token) + .build()) + .build(); + + HttpResponse catalogItemResponse = HttpResponse.builder() + .statusCode(200) + .payload(payloadFromResourceWithContentType("/catalog/catalogItem.xml", VCloudDirectorMediaType.CATALOG_ITEM)) + .build(); + + VCloudDirectorClient client = requestsSendResponses(loginRequest, sessionResponse, catalogItemRequest, catalogItemResponse); + + Reference catalogItemReference = Reference.builder() + .type("application/vnd.vmware.vcloud.catalogItem+xml") + .name("ubuntu10") + .href(URI.create("https://vcloudbeta.bluelock.com/api/catalogItem/a36fdac9-b8c2-43e2-9a4c-2ffaf3ee13df")) + .build(); + + CatalogItem expected = catalogItem(); + + assertEquals(client.getCatalogClient().getCatalogItem(catalogItemReference), expected); + } + + @Test + public void testUpdateCatalogItem() { + HttpRequest catalogItemRequest = HttpRequest.builder() + .method("PUT") + .endpoint(URI.create(endpoint + "/catalogItem/a36fdac9-b8c2-43e2-9a4c-2ffaf3ee13df")) + .headers(ImmutableMultimap. builder() + .put("Accept", "application/vnd.vmware.vcloud.catalogItem+xml") + .put("x-vcloud-authorization", token) + .build()) + .payload(payloadFromResourceWithContentType("/catalog/updateCatalogItem.xml", VCloudDirectorMediaType.CATALOG_ITEM)) + .build(); + + HttpResponse catalogItemResponse = HttpResponse.builder() + .statusCode(200) + .payload(payloadFromResourceWithContentType("/catalog/updateCatalogItem.xml", VCloudDirectorMediaType.CATALOG_ITEM + ";version=1.5")) + .build(); + + VCloudDirectorClient client = requestsSendResponses(loginRequest, sessionResponse, catalogItemRequest, catalogItemResponse); + + Reference catalogItemReference = Reference.builder() + .type("application/vnd.vmware.vcloud.catalogItem+xml") + .name("ubuntu10") + .href(URI.create("https://vcloudbeta.bluelock.com/api/catalogItem/a36fdac9-b8c2-43e2-9a4c-2ffaf3ee13df")) + .build(); + + CatalogItem expected = catalogItem(); + + assertEquals(client.getCatalogClient().updateCatalogItem(catalogItemReference, expected), expected); + } + + @Test + public void testDeleteCatalogItem() { + HttpRequest catalogItemRequest = HttpRequest.builder() + .method("DELETE") + .endpoint(URI.create(endpoint + "/catalogItem/a36fdac9-b8c2-43e2-9a4c-2ffaf3ee13df")) + .headers(ImmutableMultimap. builder() + .put("Accept", "*/*") + .put("x-vcloud-authorization", token) + .build()) + .build(); + + HttpResponse catalogItemResponse = HttpResponse.builder() + .statusCode(200) + .build(); + + VCloudDirectorClient client = requestsSendResponses(loginRequest, sessionResponse, catalogItemRequest, catalogItemResponse); + + Reference catalogItemReference = Reference.builder() + .type("application/vnd.vmware.vcloud.catalogItem+xml") + .name("ubuntu10") + .href(URI.create("https://vcloudbeta.bluelock.com/api/catalogItem/a36fdac9-b8c2-43e2-9a4c-2ffaf3ee13df")) + .build(); + + client.getCatalogClient().deleteCatalogItem(catalogItemReference); + } + + @Test + public void testGetCatalogItemMetadata() { + HttpRequest catalogItemRequest = HttpRequest.builder() + .method("GET") + .endpoint(URI.create(endpoint + "/catalogItem/a36fdac9-b8c2-43e2-9a4c-2ffaf3ee13df/metadata")) + .headers(ImmutableMultimap. builder() + .put("Accept", "*/*") + .put("x-vcloud-authorization", token) + .build()) + .build(); + + HttpResponse catalogItemResponse = HttpResponse.builder() + .statusCode(200) + .payload(payloadFromResourceWithContentType("/catalog/catalogItemMetadata.xml", VCloudDirectorMediaType.METADATA)) + .build(); + + VCloudDirectorClient client = requestsSendResponses(loginRequest, sessionResponse, catalogItemRequest, catalogItemResponse); + + Reference catalogItemReference = Reference.builder() + .type("application/vnd.vmware.vcloud.catalogItem+xml") + .name("ubuntu10") + .href(URI.create("https://vcloudbeta.bluelock.com/api/catalogItem/a36fdac9-b8c2-43e2-9a4c-2ffaf3ee13df")) + .build(); + + Metadata expected = Metadata.builder() + .type("application/vnd.vmware.vcloud.metadata+xml") + .href(URI.create("https://vcloudbeta.bluelock.com/api/catalogItem/a36fdac9-b8c2-43e2-9a4c-2ffaf3ee13df/metadata")) + .link(Link.builder() + .rel("up") + .type("application/vnd.vmware.vcloud.catalogItem+xml") + .href(URI.create("https://vcloudbeta.bluelock.com/api/catalogItem/a36fdac9-b8c2-43e2-9a4c-2ffaf3ee13df")) + .build()) + .entries(ImmutableSet.of(itemMetadataEntry())) + .build(); + + assertEquals(client.getCatalogClient().getCatalogItemMetadata(catalogItemReference), expected); + } + + @Test + public void testMergeCatalogItemMetadata() { + HttpRequest catalogItemRequest = HttpRequest.builder() + .method("POST") + .endpoint(URI.create(endpoint + "/catalogItem/a36fdac9-b8c2-43e2-9a4c-2ffaf3ee13df/metadata")) + .headers(ImmutableMultimap. builder() + .put("Accept", "application/vnd.vmware.vcloud.task+xml") + .put("x-vcloud-authorization", token) + .build()) + .payload(payloadFromResourceWithContentType("/catalog/mergeCatalogItemMetadata.xml", VCloudDirectorMediaType.METADATA)) + .build(); + + HttpResponse catalogItemResponse = HttpResponse.builder() + .statusCode(200) + .payload(payloadFromResourceWithContentType("/catalog/mergeMetadataTask.xml", VCloudDirectorMediaType.TASK + ";version=1.5")) + .build(); + + VCloudDirectorClient client = requestsSendResponses(loginRequest, sessionResponse, catalogItemRequest, catalogItemResponse); + + Reference catalogItemReference = Reference.builder() + .type("application/vnd.vmware.vcloud.catalogItem+xml") + .name("ubuntu10") + .href(URI.create("https://vcloudbeta.bluelock.com/api/catalogItem/a36fdac9-b8c2-43e2-9a4c-2ffaf3ee13df")) + .build(); + + Metadata metadata = Metadata.builder().entry(MetadataEntry.builder().entry("KEY", "VALUE").build()).build(); + + Task expected = mergeMetadataTask(); + + assertEquals(client.getCatalogClient().mergeCatalogItemMetadata(catalogItemReference, metadata), expected); + } + + @Test + public void testGetCatalogItemMetadataEntry() { + HttpRequest catalogItemRequest = HttpRequest.builder() + .method("GET") + .endpoint(URI.create(endpoint + "/catalogItem/a36fdac9-b8c2-43e2-9a4c-2ffaf3ee13df/metadata/KEY")) + .headers(ImmutableMultimap. builder() + .put("Accept", "*/*") + .put("x-vcloud-authorization", token) + .build()) + .build(); + + HttpResponse catalogItemResponse = HttpResponse.builder() + .statusCode(200) + .payload(payloadFromResourceWithContentType("/catalog/catalogItemMetadataEntry.xml", VCloudDirectorMediaType.METADATA_ENTRY + ";version=1.5")) + .build(); + + VCloudDirectorClient client = requestsSendResponses(loginRequest, sessionResponse, catalogItemRequest, catalogItemResponse); + + Reference catalogItemReference = Reference.builder() + .type("application/vnd.vmware.vcloud.catalogItem+xml") + .name("ubuntu10") + .href(URI.create("https://vcloudbeta.bluelock.com/api/catalogItem/a36fdac9-b8c2-43e2-9a4c-2ffaf3ee13df")) + .build(); + + MetadataEntry expected = itemMetadataEntry(); + + assertEquals(client.getCatalogClient().getCatalogItemMetadataEntry(catalogItemReference, "KEY"), expected); + } + + @Test + public void testSetCatalogItemMetadataEntry() { + HttpRequest catalogItemRequest = HttpRequest.builder() + .method("PUT") + .endpoint(URI.create(endpoint + "/catalogItem/a36fdac9-b8c2-43e2-9a4c-2ffaf3ee13df/metadata/KEY")) + .headers(ImmutableMultimap. builder() + .put("Accept", "application/vnd.vmware.vcloud.task+xml") + .put("x-vcloud-authorization", token) + .build()) + .payload(payloadFromResourceWithContentType("/catalog/setCatalogItemMetadataValue.xml", VCloudDirectorMediaType.METADATA_VALUE)) + .build(); + + HttpResponse catalogItemResponse = HttpResponse.builder() + .statusCode(200) + .payload(payloadFromResourceWithContentType("/catalog/setMetadataValueTask.xml", VCloudDirectorMediaType.TASK + ";version=1.5")) + .build(); + + VCloudDirectorClient client = requestsSendResponses(loginRequest, sessionResponse, catalogItemRequest, catalogItemResponse); + + Reference catalogItemReference = Reference.builder() + .type("application/vnd.vmware.vcloud.catalogItem+xml") + .name("ubuntu10") + .href(URI.create("https://vcloudbeta.bluelock.com/api/catalogItem/a36fdac9-b8c2-43e2-9a4c-2ffaf3ee13df")) + .build(); + + MetadataValue value = MetadataValue.builder().value("KITTENS").build(); + + Task expected = setMetadataValueTask(); + + assertEquals(client.getCatalogClient().setCatalogItemMetadataEntry(catalogItemReference, "KEY", value), expected); + } + + @Test + public void testDeleteCatalogItemMetadataEntry() { + HttpRequest catalogItemRequest = HttpRequest.builder() + .method("DELETE") + .endpoint(URI.create(endpoint + "/catalogItem/a36fdac9-b8c2-43e2-9a4c-2ffaf3ee13df/metadata/KEY")) + .headers(ImmutableMultimap. builder() + .put("Accept", "*/*") + .put("x-vcloud-authorization", token) + .build()) + .build(); + + HttpResponse catalogItemResponse = HttpResponse.builder() + .statusCode(200) + .payload(payloadFromResourceWithContentType("/catalog/deleteMetadataEntryTask.xml", VCloudDirectorMediaType.TASK)) + .build(); + + VCloudDirectorClient client = requestsSendResponses(loginRequest, sessionResponse, catalogItemRequest, catalogItemResponse); + + Reference catalogItemReference = Reference.builder() + .type("application/vnd.vmware.vcloud.catalogItem+xml") + .name("ubuntu10") + .href(URI.create("https://vcloudbeta.bluelock.com/api/catalogItem/a36fdac9-b8c2-43e2-9a4c-2ffaf3ee13df")) + .build(); + + Task expected = deleteMetadataEntryTask(); + + assertEquals(client.getCatalogClient().deleteCatalogItemMetadataEntry(catalogItemReference, "KEY"), expected); + } + + public static final Catalog catalog() { + return Catalog.builder() + .name("QunyingTestCatalog") + .type("application/vnd.vmware.vcloud.catalog+xml") + .id("urn:vcloud:catalog:7212e451-76e1-4631-b2de-ba1dfd8080e4") + .href(URI.create("https://vcloudbeta.bluelock.com/api/catalog/7212e451-76e1-4631-b2de-ba1dfd8080e4")) + .link(Link.builder() + .rel("up") + .type("application/vnd.vmware.vcloud.org+xml") + .href(URI.create("https://vcloudbeta.bluelock.com/api/org/6f312e42-cd2b-488d-a2bb-97519cd57ed0")) + .build()) + .link(Link.builder() + .rel("add") + .type("application/vnd.vmware.vcloud.catalogItem+xml") + .href(URI.create("https://vcloudbeta.bluelock.com/api/catalog/7212e451-76e1-4631-b2de-ba1dfd8080e4/catalogItems")) + .build()) + .link(Link.builder() + .rel("down") + .type("application/vnd.vmware.vcloud.metadata+xml") + .href(URI.create("https://vcloudbeta.bluelock.com/api/catalog/7212e451-76e1-4631-b2de-ba1dfd8080e4/metadata")) + .build()) + .catalogItems(CatalogItems.builder() + .item(Reference.builder() + .type("application/vnd.vmware.vcloud.catalogItem+xml") + .name("ubuntu10") + .href(URI.create("https://vcloudbeta.bluelock.com/api/catalogItem/a36fdac9-b8c2-43e2-9a4c-2ffaf3ee13df")) + .build()) + .item(Reference.builder() + .type("application/vnd.vmware.vcloud.catalogItem+xml") + .name("imageTesting") + .href(URI.create("https://vcloudbeta.bluelock.com/api/catalogItem/a9e0afdb-a42b-4688-8409-2ac68cf22939")) + .build()) + .build()) + .description("Testing") + .build(); + } + + public static CatalogItem createdCatalogItem() { + return CatalogItem.builder() + .name("newCatalogItem") + .id("urn:vcloud:catalogitem:a36fdac9-b8c2-43e2-9a4c-2ffaf3ee13df") + .type("application/vnd.vmware.vcloud.catalogItem+xml") + .href(URI.create("https://vcloudbeta.bluelock.com/api/catalogItem/a36fdac9-b8c2-43e2-9a4c-2ffaf3ee13df")) + .link(Link.builder() + .rel("up") + .type("application/vnd.vmware.vcloud.catalog+xml") + .href(URI.create("https://vcloudbeta.bluelock.com/api/catalog/7212e451-76e1-4631-b2de-ba1dfd8080e4")) + .build()) + .link(Link.builder() + .rel("down") + .type("application/vnd.vmware.vcloud.metadata+xml") + .href(URI.create("https://vcloudbeta.bluelock.com/api/catalogItem/a36fdac9-b8c2-43e2-9a4c-2ffaf3ee13df/metadata")) + .build()) + .link(Link.builder() + .rel("edit") + .type("application/vnd.vmware.vcloud.catalogItem+xml") + .href(URI.create("https://vcloudbeta.bluelock.com/api/catalogItem/a36fdac9-b8c2-43e2-9a4c-2ffaf3ee13df")) + .build()) + .link(Link.builder() + .rel("remove") + .href(URI.create("https://vcloudbeta.bluelock.com/api/catalogItem/a36fdac9-b8c2-43e2-9a4c-2ffaf3ee13df")) + .build()) + .description("New Catalog Item") + .entity(ubuntuVappTemplateReference()) + .build(); + } + + public static Reference ubuntuVappTemplateReference() { + return Reference.builder() + .type("application/vnd.vmware.vcloud.vAppTemplate+xml") + .name("ubuntu10") + .href(URI.create("https://vcloudbeta.bluelock.com/api/vAppTemplate/vappTemplate-ef4415e6-d413-4cbb-9262-f9bbec5f2ea9")) + .build(); + } + + public static MetadataEntry metadataEntry() { + return MetadataEntry.builder() + .href(URI.create("https://vcloudbeta.bluelock.com/api/catalog/7212e451-76e1-4631-b2de-ba1dfd8080e4/metadata/KEY")) + .link(Link.builder() + .rel("up") + .type("application/vnd.vmware.vcloud.metadata+xml") + .href(URI.create("https://vcloudbeta.bluelock.com/api/catalog/7212e451-76e1-4631-b2de-ba1dfd8080e4/metadata")) + .build()) + .entry("KEY", "VALUE") + .build(); + } + + public static MetadataEntry itemMetadataEntry() { + return MetadataEntry.builder() + .href(URI.create("https://vcloudbeta.bluelock.com/api/catalogItem/a36fdac9-b8c2-43e2-9a4c-2ffaf3ee13df/metadata/KEY")) + .link(Link.builder() + .rel("up") + .type("application/vnd.vmware.vcloud.metadata+xml") + .href(URI.create("https://vcloudbeta.bluelock.com/api/catalogItem/a36fdac9-b8c2-43e2-9a4c-2ffaf3ee13df/metadata")) + .build()) + .entry("KEY", "VALUE") + .build(); + } + + public static CatalogItem catalogItem() { + return CatalogItem.builder() + .name("ubuntu10") .id("urn:vcloud:catalogitem:a36fdac9-b8c2-43e2-9a4c-2ffaf3ee13df") .type("application/vnd.vmware.vcloud.catalogItem+xml") .href(URI.create("https://vcloudbeta.bluelock.com/api/catalogItem/a36fdac9-b8c2-43e2-9a4c-2ffaf3ee13df")) @@ -171,48 +550,108 @@ public class CatalogClientExpectTest extends BaseVCloudDirectorRestClientExpectT .rel("remove") .href(URI.create("https://vcloudbeta.bluelock.com/api/catalogItem/a36fdac9-b8c2-43e2-9a4c-2ffaf3ee13df")) .build()) - .description("New Catalog Item") - .entity(ubuntu) + .description("For testing") + .entity(ubuntuVappTemplateReference()) .build(); - - assertEquals(client.getCatalogClient().addCatalogItem(catalogRef, newItem), expected); } - @Test - public void testGetCatalogMetadata() { - HttpRequest catalogItemRequest = HttpRequest.builder() - .method("GET") - .endpoint(URI.create(endpoint + "/catalog/7212e451-76e1-4631-b2de-ba1dfd8080e4/metadata")) - .headers(ImmutableMultimap. builder() - .put("Accept", "*/*") - .put("x-vcloud-authorization", token) - .build()) - .build(); - - HttpResponse catalogItemResponse = HttpResponse.builder() - .statusCode(200) - .payload(payloadFromResourceWithContentType("/catalog/catalogMetadata.xml", VCloudDirectorMediaType.METADATA + ";version=1.5")) - .build(); - - VCloudDirectorClient client = requestsSendResponses(loginRequest, sessionResponse, catalogItemRequest, catalogItemResponse); - - Reference catalogRef = Reference.builder() - .type("application/vnd.vmware.vcloud.catalog+xml") - .name("QunyingTestCatalog") - .href(URI.create(endpoint + "/catalog/7212e451-76e1-4631-b2de-ba1dfd8080e4")) - .build(); - - Metadata expected = Metadata.builder() - .type("application/vnd.vmware.vcloud.metadata+xml") - .href(URI.create("https://vcloudbeta.bluelock.com/api//catalog/7212e451-76e1-4631-b2de-ba1dfd8080e4/metadata")) + public static Task mergeMetadataTask() { + return Task.builder() + .name("task") + .id("urn:vcloud:task:c6dca927-eab4-41fa-ad6a-3ac58602541c") + .type("application/vnd.vmware.vcloud.task+xml") + .href(URI.create("https://vcloudbeta.bluelock.com/api/task/c6dca927-eab4-41fa-ad6a-3ac58602541c")) + .status("running") + .startTime(dateService.iso8601DateParse("2012-02-13T06:35:08.011-05:00")) + .expiryTime(dateService.iso8601DateParse("2012-05-13T06:35:08.011-04:00")) + .operationName("metadataUpdate") + .operation("Updating metadata for Catalog Item (a36fdac9-b8c2-43e2-9a4c-2ffaf3ee13df)") .link(Link.builder() - .rel("up") - .type("application/vnd.vmware.vcloud.catalog+xml") - .href(URI.create("https://vcloudbeta.bluelock.com/api/catalog/7212e451-76e1-4631-b2de-ba1dfd8080e4")) + .rel("task:cancel") + .href(URI.create("https://vcloudbeta.bluelock.com/api/task/c6dca927-eab4-41fa-ad6a-3ac58602541c/action/cancel")) + .build()) + .owner(Reference.builder() + .type("application/vnd.vmware.vcloud.catalogItem+xml") + .name("") + .href(URI.create("https://vcloudbeta.bluelock.com/api/catalogItem/a36fdac9-b8c2-43e2-9a4c-2ffaf3ee13df")) + .build()) + .user(Reference.builder() + .type("application/vnd.vmware.admin.user+xml") + .name("adk@cloudsoftcorp.com") + .href(URI.create("https://vcloudbeta.bluelock.com/api/admin/user/e9eb1b29-0404-4c5e-8ef7-e584acc51da9")) + .build()) + .org(Reference.builder() + .type("application/vnd.vmware.vcloud.org+xml") + .name("JClouds") + .href(URI.create("https://vcloudbeta.bluelock.com/api/org/6f312e42-cd2b-488d-a2bb-97519cd57ed0")) + .build()) + .build(); + } + + public static Task setMetadataValueTask() { + return Task.builder() + .name("task") + .id("urn:vcloud:task:c6dca927-eab4-41fa-ad6a-3ac58602541c") + .type("application/vnd.vmware.vcloud.task+xml") + .href(URI.create("https://vcloudbeta.bluelock.com/api/task/c6dca927-eab4-41fa-ad6a-3ac58602541c")) + .status("running") + .startTime(dateService.iso8601DateParse("2012-02-13T06:35:08.011-05:00")) + .expiryTime(dateService.iso8601DateParse("2012-05-13T06:35:08.011-04:00")) + .operationName("metadataSet") + .operation("Setting metadata for Catalog Item (a36fdac9-b8c2-43e2-9a4c-2ffaf3ee13df)") + .link(Link.builder() + .rel("task:cancel") + .href(URI.create("https://vcloudbeta.bluelock.com/api/task/c6dca927-eab4-41fa-ad6a-3ac58602541c/action/cancel")) + .build()) + .owner(Reference.builder() + .type("application/vnd.vmware.vcloud.catalogItem+xml") + .name("") + .href(URI.create("https://vcloudbeta.bluelock.com/api/catalogItem/a36fdac9-b8c2-43e2-9a4c-2ffaf3ee13df")) + .build()) + .user(Reference.builder() + .type("application/vnd.vmware.admin.user+xml") + .name("adk@cloudsoftcorp.com") + .href(URI.create("https://vcloudbeta.bluelock.com/api/admin/user/e9eb1b29-0404-4c5e-8ef7-e584acc51da9")) + .build()) + .org(Reference.builder() + .type("application/vnd.vmware.vcloud.org+xml") + .name("JClouds") + .href(URI.create("https://vcloudbeta.bluelock.com/api/org/6f312e42-cd2b-488d-a2bb-97519cd57ed0")) + .build()) + .build(); + } + + public static Task deleteMetadataEntryTask() { + return Task.builder() + .name("task") + .id("urn:vcloud:task:c6dca927-eab4-41fa-ad6a-3ac58602541c") + .type("application/vnd.vmware.vcloud.task+xml") + .href(URI.create("https://vcloudbeta.bluelock.com/api/task/c6dca927-eab4-41fa-ad6a-3ac58602541c")) + .status("running") + .startTime(dateService.iso8601DateParse("2012-02-13T06:35:08.011-05:00")) + .expiryTime(dateService.iso8601DateParse("2012-05-13T06:35:08.011-04:00")) + .operationName("metadataDelete") + .operation("Deleting metadata for Catalog Item (a36fdac9-b8c2-43e2-9a4c-2ffaf3ee13df)") + .link(Link.builder() + .rel("task:cancel") + .href(URI.create("https://vcloudbeta.bluelock.com/api/task/c6dca927-eab4-41fa-ad6a-3ac58602541c/action/cancel")) + .build()) + .owner(Reference.builder() + .type("application/vnd.vmware.vcloud.catalogItem+xml") + .name("") + .href(URI.create("https://vcloudbeta.bluelock.com/api/catalogItem/a36fdac9-b8c2-43e2-9a4c-2ffaf3ee13df")) + .build()) + .user(Reference.builder() + .type("application/vnd.vmware.admin.user+xml") + .name("adk@cloudsoftcorp.com") + .href(URI.create("https://vcloudbeta.bluelock.com/api/admin/user/e9eb1b29-0404-4c5e-8ef7-e584acc51da9")) + .build()) + .org(Reference.builder() + .type("application/vnd.vmware.vcloud.org+xml") + .name("JClouds") + .href(URI.create("https://vcloudbeta.bluelock.com/api/org/6f312e42-cd2b-488d-a2bb-97519cd57ed0")) .build()) - .metadata(ImmutableSet.of(MetadataEntry.builder().entry("key", "value").build())) .build(); - - assertEquals(client.getCatalogClient().getCatalogMetadata(catalogRef), expected); } } + diff --git a/labs/vcloud-director/src/test/java/org/jclouds/vcloud/director/v1_5/features/CatalogClientLiveTest.java b/labs/vcloud-director/src/test/java/org/jclouds/vcloud/director/v1_5/features/CatalogClientLiveTest.java new file mode 100644 index 0000000000..ba26090415 --- /dev/null +++ b/labs/vcloud-director/src/test/java/org/jclouds/vcloud/director/v1_5/features/CatalogClientLiveTest.java @@ -0,0 +1,87 @@ +/* + * 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.vcloud.director.v1_5.features; + +import static org.jclouds.vcloud.director.v1_5.domain.Checks.checkTask; +import static org.testng.Assert.assertFalse; + +import java.net.URI; + +import org.jclouds.vcloud.director.v1_5.domain.OrgList; +import org.jclouds.vcloud.director.v1_5.domain.Reference; +import org.jclouds.vcloud.director.v1_5.domain.Task; +import org.jclouds.vcloud.director.v1_5.domain.TasksList; +import org.jclouds.vcloud.director.v1_5.internal.BaseVCloudDirectorClientLiveTest; +import org.testng.annotations.Test; + +import com.google.common.collect.Iterables; + +/** +* Tests live behavior of {@link taskClient}. +* +* @author grkvlt@apache.task +*/ +@Test(groups = { "live", "apitests" }, testName = "TaskClientLiveTest") +public class CatalogClientLiveTest extends BaseVCloudDirectorClientLiveTest { + + /* + * Shared state between dependant tests. + */ + + private OrgList orgList; + private Reference orgRef; + private TasksList taskList; + private Task task; + private URI taskUri; + + @Test(testName = "GET /tasksList/{id}") + public void testGetTaskList() { + orgList = context.getApi().getOrgClient().getOrgList(); + orgRef = Iterables.getFirst(orgList.getOrgs(), null); + + // Call the method being tested + taskList = context.getApi().getTaskClient().getTaskList(orgRef); + + // NOTE The environment MUST have ... + + // Check required elements and attributes + assertFalse(Iterables.isEmpty(taskList.getTasks()), "There must always be Task elements in the TaskList"); + + for (Task task : taskList.getTasks()) { + checkTask(task); + } + } + + @Test(testName = "GET /task/{id}", dependsOnMethods = { "testGetTaskList" }) + public void testGetTask() { + taskUri = Iterables.getFirst(taskList.getTasks(), null).getHref(); + + // Call the method being tested + task = context.getApi().getTaskClient().getTask(taskUri); + + // Check required elements and attributes + checkTask(task); + } + + @Test(testName = "GET /task/{id}/metadata/", dependsOnMethods = { "testGetTask" }) + public void testCancelTask() { + // Call the method being tested + context.getApi().getTaskClient().cancelTask(taskUri); + } +} \ No newline at end of file diff --git a/labs/vcloud-director/src/test/java/org/jclouds/vcloud/director/v1_5/features/MediaClientExpectTest.java b/labs/vcloud-director/src/test/java/org/jclouds/vcloud/director/v1_5/features/MediaClientExpectTest.java new file mode 100644 index 0000000000..43677c8291 --- /dev/null +++ b/labs/vcloud-director/src/test/java/org/jclouds/vcloud/director/v1_5/features/MediaClientExpectTest.java @@ -0,0 +1,646 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + *(Link.builder().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(Link.builder().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.vcloud.director.v1_5.features; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.fail; + +import java.net.URI; + +import org.jclouds.vcloud.director.v1_5.VCloudDirectorClient; +import org.jclouds.vcloud.director.v1_5.VCloudDirectorException; +import org.jclouds.vcloud.director.v1_5.VCloudDirectorMediaType; +import org.jclouds.vcloud.director.v1_5.domain.Error; +import org.jclouds.vcloud.director.v1_5.domain.Link; +import org.jclouds.vcloud.director.v1_5.domain.Media; +import org.jclouds.vcloud.director.v1_5.domain.Metadata; +import org.jclouds.vcloud.director.v1_5.domain.MetadataEntry; +import org.jclouds.vcloud.director.v1_5.domain.MetadataValue; +import org.jclouds.vcloud.director.v1_5.domain.Owner; +import org.jclouds.vcloud.director.v1_5.domain.Reference; +import org.jclouds.vcloud.director.v1_5.domain.Task; +import org.jclouds.vcloud.director.v1_5.internal.BaseVCloudDirectorRestClientExpectTest; +import org.testng.annotations.Test; + +/** + * Allows us to test a client via its side effects. + * + * @author danikov + */ +@Test(groups = "unit", singleThreaded = true, testName = "NetworkClientExpectTest") +public class MediaClientExpectTest extends BaseVCloudDirectorRestClientExpectTest { + + @Test + public void testGetMedia() { + URI mediaUri = URI.create(endpoint + "/media/794eb334-754e-4917-b5a0-5df85cbd61d1"); + + VCloudDirectorClient client = requestsSendResponses(loginRequest, sessionResponse, + new VcloudHttpRequestPrimer() + .apiCommand("GET", "/media/794eb334-754e-4917-b5a0-5df85cbd61d1") + .acceptAnyMedia() + .httpRequestBuilder().build(), + new VcloudHttpResponsePrimer() + .xmlFilePayload("/media/media.xml", VCloudDirectorMediaType.MEDIA) + .httpResponseBuilder().build()); + + Media expected = media(); + + Reference mediaRef = Reference.builder().href(mediaUri).build(); + + assertEquals(client.getMediaClient().getMedia(mediaRef), expected); + } + + public void testResponse400ForInvalidMedia() { + URI mediaUri = URI.create(endpoint + "/media/NOTAUUID"); + + VCloudDirectorClient client = requestsSendResponses(loginRequest, sessionResponse, + new VcloudHttpRequestPrimer() + .apiCommand("GET", "/media/NOTAUUID") + .acceptAnyMedia() + .httpRequestBuilder().build(), + new VcloudHttpResponsePrimer() + .xmlFilePayload("/media/error400.xml", VCloudDirectorMediaType.ERROR) + .httpResponseBuilder().statusCode(400).build()); + + Error expected = Error.builder() + .message("validation error on field 'id': String value has invalid format or length") + .majorErrorCode(400) + .minorErrorCode("BAD_REQUEST") + .build(); + + Reference mediaRef = Reference.builder().href(mediaUri).build(); + + try { + client.getMediaClient().getMedia(mediaRef); + fail("Should give HTTP 400 error"); + } catch (VCloudDirectorException vde) { + assertEquals(vde.getError(), expected); + } catch (Exception e) { + fail("Should have thrown a VCloudDirectorException"); + } + } + + @Test + public void testResponse403ForCatalogIdUsedAsMediaId() { + URI mediaUri = URI.create(endpoint + "/media/e9cd3387-ac57-4d27-a481-9bee75e0690f"); + + VCloudDirectorClient client = requestsSendResponses(loginRequest, sessionResponse, + new VcloudHttpRequestPrimer() + .apiCommand("GET", "/media/e9cd3387-ac57-4d27-a481-9bee75e0690f") + .acceptAnyMedia() + .httpRequestBuilder().build(), + new VcloudHttpResponsePrimer() + .xmlFilePayload("/media/error403-catalog.xml", VCloudDirectorMediaType.ERROR) + .httpResponseBuilder().statusCode(403).build()); + + Error expected = Error.builder() + .message("No access to entity \"(com.vmware.vcloud.entity.media:e9cd3387-ac57-4d27-a481-9bee75e0690f)\".") + .majorErrorCode(403) + .minorErrorCode("ACCESS_TO_RESOURCE_IS_FORBIDDEN") + .build(); + + Reference mediaRef = Reference.builder().href(mediaUri).build(); + + try { + client.getMediaClient().getMedia(mediaRef); + fail("Should give HTTP 403 error"); + } catch (VCloudDirectorException vde) { + assertEquals(vde.getError(), expected); + } catch (Exception e) { + fail("Should have thrown a VCloudDirectorException"); + } + } + + @Test + public void testResponse403ForFakeMediaId() { + URI mediaUri = URI.create(endpoint + "/media/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"); + + VCloudDirectorClient client = requestsSendResponses(loginRequest, sessionResponse, + new VcloudHttpRequestPrimer() + .apiCommand("GET", "/media/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee") + .acceptAnyMedia() + .httpRequestBuilder().build(), + new VcloudHttpResponsePrimer() + .xmlFilePayload("/media/error403-fake.xml", VCloudDirectorMediaType.ERROR) + .httpResponseBuilder().statusCode(403).build()); + + Error expected = Error.builder() + .message("No access to entity \"(com.vmware.vcloud.entity.media:aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee)\".") + .majorErrorCode(403) + .minorErrorCode("ACCESS_TO_RESOURCE_IS_FORBIDDEN") + .build(); + + Reference mediaRef = Reference.builder().href(mediaUri).build(); + + try { + client.getMediaClient().getMedia(mediaRef); + fail("Should give HTTP 403 error"); + } catch (VCloudDirectorException vde) { + assertEquals(vde.getError(), expected); + } catch (Exception e) { + fail("Should have thrown a VCloudDirectorException"); + } + } + + // TODO: fix this + @Test( enabled=false ) + public void testUpdateMedia() { + URI mediaUri = URI.create(endpoint + "/media/794eb334-754e-4917-b5a0-5df85cbd61d1"); + + VCloudDirectorClient client = requestsSendResponses(loginRequest, sessionResponse, + new VcloudHttpRequestPrimer() + .apiCommand("PUT", "/media/794eb334-754e-4917-b5a0-5df85cbd61d1") + .xmlFilePayload("/media/updateMedia.xml", VCloudDirectorMediaType.MEDIA) + .acceptMedia(VCloudDirectorMediaType.TASK) + .httpRequestBuilder().build(), + new VcloudHttpResponsePrimer() + .xmlFilePayload("/media/updateMediaTask.xml", VCloudDirectorMediaType.TASK) + .httpResponseBuilder().build()); + + Media update = updateMedia(); + Task expected = updateMediaTask(); + Reference mediaRef = Reference.builder().href(mediaUri).build(); + + assertEquals(client.getMediaClient().updateMedia(mediaRef, update), expected); + } + + @Test + public void testDeleteMedia() { + URI mediaUri = URI.create(endpoint + "/media/794eb334-754e-4917-b5a0-5df85cbd61d1"); + + VCloudDirectorClient client = requestsSendResponses(loginRequest, sessionResponse, + new VcloudHttpRequestPrimer() + .apiCommand("DELETE", "/media/794eb334-754e-4917-b5a0-5df85cbd61d1") + .acceptMedia(VCloudDirectorMediaType.TASK) + .httpRequestBuilder().build(), + new VcloudHttpResponsePrimer() + .xmlFilePayload("/media/deleteMediaTask.xml", VCloudDirectorMediaType.TASK) + .httpResponseBuilder().build()); + + Task expected = deleteMediaTask(); + Reference mediaRef = Reference.builder().href(mediaUri).build(); + + assertEquals(client.getMediaClient().deleteMedia(mediaRef), expected); + } + + @Test + public void testGetMetadata() { + URI mediaUri = URI.create("https://vcloudbeta.bluelock.com/api/media/794eb334-754e-4917-b5a0-5df85cbd61d1"); + + VCloudDirectorClient client = requestsSendResponses(loginRequest, sessionResponse, + new VcloudHttpRequestPrimer() + .apiCommand("GET", "/media/794eb334-754e-4917-b5a0-5df85cbd61d1/metadata") + .acceptAnyMedia() + .httpRequestBuilder().build(), + new VcloudHttpResponsePrimer() + .xmlFilePayload("/media/metadata.xml", VCloudDirectorMediaType.METADATA) + .httpResponseBuilder().build()); + + Reference mediaRef = Reference.builder().href(mediaUri).build(); + + Metadata expected = metadata(); + + assertEquals(client.getMediaClient().getMetadata(mediaRef), expected); + } + + @Test + public void testMergeMetadata() { + URI mediaUri = URI.create("https://vcloudbeta.bluelock.com/api/media/794eb334-754e-4917-b5a0-5df85cbd61d1"); + + VCloudDirectorClient client = requestsSendResponses(loginRequest, sessionResponse, + new VcloudHttpRequestPrimer() + .apiCommand("POST", "/media/794eb334-754e-4917-b5a0-5df85cbd61d1/metadata") + .xmlFilePayload("/media/mergeMetadata.xml", VCloudDirectorMediaType.METADATA) + .acceptMedia(VCloudDirectorMediaType.TASK) + .httpRequestBuilder().build(), + new VcloudHttpResponsePrimer() + .xmlFilePayload("/media/mergeMetadataTask.xml", VCloudDirectorMediaType.TASK) + .httpResponseBuilder().build()); + + Reference mediaRef = Reference.builder().href(mediaUri).build(); + Metadata inputMetadata = metadata(); + Task expectedTask = mergeMetadataTask(); + + assertEquals(client.getMediaClient().mergeMetadata(mediaRef, inputMetadata), expectedTask); + } + + public void testGetMetadataValue() { + URI mediaUri = URI.create("https://vcloudbeta.bluelock.com/api/media/794eb334-754e-4917-b5a0-5df85cbd61d1"); + + VCloudDirectorClient client = requestsSendResponses(loginRequest, sessionResponse, + new VcloudHttpRequestPrimer() + .apiCommand("GET", "/media/794eb334-754e-4917-b5a0-5df85cbd61d1/metadata/key") + .acceptAnyMedia() + .httpRequestBuilder().build(), + new VcloudHttpResponsePrimer() + .xmlFilePayload("/media/metadataValue.xml", VCloudDirectorMediaType.METADATA_VALUE) + .httpResponseBuilder().build()); + + MetadataValue expected = metadataValue(); + + Reference mediaRef = Reference.builder().href(mediaUri).build(); + + assertEquals(client.getMediaClient().getMetadataValue(mediaRef, "key"), expected); + } + + @Test + public void testSetMetadataValue() { + URI mediaUri = URI.create("https://vcloudbeta.bluelock.com/api/media/794eb334-754e-4917-b5a0-5df85cbd61d1"); + + VCloudDirectorClient client = requestsSendResponses(loginRequest, sessionResponse, + new VcloudHttpRequestPrimer() + .apiCommand("PUT", "/media/794eb334-754e-4917-b5a0-5df85cbd61d1/metadata/key") + .xmlFilePayload("/media/setMetadataValue.xml", VCloudDirectorMediaType.METADATA_VALUE) + .acceptMedia(VCloudDirectorMediaType.TASK) + .httpRequestBuilder().build(), + new VcloudHttpResponsePrimer() + .xmlFilePayload("/media/setMetadataValueTask.xml", VCloudDirectorMediaType.TASK) + .httpResponseBuilder().build()); + + Reference mediaRef = Reference.builder().href(mediaUri).build(); + MetadataValue inputMetadataValue = MetadataValue.builder().value("value").build(); + + Task expectedTask = setMetadataEntryTask(); + + assertEquals(client.getMediaClient().setMetadata(mediaRef, "key", inputMetadataValue), expectedTask); + } + + @Test + public void testDeleteMetadataValue() { + URI mediaUri = URI.create("https://vcloudbeta.bluelock.com/api/media/794eb334-754e-4917-b5a0-5df85cbd61d1"); + + VCloudDirectorClient client = requestsSendResponses(loginRequest, sessionResponse, + new VcloudHttpRequestPrimer() + .apiCommand("DELETE", "/media/794eb334-754e-4917-b5a0-5df85cbd61d1/metadata/key") + .acceptMedia(VCloudDirectorMediaType.TASK) + .httpRequestBuilder().build(), + new VcloudHttpResponsePrimer() + .xmlFilePayload("/media/deleteMetadataEntryTask.xml", VCloudDirectorMediaType.TASK) + .httpResponseBuilder().build()); + + Reference mediaRef = Reference.builder().href(mediaUri).build(); + Task expectedTask = deleteMetadataEntryTask(); + + assertEquals(client.getMediaClient().deleteMetadataEntry(mediaRef, "key"), expectedTask); + } + + @Test + public void testGetOwner() { + URI mediaUri = URI.create(endpoint + "/media/794eb334-754e-4917-b5a0-5df85cbd61d1"); + + VCloudDirectorClient client = requestsSendResponses(loginRequest, sessionResponse, + new VcloudHttpRequestPrimer() + .apiCommand("GET", "/media/794eb334-754e-4917-b5a0-5df85cbd61d1/owner") + .acceptAnyMedia() + .httpRequestBuilder().build(), + new VcloudHttpResponsePrimer() + .xmlFilePayload("/media/owner.xml", VCloudDirectorMediaType.OWNER) + .httpResponseBuilder().build()); + + Owner expected = owner(); + + Reference mediaRef = Reference.builder().href(mediaUri).build(); + + assertEquals(client.getMediaClient().getOwner(mediaRef), expected); + } + + private static Media media() { + return Media.builder() + .size(175163392) + .imageType("iso") + .status(1) + .name("DansTestMedia") + .id("urn:vcloud:media:794eb334-754e-4917-b5a0-5df85cbd61d1") + .href(URI.create("https://mycloud.greenhousedata.com/api/media/794eb334-754e-4917-b5a0-5df85cbd61d1")) + .link(Link.builder() + .rel("up") + .type("application/vnd.vmware.vcloud.vdc+xml") + .href(URI.create("https://mycloud.greenhousedata.com/api/vdc/e9cd3387-ac57-4d27-a481-9bee75e0690f")) + .build()) + .link(Link.builder() + .rel("catalogItem") + .type("application/vnd.vmware.vcloud.catalogItem+xml") + .href(URI.create("https://mycloud.greenhousedata.com/api/catalogItem/1979d680-304e-4118-9283-9210c3b3ed8d")) + .build()) + .link(Link.builder() + .rel("remove") + .href(URI.create("https://mycloud.greenhousedata.com/api/media/794eb334-754e-4917-b5a0-5df85cbd61d1")) + .build()) + .link(Link.builder() + .rel("edit") + .type("application/vnd.vmware.vcloud.media+xml") + .href(URI.create("https://mycloud.greenhousedata.com/api/media/794eb334-754e-4917-b5a0-5df85cbd61d1")) + .build()) + .link(Link.builder() + .rel("down") + .type("application/vnd.vmware.vcloud.owner+xml") + .href(URI.create("https://mycloud.greenhousedata.com/api/media/794eb334-754e-4917-b5a0-5df85cbd61d1/owner")) + .build()) + .link(Link.builder() + .rel("down") + .type("application/vnd.vmware.vcloud.metadata+xml") + .href(URI.create("https://mycloud.greenhousedata.com/api/media/794eb334-754e-4917-b5a0-5df85cbd61d1/metadata")) + .build()) + .description("Windows 2003 R2 Disk2 Standard 32bit & 64bit") + .owner(owner()) + .build(); + } + + private static Media updateMedia() { + return Media.builder() + .size(175163392) + .imageType("iso") + .status(1) + .name("new testMedia1") + .id("urn:vcloud:media:c93e5cdc-f29a-4749-8ed2-093df04cc75e") + .type("application/vnd.vmware.vcloud.media+xml") + .href(URI.create("https://mycloud.greenhousedata.com/api/media/c93e5cdc-f29a-4749-8ed2-093df04cc75e")) + .link(Link.builder() + .rel("up") + .type("application/vnd.vmware.vcloud.vdc+xml") + .href(URI.create("https://mycloud.greenhousedata.com/api/vdc/e9cd3387-ac57-4d27-a481-9bee75e0690f")) + .build()) + .link(Link.builder() + .rel("catalogItem") + .type("application/vnd.vmware.vcloud.catalogItem+xml") + .href(URI.create("https://mycloud.greenhousedata.com/api/catalogItem/1b317eb9-0e25-429a-ada2-3c7a74a0367b")) + .build()) + .link(Link.builder() + .rel("remove") + .type("application/vnd.vmware.vcloud.metadata+xml") + .href(URI.create("https://mycloud.greenhousedata.com/api/media/c93e5cdc-f29a-4749-8ed2-093df04cc75e")) + .build()) + .link(Link.builder() + .rel("edit") + .type("application/vnd.vmware.vcloud.media+xml") + .href(URI.create("https://mycloud.greenhousedata.com/api/media/c93e5cdc-f29a-4749-8ed2-093df04cc75e")) + .build()) + .link(Link.builder() + .rel("down") + .type("application/vnd.vmware.vcloud.owner+xml") + .href(URI.create("https://mycloud.greenhousedata.com/api/media/c93e5cdc-f29a-4749-8ed2-093df04cc75e/owner")) + .build()) + .link(Link.builder() + .rel("down") + .type("application/vnd.vmware.vcloud.metadata+xml") + .href(URI.create("https://mycloud.greenhousedata.com/api/media/c93e5cdc-f29a-4749-8ed2-093df04cc75e/metadata")) + .build()) + .description("new test description") + .owner(Owner.builder() + .user(Reference.builder() + .type("application/vnd.vmware.admin.user+xml") + .name("dan") + .href(URI.create("https://mycloud.greenhousedata.com/api/admin/user/7818d31c-df33-4d77-9bbc-0a0741cf3d44")) + .build()) + .build()) + .build(); + } + + private static Task updateMediaTask() { + return Task.builder() + .name("task") + .id("urn:vcloud:task:c6dca927-eab4-41fa-ad6a-3ac58602541c") + .type("application/vnd.vmware.vcloud.task+xml") + .href(URI.create("https://vcloudbeta.bluelock.com/api/task/c6dca927-eab4-41fa-ad6a-3ac58602541c")) + .status("running") + .startTime(dateService.iso8601DateParse("2012-02-13T06:35:08.011-05:00")) + .expiryTime(dateService.iso8601DateParse("2012-05-13T06:35:08.011-04:00")) + .operationName("mediaUpdate") + .operation("Updating Media (794eb334-754e-4917-b5a0-5df85cbd61d1)") + .link(Link.builder() + .rel("task:cancel") + .href(URI.create("https://vcloudbeta.bluelock.com/api/task/c6dca927-eab4-41fa-ad6a-3ac58602541c/action/cancel")) + .build()) + .owner(Reference.builder() + .type("application/vnd.vmware.vcloud.media+xml") + .name("") + .href(URI.create("https://vcloudbeta.bluelock.com/api/media/794eb334-754e-4917-b5a0-5df85cbd61d1")) + .build()) + .user(Reference.builder() + .type("application/vnd.vmware.admin.user+xml") + .name("adk@cloudsoftcorp.com") + .href(URI.create("https://vcloudbeta.bluelock.com/api/admin/user/e9eb1b29-0404-4c5e-8ef7-e584acc51da9")) + .build()) + .org(Reference.builder() + .type("application/vnd.vmware.vcloud.org+xml") + .name("JClouds") + .href(URI.create("https://vcloudbeta.bluelock.com/api/org/6f312e42-cd2b-488d-a2bb-97519cd57ed0")) + .build()) + .build(); + } + + public static Task deleteMediaTask() { + return Task.builder() + .name("task") + .id("urn:vcloud:task:c6dca927-eab4-41fa-ad6a-3ac58602541c") + .type("application/vnd.vmware.vcloud.task+xml") + .href(URI.create("https://vcloudbeta.bluelock.com/api/task/c6dca927-eab4-41fa-ad6a-3ac58602541c")) + .status("running") + .startTime(dateService.iso8601DateParse("2012-02-13T06:35:08.011-05:00")) + .expiryTime(dateService.iso8601DateParse("2012-05-13T06:35:08.011-04:00")) + .operationName("vdcDeleteMedia") + .operation("Deleting Media File (794eb334-754e-4917-b5a0-5df85cbd61d1)") + .link(Link.builder() + .rel("task:cancel") + .href(URI.create("https://vcloudbeta.bluelock.com/api/task/c6dca927-eab4-41fa-ad6a-3ac58602541c/action/cancel")) + .build()) + .owner(Reference.builder() + .type("application/vnd.vmware.vcloud.media+xml") + .name("") + .href(URI.create("https://vcloudbeta.bluelock.com/api/media/794eb334-754e-4917-b5a0-5df85cbd61d1")) + .build()) + .user(Reference.builder() + .type("application/vnd.vmware.admin.user+xml") + .name("adk@cloudsoftcorp.com") + .href(URI.create("https://vcloudbeta.bluelock.com/api/admin/user/e9eb1b29-0404-4c5e-8ef7-e584acc51da9")) + .build()) + .org(Reference.builder() + .type("application/vnd.vmware.vcloud.org+xml") + .name("JClouds") + .href(URI.create("https://vcloudbeta.bluelock.com/api/org/6f312e42-cd2b-488d-a2bb-97519cd57ed0")) + .build()) + .build(); + } + + private static Owner owner() { + return Owner.builder() + .type("application/vnd.vmware.vcloud.owner+xml") + .user(Reference.builder() + .type("application/vnd.vmware.admin.user+xml") + .name("acole") + .href(URI.create("https://mycloud.greenhousedata.com/api/admin/user/c090335b-708c-4c1c-9e3d-89560d002120")) + .build()) + .build(); + } + + private static Metadata metadata() { + return Metadata.builder() + .type("application/vnd.vmware.vcloud.metadata+xml") + .href(URI.create("https://mycloud.greenhousedata.com/api/media/c93e5cdc-f29a-4749-8ed2-093df04cc75e/metadata")) + .link(Link.builder() + .rel("up") + .type("application/vnd.vmware.vcloud.media+xml") + .href(URI.create("https://mycloud.greenhousedata.com/api/media/c93e5cdc-f29a-4749-8ed2-093df04cc75e")) + .build()) + .link(Link.builder() + .rel("add") + .type("application/vnd.vmware.vcloud.metadata+xml") + .href(URI.create("https://mycloud.greenhousedata.com/api/media/c93e5cdc-f29a-4749-8ed2-093df04cc75e/metadata")) + .build()) + .entry(MetadataEntry.builder() + .type("application/vnd.vmware.vcloud.metadata.value+xml") + .href(URI.create("https://mycloud.greenhousedata.com/api/media/c93e5cdc-f29a-4749-8ed2-093df04cc75e/metadata/key")) + .link(Link.builder() + .rel("up") + .type("application/vnd.vmware.vcloud.metadata+xml") + .href(URI.create("https://mycloud.greenhousedata.com/api/media/c93e5cdc-f29a-4749-8ed2-093df04cc75e/metadata")) + .build()) + .link(Link.builder() + .rel("edit") + .type("application/vnd.vmware.vcloud.metadata.value+xml") + .href(URI.create("https://mycloud.greenhousedata.com/api/media/c93e5cdc-f29a-4749-8ed2-093df04cc75e/metadata/key")) + .build()) + .link(Link.builder() + .rel("remove") + .href(URI.create("https://mycloud.greenhousedata.com/api/media/c93e5cdc-f29a-4749-8ed2-093df04cc75e/metadata/key")) + .build()) + .key("key").value("value").build()) + .build(); + } + + private static MetadataValue metadataValue() { + return MetadataValue.builder() + .type("application/vnd.vmware.vcloud.metadata.value+xml") + .href(URI.create("https://mycloud.greenhousedata.com/api/media/c93e5cdc-f29a-4749-8ed2-093df04cc75e/metadata/key")) + .link(Link.builder() + .rel("up") + .type("application/vnd.vmware.vcloud.metadata+xml") + .href(URI.create("https://mycloud.greenhousedata.com/api/media/c93e5cdc-f29a-4749-8ed2-093df04cc75e/metadata")) + .build()) + .link(Link.builder() + .rel("edit") + .type("application/vnd.vmware.vcloud.metadata.value+xml") + .href(URI.create("https://mycloud.greenhousedata.com/api/media/c93e5cdc-f29a-4749-8ed2-093df04cc75e/metadata/key")) + .build()) + .link(Link.builder() + .rel("remove") + .href(URI.create("https://mycloud.greenhousedata.com/api/media/c93e5cdc-f29a-4749-8ed2-093df04cc75e/metadata/key")) + .build()) + .value("value").build(); + } + + private Task mergeMetadataTask() { + return Task.builder() + .status("running") + .startTime(dateService.iso8601DateParse("2012-02-13T06:35:08.011-05:00")) + .operationName("metadataUpdate") + .operation("Updating metadata for Media File (794eb334-754e-4917-b5a0-5df85cbd61d1)") + .expiryTime(dateService.iso8601DateParse("2012-05-13T06:35:08.011-04:00")) + .name("task") + .id("urn:vcloud:task:c6dca927-eab4-41fa-ad6a-3ac58602541c") + .type("application/vnd.vmware.vcloud.task+xml") + .href(URI.create("https://vcloudbeta.bluelock.com/api/task/c6dca927-eab4-41fa-ad6a-3ac58602541c")) + .link(Link.builder() + .rel("task:cancel") + .href(URI.create("https://vcloudbeta.bluelock.com/api/task/c6dca927-eab4-41fa-ad6a-3ac58602541c/action/cancel")) + .build()) + .owner(Reference.builder() + .type("application/vnd.vmware.vcloud.media+xml") + .name("") + .href(URI.create("https://vcloudbeta.bluelock.com/api/media/794eb334-754e-4917-b5a0-5df85cbd61d1")) + .build()) + .user(Reference.builder() + .type("application/vnd.vmware.admin.user+xml") + .name("adk@cloudsoftcorp.com") + .href(URI.create("https://vcloudbeta.bluelock.com/api/admin/user/e9eb1b29-0404-4c5e-8ef7-e584acc51da9")) + .build()) + .org(Reference.builder() + .type("application/vnd.vmware.vcloud.org+xml") + .name("JClouds") + .href(URI.create("https://vcloudbeta.bluelock.com/api/org/6f312e42-cd2b-488d-a2bb-97519cd57ed0")) + .build()) + .build(); + } + + private Task setMetadataEntryTask() { + return Task.builder() + .status("running") + .startTime(dateService.iso8601DateParse("2012-02-13T06:35:08.011-05:00")) + .operationName("metadataUpdate") + .operation("Updating metadata for Media File (794eb334-754e-4917-b5a0-5df85cbd61d1)") + .expiryTime(dateService.iso8601DateParse("2012-05-13T06:35:08.011-04:00")) + .name("task") + .id("urn:vcloud:task:c6dca927-eab4-41fa-ad6a-3ac58602541c") + .type("application/vnd.vmware.vcloud.task+xml") + .href(URI.create("https://vcloudbeta.bluelock.com/api/task/c6dca927-eab4-41fa-ad6a-3ac58602541c")) + .link(Link.builder() + .rel("task:cancel") + .href(URI.create("https://vcloudbeta.bluelock.com/api/task/c6dca927-eab4-41fa-ad6a-3ac58602541c/action/cancel")) + .build()) + .owner(Reference.builder() + .type("application/vnd.vmware.vcloud.media+xml") + .name("") + .href(URI.create("https://vcloudbeta.bluelock.com/api/media/794eb334-754e-4917-b5a0-5df85cbd61d1")) + .build()) + .user(Reference.builder() + .type("application/vnd.vmware.admin.user+xml") + .name("adk@cloudsoftcorp.com") + .href(URI.create("https://vcloudbeta.bluelock.com/api/admin/user/e9eb1b29-0404-4c5e-8ef7-e584acc51da9")) + .build()) + .org(Reference.builder() + .type("application/vnd.vmware.vcloud.org+xml") + .name("JClouds") + .href(URI.create("https://vcloudbeta.bluelock.com/api/org/6f312e42-cd2b-488d-a2bb-97519cd57ed0")) + .build()) + .build(); + } + + public static Task deleteMetadataEntryTask() { + return Task.builder() + .name("task") + .id("urn:vcloud:task:c6dca927-eab4-41fa-ad6a-3ac58602541c") + .type("application/vnd.vmware.vcloud.task+xml") + .href(URI.create("https://vcloudbeta.bluelock.com/api/task/c6dca927-eab4-41fa-ad6a-3ac58602541c")) + .status("running") + .startTime(dateService.iso8601DateParse("2012-02-13T06:35:08.011-05:00")) + .expiryTime(dateService.iso8601DateParse("2012-05-13T06:35:08.011-04:00")) + .operationName("metadataDelete") + .operation("Deleting metadata for Media File (794eb334-754e-4917-b5a0-5df85cbd61d1)") + .link(Link.builder() + .rel("task:cancel") + .href(URI.create("https://vcloudbeta.bluelock.com/api/task/c6dca927-eab4-41fa-ad6a-3ac58602541c/action/cancel")) + .build()) + .owner(Reference.builder() + .type("application/vnd.vmware.vcloud.media+xml") + .name("") + .href(URI.create("https://vcloudbeta.bluelock.com/api/media/794eb334-754e-4917-b5a0-5df85cbd61d1")) + .build()) + .user(Reference.builder() + .type("application/vnd.vmware.admin.user+xml") + .name("adk@cloudsoftcorp.com") + .href(URI.create("https://vcloudbeta.bluelock.com/api/admin/user/e9eb1b29-0404-4c5e-8ef7-e584acc51da9")) + .build()) + .org(Reference.builder() + .type("application/vnd.vmware.vcloud.org+xml") + .name("JClouds") + .href(URI.create("https://vcloudbeta.bluelock.com/api/org/6f312e42-cd2b-488d-a2bb-97519cd57ed0")) + .build()) + .build(); + } +} diff --git a/labs/vcloud-director/src/test/java/org/jclouds/vcloud/director/v1_5/features/MediaClientLiveTest.java b/labs/vcloud-director/src/test/java/org/jclouds/vcloud/director/v1_5/features/MediaClientLiveTest.java new file mode 100644 index 0000000000..f2bb585c63 --- /dev/null +++ b/labs/vcloud-director/src/test/java/org/jclouds/vcloud/director/v1_5/features/MediaClientLiveTest.java @@ -0,0 +1,348 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + *(Link.builder().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(Link.builder().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.vcloud.director.v1_5.features; + +import static com.google.common.base.Objects.equal; +import static org.jclouds.vcloud.director.v1_5.VCloudDirectorLiveTestConstants.GETTER_RETURNS_SAME_OBJ; +import static org.jclouds.vcloud.director.v1_5.VCloudDirectorLiveTestConstants.OBJ_DEL; +import static org.jclouds.vcloud.director.v1_5.VCloudDirectorLiveTestConstants.OBJ_FIELD_ATTRB_DEL; +import static org.jclouds.vcloud.director.v1_5.VCloudDirectorLiveTestConstants.OBJ_FIELD_ATTRB_REQ; +import static org.jclouds.vcloud.director.v1_5.VCloudDirectorLiveTestConstants.OBJ_FIELD_CONTAINS; +import static org.jclouds.vcloud.director.v1_5.VCloudDirectorLiveTestConstants.OBJ_FIELD_EQ; +import static org.jclouds.vcloud.director.v1_5.VCloudDirectorLiveTestConstants.OBJ_FIELD_GTE_0; +import static org.jclouds.vcloud.director.v1_5.VCloudDirectorLiveTestConstants.OBJ_FIELD_REQ; +import static org.jclouds.vcloud.director.v1_5.VCloudDirectorLiveTestConstants.OBJ_FIELD_REQ_LIVE; +import static org.jclouds.vcloud.director.v1_5.VCloudDirectorLiveTestConstants.OBJ_FIELD_UPDATABLE; +import static org.jclouds.vcloud.director.v1_5.VCloudDirectorLiveTestConstants.OBJ_REQ_LIVE; +import static org.jclouds.vcloud.director.v1_5.VCloudDirectorLiveTestConstants.REF_REQ_LIVE; +import static org.jclouds.vcloud.director.v1_5.VCloudDirectorLiveTestConstants.TASK_COMPLETE_TIMELY; +import static org.jclouds.vcloud.director.v1_5.domain.Checks.checkResourceType; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertNull; +import static org.testng.Assert.assertTrue; +import static org.testng.Assert.fail; + +import java.net.URI; +import java.util.Set; +import java.util.concurrent.TimeUnit; + +import org.jclouds.predicates.RetryablePredicate; +import org.jclouds.vcloud.director.v1_5.VCloudDirectorException; +import org.jclouds.vcloud.director.v1_5.domain.Checks; +import org.jclouds.vcloud.director.v1_5.domain.Error; +import org.jclouds.vcloud.director.v1_5.domain.Media; +import org.jclouds.vcloud.director.v1_5.domain.Metadata; +import org.jclouds.vcloud.director.v1_5.domain.MetadataEntry; +import org.jclouds.vcloud.director.v1_5.domain.MetadataValue; +import org.jclouds.vcloud.director.v1_5.domain.Owner; +import org.jclouds.vcloud.director.v1_5.domain.Reference; +import org.jclouds.vcloud.director.v1_5.domain.Task; +import org.jclouds.vcloud.director.v1_5.internal.BaseVCloudDirectorClientLiveTest; +import org.jclouds.vcloud.director.v1_5.predicates.TaskSuccess; +import org.testng.annotations.BeforeGroups; +import org.testng.annotations.Test; + +import com.google.common.base.Predicate; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Iterables; + +/** + * Tests behavior of {@code MediaClient} + * + * @author danikov + */ +@Test(groups = { "live", "apitests", "User" }, testName = "MediaClientLiveTest") +public class MediaClientLiveTest extends BaseVCloudDirectorClientLiveTest { + public static final String MEDIA = "media"; + public static Predicate taskTester; + + /* + * Convenience references to API clients. + */ + protected MediaClient mediaClient; + + /* + * Shared state between dependent tests. + */ + private Reference mediaRef; + private Media media; + private Owner owner; + private Metadata metadata; + private MetadataValue metadataValue; + private String metadataEntryValue = "value"; + + @BeforeGroups(groups = { "live" }, dependsOnMethods = { "setupClient" }) + public void before() { + String mediaId = "68dc01a4-6c76-4177-9f19-ec12bf94287c"; // TODO: inject + mediaRef = Reference.builder() + .type("application/vnd.vmware.vcloud.media+xml") + .name("") + .href(URI.create(endpoint+"/media/"+mediaId)) + .id(mediaId) + .build(); + mediaClient = context.getApi().getMediaClient(); + taskTester = new RetryablePredicate(new TaskSuccess(context), 10, 1, TimeUnit.SECONDS); + mediaClient.setMetadata(mediaRef, "key", MetadataValue.builder().value("value").build()); + } + + @Test(testName = "GET /media/{id}") + public void testWhenResponseIs2xxLoginReturnsValidMedia() { + // required for testing + assertNotNull(mediaRef, String.format(REF_REQ_LIVE, MEDIA)); + + media = mediaClient.getMedia(mediaRef); + assertNotNull(media, String.format(OBJ_REQ_LIVE, MEDIA)); + assertTrue(!media.getDescription().equals("DO NOT USE"), "Media isn't to be used for testing"); + + owner = media.getOwner(); + assertNotNull(owner, String.format(OBJ_FIELD_REQ_LIVE, MEDIA, "owner")); + Checks.checkResourceType(media.getOwner()); + + // parent type + Checks.checkResourceEntityType(media); + + // required + String imageType = media.getImageType(); + Checks.checkImageType(imageType); + Long size = media.getSize(); + assertNotNull(size, String.format(OBJ_FIELD_REQ, MEDIA, "size")); + assertTrue(size >= 0, String.format(OBJ_FIELD_GTE_0, MEDIA, "size", size)); + } + + @Test(testName = "GET /media/{id}/owner", + dependsOnMethods = { "testWhenResponseIs2xxLoginReturnsValidMedia" }) + public void testWhenResponseIs2xxLoginReturnsValidMediaOwner() { + Owner directOwner = mediaClient.getOwner(mediaRef); + assertEquals(owner, directOwner, String.format(GETTER_RETURNS_SAME_OBJ, + "getOwner()", "owner", "media.getOwner()", owner.toString(), directOwner.toString())); + + // parent type + Checks.checkResourceType(directOwner); + + // required + assertNotNull(directOwner.getUser(), String.format(OBJ_FIELD_REQ, "Owner", "user")); + Checks.checkReferenceType(directOwner.getUser()); + } + + @Test(testName = "PUT /media/{id}", + dependsOnMethods = { "testWhenResponseIs2xxLoginReturnsValidMedia" }) + public void testWhenResponseIs2xxLoginReturnsValidNetwork() { + String oldName = media.getName(); + String newName = "new "+oldName; + String oldDescription = media.getDescription(); + String newDescription = "new "+oldDescription; + media.setName(newName); + media.setDescription(newDescription); + + Task updateMedia = mediaClient.updateMedia(mediaRef, media); + Checks.checkTask(updateMedia); + assertTrue(taskTester.apply(updateMedia.getHref()), String.format(TASK_COMPLETE_TIMELY, "updateMedia")); + media = mediaClient.getMedia(mediaRef); + + assertTrue(equal(media.getName(), newName), String.format(OBJ_FIELD_UPDATABLE, MEDIA, "name")); + assertTrue(equal(media.getDescription(), newDescription), + String.format(OBJ_FIELD_UPDATABLE, MEDIA, "description")); + + //TODO negative tests? + + // ensure media remains valid + testWhenResponseIs2xxLoginReturnsValidMedia(); + + media.setName(newName); + media.setDescription(newDescription); + + updateMedia = mediaClient.updateMedia(mediaRef, media); + Checks.checkTask(updateMedia); + assertTrue(taskTester.apply(updateMedia.getHref()), String.format(TASK_COMPLETE_TIMELY, "updateMedia")); + media = mediaClient.getMedia(mediaRef); + } + + @Test(testName = "GET /media/{id}/metadata", + dependsOnMethods = { "testWhenResponseIs2xxLoginReturnsValidMedia" }) + public void testWhenResponseIs2xxLoginReturnsValidMetadata() { + metadata = mediaClient.getMetadata(mediaRef); + // required for testing + assertFalse(Iterables.isEmpty(metadata.getMetadataEntries()), + String.format(OBJ_FIELD_REQ_LIVE, MEDIA, "metadata.entries")); + + // parent type + checkResourceType(metadata); + + for (MetadataEntry entry : metadata.getMetadataEntries()) { + // required elements and attributes + assertNotNull(entry.getKey(), + String.format(OBJ_FIELD_ATTRB_REQ, MEDIA, "MetadataEntry", metadataValue, "key")); + assertNotNull(entry.getValue(), + String.format(OBJ_FIELD_ATTRB_REQ, MEDIA, "MetadataEntry", metadataValue, "value")); + + // parent type + checkResourceType(entry); + } + } + + @Test(testName = "POST /media/{id}/metadata", + dependsOnMethods = { "testWhenResponseIs2xxLoginReturnsValidMetadata" }) + public void testWhenResponseIs2xxLoginMergedMetadata() { + // test new + Set inputEntries = ImmutableSet.of(MetadataEntry.builder().entry("testKey", "testValue").build()); + Metadata inputMetadata = Metadata.builder() + .entries(inputEntries) + .build(); + + Task mergeMetadata = mediaClient.mergeMetadata(mediaRef, inputMetadata); + Checks.checkTask(mergeMetadata); + assertTrue(taskTester.apply(mergeMetadata.getHref()), String.format(TASK_COMPLETE_TIMELY, "mergeMetadata(new)")); + metadata = mediaClient.getMetadata(mediaRef); + checkMetadataContainsEntries(metadata, inputEntries); + + testWhenResponseIs2xxLoginReturnsValidMetadata(); + + // test modify + inputEntries = ImmutableSet.of(MetadataEntry.builder().entry("testKey", "new testValue").build()); + inputMetadata = Metadata.builder() + .entries(inputEntries) + .build(); + + mergeMetadata = mediaClient.mergeMetadata(mediaRef, inputMetadata); + Checks.checkTask(mergeMetadata); + assertTrue(taskTester.apply(mergeMetadata.getHref()), String.format(TASK_COMPLETE_TIMELY, "mergeMetadata(modify)")); + metadata = mediaClient.getMetadata(mediaRef); + checkMetadataContainsEntries(metadata, inputEntries); + + testWhenResponseIs2xxLoginReturnsValidMetadata(); + } + + private void checkMetadataContainsEntries(Metadata metadata, Set entries) { + for (MetadataEntry inputEntry : entries) { + boolean found = false; + for (MetadataEntry entry : metadata.getMetadataEntries()) { + if (equal(inputEntry.getKey(), entry.getKey())) { + found = true; break; + } + } + + if (!found) { + String.format(OBJ_FIELD_CONTAINS, MEDIA, "metadata", + Iterables.toString(metadata.getMetadataEntries()), + Iterables.toString(entries)); + } + } + } + + @Test(testName = "GET /media/{id}/metadata/{key}", + dependsOnMethods = { "testWhenResponseIs2xxLoginMergedMetadata" }) + public void testWhenResponseIs2xxLoginReturnsValidMetadataValue() { + metadataValue = mediaClient.getMetadataValue(mediaRef, "key"); + + // Check parent type + checkResourceType(metadataValue); + + // Check required elements and attributes + String value = metadataValue.getValue(); + assertNotNull(value, + String.format(OBJ_FIELD_ATTRB_REQ, MEDIA, "MetadataEntry", + metadataValue.toString(), metadataEntryValue.toString())); + assertEquals(value, metadataEntryValue, + String.format(OBJ_FIELD_EQ, MEDIA, "metadataEntry.value", metadataEntryValue, value)); + } + + @Test(testName = "PUT /media/{id}/metadata/{key}", + dependsOnMethods = { "testWhenResponseIs2xxLoginReturnsValidMetadataValue" }) + public void testWhenResponseIs2xxLoginUpdatesMetadataEntry() { + metadataEntryValue = "newValue"; + MetadataValue newValue = MetadataValue.builder().value(metadataEntryValue).build(); + + Task setMetadataEntry = mediaClient.setMetadata(mediaRef, "key", newValue); + Checks.checkTask(setMetadataEntry); + assertTrue(taskTester.apply(setMetadataEntry.getHref()), + String.format(TASK_COMPLETE_TIMELY, "setMetadataEntry")); + metadataValue = mediaClient.getMetadataValue(mediaRef, "key"); + + // ensure metadataEntry remains valid + testWhenResponseIs2xxLoginReturnsValidMetadataValue(); + } + + @Test(testName = "DELETE /media/{id}/metadata/{key}", + dependsOnMethods = { "testWhenResponseIs2xxLoginUpdatesMetadataEntry" } ) + public void testWhenResponseIs2xxLoginDeletesMetadataEntry() { + Task deleteMetadataEntry = mediaClient.deleteMetadataEntry(mediaRef, "testKey"); + Checks.checkTask(deleteMetadataEntry); + assertTrue(taskTester.apply(deleteMetadataEntry.getHref()), + String.format(TASK_COMPLETE_TIMELY, "deleteMetadataEntry")); + + Error expected = Error.builder() + .message("The access to the resource metadata_item with id testKey is forbidden") + .majorErrorCode(403) + .minorErrorCode("ACCESS_TO_RESOURCE_IS_FORBIDDEN") + .build(); + + try { + metadataValue = mediaClient.getMetadataValue(mediaRef, "testKey"); + fail("Should give HTTP 403 error"); + } catch (VCloudDirectorException vde) { + assertEquals(vde.getError(), expected); + metadataValue = null; + } catch (Exception e) { + fail("Should have thrown a VCloudDirectorException"); + } + + if (metadataValue != null) { // guard against NPE on the .toStrings + assertNull(metadataValue, String.format(OBJ_FIELD_ATTRB_DEL, MEDIA, + "Metadata", metadataValue.toString(), + "metadataEntry", metadataValue.toString())); + } + + // ensure metadata and media remains valid + testWhenResponseIs2xxLoginReturnsValidMetadata(); + testWhenResponseIs2xxLoginReturnsValidMedia(); + } + @Test(testName = "DELETE /media/{id}", + dependsOnMethods = { "testWhenResponseIs2xxLoginDeletesMetadataEntry" } ) + public void testWhenResponseIs2xxLoginDeletesMedia() { + + Task deleteMedia = mediaClient.deleteMedia(mediaRef); + Checks.checkTask(deleteMedia); + assertTrue(taskTester.apply(deleteMedia.getHref()), + String.format(TASK_COMPLETE_TIMELY, "deleteMedia")); + + Error expected = Error.builder() + .message(String.format( + "No access to entity \"(com.vmware.vcloud.entity.media:%s)\".", + mediaRef.getId())) + .majorErrorCode(403) + .minorErrorCode("ACCESS_TO_RESOURCE_IS_FORBIDDEN") + .build(); + + try { + media = mediaClient.getMedia(mediaRef); + fail("Should give HTTP 403 error"); + } catch (VCloudDirectorException vde) { + assertEquals(vde.getError(), expected); + media = null; + } catch (Exception e) { + fail("Should have thrown a VCloudDirectorException"); + } + + if (media != null) { // guard against NPE on the .toStrings + assertNull(metadataValue, String.format(OBJ_DEL, MEDIA, media.toString())); + } + } +} diff --git a/labs/vcloud-director/src/test/java/org/jclouds/vcloud/director/v1_5/features/NetworkClientExpectTest.java b/labs/vcloud-director/src/test/java/org/jclouds/vcloud/director/v1_5/features/NetworkClientExpectTest.java index 5d2f897f85..1ee6629174 100644 --- a/labs/vcloud-director/src/test/java/org/jclouds/vcloud/director/v1_5/features/NetworkClientExpectTest.java +++ b/labs/vcloud-director/src/test/java/org/jclouds/vcloud/director/v1_5/features/NetworkClientExpectTest.java @@ -1,15 +1,15 @@ -/** +/* * Licensed to jclouds, Inc. (jclouds) under one or more * contributor license agreements. See the NOTICE file * distributed with this work for additional information - *(Link.builder().regarding copyright ownership. jclouds licenses this file + * 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(Link.builder().required by applicable law or agreed to in writing, + * 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 @@ -18,12 +18,15 @@ */ package org.jclouds.vcloud.director.v1_5.features; -import static org.testng.Assert.*; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.fail; import java.net.URI; import org.jclouds.vcloud.director.v1_5.VCloudDirectorClient; +import org.jclouds.vcloud.director.v1_5.VCloudDirectorException; import org.jclouds.vcloud.director.v1_5.VCloudDirectorMediaType; +import org.jclouds.vcloud.director.v1_5.domain.Error; import org.jclouds.vcloud.director.v1_5.domain.IpAddresses; import org.jclouds.vcloud.director.v1_5.domain.IpRange; import org.jclouds.vcloud.director.v1_5.domain.IpRanges; @@ -38,6 +41,8 @@ import org.jclouds.vcloud.director.v1_5.domain.SyslogServerSettings; import org.jclouds.vcloud.director.v1_5.internal.BaseVCloudDirectorRestClientExpectTest; import org.testng.annotations.Test; +import com.google.common.collect.ImmutableSet; + /** * Allows us to test a client via its side effects. * @@ -48,60 +53,102 @@ public class NetworkClientExpectTest extends BaseVCloudDirectorRestClientExpectT @Test public void testWhenResponseIs2xxLoginReturnsValidNetwork() { - URI networkRef = URI.create("https://vcloudbeta.bluelock.com/api/network/55a677cf-ab3f-48ae-b880-fab90421980c"); + URI networkUri = URI.create(endpoint + "/network/55a677cf-ab3f-48ae-b880-fab90421980c"); VCloudDirectorClient client = requestsSendResponses(loginRequest, sessionResponse, - getStandardRequest("GET", networkRef), + getStandardRequest("GET", "/network/55a677cf-ab3f-48ae-b880-fab90421980c"), getStandardPayloadResponse("/network/network.xml", VCloudDirectorMediaType.ORG_NETWORK)); - OrgNetwork expected = OrgNetwork - .builder() - .name("internet01-Jclouds") - .id("urn:vcloud:network:55a677cf-ab3f-48ae-b880-fab90421980c") - .type(VCloudDirectorMediaType.ORG_NETWORK) - .href(URI.create("https://vcloudbeta.bluelock.com/api/network/55a677cf-ab3f-48ae-b880-fab90421980c")) - .link(Link.builder() - .rel("up") - .type("application/vnd.vmware.vcloud.org+xml") - .href(URI.create("https://vcloudbeta.bluelock.com/api/org/6f312e42-cd2b-488d-a2bb-97519cd57ed0")) - .build()) - .link(Link.builder() - .rel("down") - .type("application/vnd.vmware.vcloud.metadata+xml") - .href(URI.create("https://vcloudbeta.bluelock.com/api/network/55a677cf-ab3f-48ae-b880-fab90421980c/metadata")) - .build()) - .description("") - .configuration(NetworkConfiguration.builder() - .ipScope(IpScope.builder() - .isInherited(true) - .gateway("173.240.107.49") - .netmask("255.255.255.240") - .dns1("173.240.111.52") - .dns2("173.240.111.53") - .ipRanges(IpRanges.builder() - .ipRange(IpRange.builder() - .startAddress("173.240.107.50") - .endAddress("173.240.107.62") - .build()) - .build()) - .build()) - .fenceMode("bridged") - .retainNetInfoAcrossDeployments(false) - .syslogServerSettings(SyslogServerSettings.builder().build()) - .build()) - .allowedExternalIpAddresses(IpAddresses.builder().build()) - .build(); + OrgNetwork expected = orgNetwork(); + + Reference networkRef = Reference.builder().href(networkUri).build(); assertEquals(client.getNetworkClient().getNetwork(networkRef), expected); } + + @Test + public void testWhenResponseIs400ForInvalidNetworkId() { + URI networkUri = URI.create(endpoint + "/network/NOTAUUID"); + + VCloudDirectorClient client = requestsSendResponses(loginRequest, sessionResponse, + getStandardRequest("GET", "/network/NOTAUUID"), + getStandardPayloadResponse(400, "/network/error400.xml", VCloudDirectorMediaType.ERROR)); + + Error expected = Error.builder() + .message("validation error : EntityRef has incorrect type, expected type is com.vmware.vcloud.entity.network.") + .majorErrorCode(400) + .minorErrorCode("BAD_REQUEST") + .build(); + + Reference networkRef = Reference.builder().href(networkUri).build(); + try { + client.getNetworkClient().getNetwork(networkRef); + fail("Should give HTTP 400 error"); + } catch (VCloudDirectorException vde) { + assertEquals(vde.getError(), expected); + } catch (Exception e) { + fail("Should have thrown a VCloudDirectorException"); + } + } + + @Test + public void testWhenResponseIs403ForCatalogIdUsedAsNetworkId() { + URI networkUri = URI.create(endpoint + "/network/9e08c2f6-077a-42ce-bece-d5332e2ebb5c"); + + VCloudDirectorClient client = requestsSendResponses(loginRequest, sessionResponse, + getStandardRequest("GET", "/network/9e08c2f6-077a-42ce-bece-d5332e2ebb5c"), + getStandardPayloadResponse(403, "/network/error403-catalog.xml", VCloudDirectorMediaType.ERROR)); + + Error expected = Error.builder() + .message("This operation is denied.") + .majorErrorCode(403) + .minorErrorCode("ACCESS_TO_RESOURCE_IS_FORBIDDEN") + .build(); + + Reference networkRef = Reference.builder().href(networkUri).build(); + + try { + client.getNetworkClient().getNetwork(networkRef); + fail("Should give HTTP 403 error"); + } catch (VCloudDirectorException vde) { + assertEquals(vde.getError(), expected); + } catch (Exception e) { + fail("Should have thrown a VCloudDirectorException"); + } + } + + @Test + public void testWhenResponseIs403ForFakeNetworkId() { + URI networkUri = URI.create(endpoint + "/network/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"); + + VCloudDirectorClient client = requestsSendResponses(loginRequest, sessionResponse, + getStandardRequest("GET", "/network/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"), + getStandardPayloadResponse(403, "/network/error403-fake.xml", VCloudDirectorMediaType.ERROR)); + + Error expected = Error.builder() + .message("This operation is denied.") + .majorErrorCode(403) + .minorErrorCode("ACCESS_TO_RESOURCE_IS_FORBIDDEN") + .build(); + + Reference networkRef = Reference.builder().href(networkUri).build(); + + try { + client.getNetworkClient().getNetwork(networkRef); + fail("Should give HTTP 403 error"); + } catch (VCloudDirectorException vde) { + assertEquals(vde.getError(), expected); + } catch (Exception e) { + fail("Should have thrown a VCloudDirectorException"); + } + } @Test - public void testWhenResponseIs2xxLoginReturnsValidMetadata() { - URI orgUri = URI.create(endpoint + "/network/55a677cf-ab3f-48ae-b880-fab90421980c"); - URI metaUri = URI.create(orgUri.toASCIIString() + "/metadata/"); + public void testWhenResponseIs2xxLoginReturnsValidMetadataList() { + URI networkUri = URI.create(endpoint + "/network/55a677cf-ab3f-48ae-b880-fab90421980c"); VCloudDirectorClient client = requestsSendResponses(loginRequest, sessionResponse, - getStandardRequest("GET", metaUri), + getStandardRequest("GET", "/network/55a677cf-ab3f-48ae-b880-fab90421980c/metadata"), getStandardPayloadResponse("/network/metadata.xml", VCloudDirectorMediaType.METADATA)); Metadata expected = Metadata.builder() @@ -112,27 +159,67 @@ public class NetworkClientExpectTest extends BaseVCloudDirectorRestClientExpectT .type("application/vnd.vmware.vcloud.network+xml") .href(URI.create("https://vcloudbeta.bluelock.com/api/network/55a677cf-ab3f-48ae-b880-fab90421980c")) .build()) + .entries(ImmutableSet.of(MetadataEntry.builder().entry("key", "value").build())) .build(); - // TODO change network client to use ReferenceType params - Reference orgRef = Reference.builder().href(orgUri).build(); - - assertEquals(client.getNetworkClient().getMetadata(orgUri), expected); + Reference networkRef = Reference.builder().href(networkUri).build(); + + assertEquals(client.getNetworkClient().getMetadata(networkRef), expected); } @Test(enabled=false) // No metadata in exemplar xml... - public void testWhenResponseIs2xxLoginReturnsValidMetadataEntry() { - URI metadataUri = URI.create(endpoint + "/network/55a677cf-ab3f-48ae-b880-fab90421980c/metadata/KEY"); + public void testWhenResponseIs2xxLoginReturnsValidMetadata() { + URI networkUri = URI.create("https://vcloudbeta.bluelock.com/api/network/55a677cf-ab3f-48ae-b880-fab90421980c"); VCloudDirectorClient client = requestsSendResponses(loginRequest, sessionResponse, - getStandardRequest("GET", metadataUri), - getStandardPayloadResponse("/network/metadata.xml", VCloudDirectorMediaType.METADATA_ENTRY)); + getStandardRequest("GET", "/network/55a677cf-ab3f-48ae-b880-fab90421980c/metadata/KEY"), + getStandardPayloadResponse("/network/metadataEntry.xml", VCloudDirectorMediaType.METADATA_ENTRY)); - MetadataEntry expected = MetadataEntry.builder().build(); + MetadataEntry expected = MetadataEntry.builder() + .entry("key", "value") + .build(); - // TODO change network client to use ReferenceType params - Reference orgRef = Reference.builder().href(metadataUri).build(); + Reference networkRef = Reference.builder().href(networkUri).build(); - assertEquals(client.getNetworkClient().getMetadataEntry(metadataUri), expected); + assertEquals(client.getNetworkClient().getMetadataValue(networkRef, "KEY"), expected); + } + + public static OrgNetwork orgNetwork() { + return OrgNetwork.builder() + .name("internet01-Jclouds") + .id("urn:vcloud:network:55a677cf-ab3f-48ae-b880-fab90421980c") + .type(VCloudDirectorMediaType.ORG_NETWORK) + .href(URI.create("https://vcloudbeta.bluelock.com/api/network/55a677cf-ab3f-48ae-b880-fab90421980c")) + .link(Link.builder() + .rel("up") + .type("application/vnd.vmware.vcloud.org+xml") + .href(URI.create("https://vcloudbeta.bluelock.com/api/org/6f312e42-cd2b-488d-a2bb-97519cd57ed0")) + .build()) + .link(Link.builder() + .rel("down") + .type("application/vnd.vmware.vcloud.metadata+xml") + .href(URI.create("https://vcloudbeta.bluelock.com/api/network/55a677cf-ab3f-48ae-b880-fab90421980c/metadata")) + .build()) + .description("") + .configuration(NetworkConfiguration.builder() + .ipScope(IpScope.builder() + .isInherited(true) + .gateway("173.240.107.49") + .netmask("255.255.255.240") + .dns1("173.240.111.52") + .dns2("173.240.111.53") + .ipRanges(IpRanges.builder() + .ipRange(IpRange.builder() + .startAddress("173.240.107.50") + .endAddress("173.240.107.62") + .build()) + .build()) + .build()) + .fenceMode("bridged") + .retainNetInfoAcrossDeployments(false) + .syslogServerSettings(SyslogServerSettings.builder().build()) + .build()) + .allowedExternalIpAddresses(IpAddresses.builder().build()) + .build(); } } diff --git a/labs/vcloud-director/src/test/java/org/jclouds/vcloud/director/v1_5/features/NetworkClientLiveTest.java b/labs/vcloud-director/src/test/java/org/jclouds/vcloud/director/v1_5/features/NetworkClientLiveTest.java new file mode 100644 index 0000000000..5c605e15f0 --- /dev/null +++ b/labs/vcloud-director/src/test/java/org/jclouds/vcloud/director/v1_5/features/NetworkClientLiveTest.java @@ -0,0 +1,139 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + *(Link.builder().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(Link.builder().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.vcloud.director.v1_5.features; + +import static org.jclouds.vcloud.director.v1_5.VCloudDirectorLiveTestConstants.OBJ_FIELD_ATTRB_REQ; +import static org.jclouds.vcloud.director.v1_5.VCloudDirectorLiveTestConstants.OBJ_FIELD_EQ; +import static org.jclouds.vcloud.director.v1_5.VCloudDirectorLiveTestConstants.OBJ_FIELD_REQ_LIVE; +import static org.jclouds.vcloud.director.v1_5.VCloudDirectorLiveTestConstants.OBJ_REQ_LIVE; +import static org.jclouds.vcloud.director.v1_5.VCloudDirectorLiveTestConstants.REF_REQ_LIVE; +import static org.jclouds.vcloud.director.v1_5.domain.Checks.checkResourceType; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; + +import java.net.URI; + +import org.jclouds.vcloud.director.v1_5.domain.Checks; +import org.jclouds.vcloud.director.v1_5.domain.IpAddresses; +import org.jclouds.vcloud.director.v1_5.domain.Metadata; +import org.jclouds.vcloud.director.v1_5.domain.MetadataEntry; +import org.jclouds.vcloud.director.v1_5.domain.MetadataValue; +import org.jclouds.vcloud.director.v1_5.domain.OrgNetwork; +import org.jclouds.vcloud.director.v1_5.domain.Reference; +import org.jclouds.vcloud.director.v1_5.domain.ReferenceType; +import org.jclouds.vcloud.director.v1_5.internal.BaseVCloudDirectorClientLiveTest; +import org.testng.annotations.BeforeGroups; +import org.testng.annotations.Test; + +import com.google.common.collect.Iterables; + +/** + * Tests behavior of {@code NetworkClient} + * + * @author danikov + */ +@Test(groups = { "live", "apitests" }, testName = "NetworkClientLiveTest") +public class NetworkClientLiveTest extends BaseVCloudDirectorClientLiveTest { + + public static final String NETWORK = "network"; + + /* + * Convenience reference to API client. + */ + protected NetworkClient networkClient; + + private Reference networkRef; + + @BeforeGroups(groups = { "live" }, dependsOnMethods = { "setupClient" }) + public void before() { + String networkId = "a604f3c2-0343-453e-ae1f-cddac5b7bd94"; // TODO: inject + networkRef = Reference.builder() + .type("application/vnd.vmware.vcloud.orgNetwork+xml") + .name("") + .href(URI.create(endpoint+"/network/"+networkId)) + .id(networkId) + .build(); + networkClient = context.getApi().getNetworkClient(); + } + + @Test(testName = "GET /network/{id}") + public void testGetNetwork() { + // required for testing + assertNotNull(networkRef, String.format(REF_REQ_LIVE, NETWORK)); + + OrgNetwork network = networkClient.getNetwork(networkRef); + assertNotNull(network, String.format(OBJ_REQ_LIVE, NETWORK)); + assertTrue(!network.getDescription().equals("DO NOT USE"), "Network isn't to be used for testing"); + + // parent type + Checks.checkNetworkType(network); + + // optional + ReferenceType networkPoolRef = network.getNetworkPool(); + if (networkPoolRef != null) { + Checks.checkReferenceType(networkPoolRef); + } + + IpAddresses allowedExternalIpAddresses = network.getAllowedExternalIpAddresses(); + if (allowedExternalIpAddresses != null) { + Checks.checkIpAddresses(allowedExternalIpAddresses); + } + } + + @Test(testName = "GET /network/{id}/metadata") + public void testGetMetadata() { + Metadata metadata = networkClient.getMetadata(networkRef); + // required for testing + assertFalse(Iterables.isEmpty(metadata.getMetadataEntries()), + String.format(OBJ_FIELD_REQ_LIVE, NETWORK, "metadata.entries")); + + // parent type + checkResourceType(metadata); + + for (MetadataEntry entry : metadata.getMetadataEntries()) { + // required elements and attributes + assertNotNull(entry.getKey(), + String.format(OBJ_FIELD_ATTRB_REQ, networkClient, "MetadataEntry", entry.getKey(), "key")); + assertNotNull(entry.getValue(), + String.format(OBJ_FIELD_ATTRB_REQ, networkClient, "MetadataEntry", entry.getValue(), "value")); + + // parent type + checkResourceType(entry); + } + } + + @Test(testName = "GET /network/{id}/metadata/{key}") + public void testGetMetadataValue() { + MetadataValue metadataValue = networkClient.getMetadataValue(networkRef, "key"); + + // Check parent type + checkResourceType(metadataValue); + + // Check required elements and attributes + String value = metadataValue.getValue(); + assertNotNull(value, + String.format(OBJ_FIELD_ATTRB_REQ, NETWORK, "MetadataEntry", + metadataValue.toString(), "value")); + assertEquals(value, "value", + String.format(OBJ_FIELD_EQ, NETWORK, "metadataEntry.value", "value", value)); + } + +} diff --git a/labs/vcloud-director/src/test/java/org/jclouds/vcloud/director/v1_5/features/OrgClientExpectTest.java b/labs/vcloud-director/src/test/java/org/jclouds/vcloud/director/v1_5/features/OrgClientExpectTest.java index b7c3dc7f6d..541a37134e 100644 --- a/labs/vcloud-director/src/test/java/org/jclouds/vcloud/director/v1_5/features/OrgClientExpectTest.java +++ b/labs/vcloud-director/src/test/java/org/jclouds/vcloud/director/v1_5/features/OrgClientExpectTest.java @@ -1,15 +1,15 @@ -/** +/* * Licensed to jclouds, Inc. (jclouds) under one or more * contributor license agreements. See the NOTICE file * distributed with this work for additional information - *(Link.builder().regarding copyright ownership. jclouds licenses this file + * 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(Link.builder().required by applicable law or agreed to in writing, + * 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 @@ -35,10 +35,11 @@ import org.jclouds.vcloud.director.v1_5.domain.Reference; import org.jclouds.vcloud.director.v1_5.internal.BaseVCloudDirectorRestClientExpectTest; import org.testng.annotations.Test; +import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; /** - * Allows us to test a client via its side effects. + * Allows us to test the {@link OrgClient} via its side effects. * * @author Adrian Cole */ @@ -46,9 +47,9 @@ import com.google.common.collect.Iterables; public class OrgClientExpectTest extends BaseVCloudDirectorRestClientExpectTest { @Test - public void testWhenResponseIs2xxLoginReturnsValidOrgList() { + public void testGetOrgList() { VCloudDirectorClient client = requestsSendResponses(loginRequest, sessionResponse, - getStandardRequest("GET", "/org"), + getStandardRequest("GET", "/org/"), getStandardPayloadResponse("/org/orglist.xml", VCloudDirectorMediaType.ORG_LIST)); OrgList expected = OrgList.builder() @@ -63,9 +64,9 @@ public class OrgClientExpectTest extends BaseVCloudDirectorRestClientExpectTest } @Test - public void testWhenResponseIs2xxLoginReturnsValidOrgFromListByReference() { + public void testGetOrgFromOrgListReference() { VCloudDirectorClient client = requestsSendResponses(loginRequest, sessionResponse, - getStandardRequest("GET", "/org"), + getStandardRequest("GET", "/org/"), getStandardPayloadResponse("/org/orglist.xml", VCloudDirectorMediaType.ORG_LIST)); Reference org = Iterables.getOnlyElement(client.getOrgClient().getOrgList().getOrgs()); @@ -80,7 +81,7 @@ public class OrgClientExpectTest extends BaseVCloudDirectorRestClientExpectTest } @Test - public void testWhenResponseIs2xxLoginReturnsValidOrg() { + public void testGetOrg() { URI orgUri = URI.create(endpoint + "/org/6f312e42-cd2b-488d-a2bb-97519cd57ed0"); VCloudDirectorClient client = requestsSendResponses(loginRequest, sessionResponse, @@ -95,7 +96,7 @@ public class OrgClientExpectTest extends BaseVCloudDirectorRestClientExpectTest } @Test - public void testWhenResponseIs400ForInvalidOrgId() { + public void testGetOrgFailOnInvalidOrgId() { URI orgUri = URI.create(endpoint + "/org/NOTAUUID"); VCloudDirectorClient client = requestsSendResponses(loginRequest, sessionResponse, @@ -120,7 +121,7 @@ public class OrgClientExpectTest extends BaseVCloudDirectorRestClientExpectTest } @Test - public void testWhenResponseIs403ForCatalogIdUsedAsOrgId() { + public void testGetOrgFailOnWrongOrgId() { URI orgUri = URI.create(endpoint + "/org/9e08c2f6-077a-42ce-bece-d5332e2ebb5c"); VCloudDirectorClient client = requestsSendResponses(loginRequest, sessionResponse, @@ -146,7 +147,7 @@ public class OrgClientExpectTest extends BaseVCloudDirectorRestClientExpectTest } @Test - public void testWhenResponseIs403ForFakeOrgId() { + public void testGetOrgFailOnFakeOrgId() { URI orgUri = URI.create(endpoint + "/org/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"); VCloudDirectorClient client = requestsSendResponses(loginRequest, sessionResponse, @@ -172,12 +173,12 @@ public class OrgClientExpectTest extends BaseVCloudDirectorRestClientExpectTest } @Test - public void testWhenResponseIs2xxLoginReturnsValidMetadataList() { + public void testGetOrgMetadata() { URI orgUri = URI.create(endpoint + "/org/6f312e42-cd2b-488d-a2bb-97519cd57ed0"); VCloudDirectorClient client = requestsSendResponses(loginRequest, sessionResponse, getStandardRequest("GET", "/org/6f312e42-cd2b-488d-a2bb-97519cd57ed0/metadata"), - getStandardPayloadResponse("/org/metadata.xml", VCloudDirectorMediaType.METADATA)); + getStandardPayloadResponse("/org/orgMetadata.xml", VCloudDirectorMediaType.METADATA)); Metadata expected = Metadata.builder() .type("application/vnd.vmware.vcloud.metadata+xml") @@ -187,28 +188,27 @@ public class OrgClientExpectTest extends BaseVCloudDirectorRestClientExpectTest .type("application/vnd.vmware.vcloud.org+xml") .href(URI.create("https://vcloudbeta.bluelock.com/api/org/6f312e42-cd2b-488d-a2bb-97519cd57ed0")) .build()) + .entries(ImmutableSet.of(metadataEntry())) .build(); Reference orgRef = Reference.builder().href(orgUri).build(); - assertEquals(client.getOrgClient().getMetadata(orgRef), expected); + assertEquals(client.getOrgClient().getOrgMetadata(orgRef), expected); } - @Test(enabled=false) // No metadata in exemplar xml... - public void testWhenResponseIs2xxLoginReturnsValidMetadata() { + @Test + public void testGetOrgMetadataEntry() { URI orgUri = URI.create("https://vcloudbeta.bluelock.com/api/org/6f312e42-cd2b-488d-a2bb-97519cd57ed0"); VCloudDirectorClient client = requestsSendResponses(loginRequest, sessionResponse, getStandardRequest("GET", "/org/6f312e42-cd2b-488d-a2bb-97519cd57ed0/metadata/KEY"), - getStandardPayloadResponse("/org/metadata.xml", VCloudDirectorMediaType.METADATA_ENTRY)); + getStandardPayloadResponse("/org/orgMetadataEntry.xml", VCloudDirectorMediaType.METADATA_ENTRY)); - MetadataEntry expected = MetadataEntry.builder() - .key("KEY") - .build(); + MetadataEntry expected = metadataEntry(); Reference orgRef = Reference.builder().href(orgUri).build(); - assertEquals(client.getOrgClient().getMetadataEntry(orgRef, "KEY"), expected); + assertEquals(client.getOrgClient().getOrgMetadataEntry(orgRef, "KEY"), expected); } public static Org org() { @@ -234,7 +234,7 @@ public class OrgClientExpectTest extends BaseVCloudDirectorRestClientExpectTest .rel("down") .type("application/vnd.vmware.vcloud.catalog+xml") .name("Public") - .href(URI.create("https://vcloudbeta.bluelock.com/api/catalog/9e08c2f6-077a-42ce-bece-d5332e2ebb5c")) + .href(URI.create("https://vcloudbeta.bluelock.com/api/catalog/7212e451-76e1-4631-b2de-ba1dfd8080e4")) .build()) .link(Link.builder() .rel("down") @@ -260,4 +260,16 @@ public class OrgClientExpectTest extends BaseVCloudDirectorRestClientExpectTest .build()) .build(); } + + public static MetadataEntry metadataEntry() { + return MetadataEntry.builder() + .href(URI.create("https://vcloudbeta.bluelock.com/api/org/6f312e42-cd2b-488d-a2bb-97519cd57ed0/metadata/KEY")) + .link(Link.builder() + .rel("up") + .type("application/vnd.vmware.vcloud.metadata+xml") + .href(URI.create("https://vcloudbeta.bluelock.com/api/org/6f312e42-cd2b-488d-a2bb-97519cd57ed0/metadata")) + .build()) + .entry("KEY", "VALUE") + .build(); + } } diff --git a/labs/vcloud-director/src/test/java/org/jclouds/vcloud/director/v1_5/features/OrgClientLiveTest.java b/labs/vcloud-director/src/test/java/org/jclouds/vcloud/director/v1_5/features/OrgClientLiveTest.java new file mode 100644 index 0000000000..5d493ea9fc --- /dev/null +++ b/labs/vcloud-director/src/test/java/org/jclouds/vcloud/director/v1_5/features/OrgClientLiveTest.java @@ -0,0 +1,127 @@ +/* + * 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.vcloud.director.v1_5.features; + +import static org.jclouds.vcloud.director.v1_5.VCloudDirectorLiveTestConstants.*; +import static org.jclouds.vcloud.director.v1_5.domain.Checks.*; +import static org.testng.Assert.*; + +import org.jclouds.vcloud.director.v1_5.VCloudDirectorMediaType; +import org.jclouds.vcloud.director.v1_5.domain.Metadata; +import org.jclouds.vcloud.director.v1_5.domain.MetadataEntry; +import org.jclouds.vcloud.director.v1_5.domain.Org; +import org.jclouds.vcloud.director.v1_5.domain.OrgList; +import org.jclouds.vcloud.director.v1_5.domain.Reference; +import org.jclouds.vcloud.director.v1_5.internal.BaseVCloudDirectorClientLiveTest; +import org.testng.annotations.Test; + +import com.google.common.collect.Iterables; + +/** +* Tests live behavior of {@link OrgClient}. +* +* @author grkvlt@apache.org +*/ +@Test(groups = { "live", "apitests" }, testName = "OrgClientLiveTest") +public class OrgClientLiveTest extends BaseVCloudDirectorClientLiveTest { + + /* + * Convenience references to API clients. + */ + + private final OrgClient orgClient = context.getApi().getOrgClient(); + + /* + * Shared state between dependant tests. + */ + + private OrgList orgList; + private Reference orgRef; + private Org org; + + @Test(testName = "GET /org/") + public void testGetOrgList() { + // Call the method being tested + orgList = orgClient.getOrgList(); + + // NOTE The environment MUST have at least one organisation configured + + // Check required elements and attributes + assertFalse(Iterables.isEmpty(orgList.getOrgs()), "There must always be Org elements in the OrgList"); + + for (Reference orgRef : orgList.getOrgs()) { + assertEquals(orgRef.getType(), VCloudDirectorMediaType.ORG, "The Refernce must be to an Org type"); + checkReferenceType(orgRef); + } + } + + @Test(testName = "GET /org/{id}", dependsOnMethods = { "testGetOrgList" }) + public void testGetOrg() { + orgRef = Iterables.getFirst(orgList.getOrgs(), null); + + // Call the method being tested + org = orgClient.getOrg(orgRef); + + // Check required elements and attributes + assertNotNull(org.getFullName(), String.format(FIELD_NOT_NULL_FMT, "FullName", "Org")); + + // Check parent type + checkEntityType(org); + } + + @Test(testName = "GET /org/{id}/metadata/", dependsOnMethods = { "testGetOrg" }) + public void testGetOrgMetadata() { + // Call the method being tested + Metadata metadata = orgClient.getOrgMetadata(orgRef); + + // NOTE The environment MUST have at one metadata entry for the first organisation configured + + // Check required elements and attributes + assertFalse(Iterables.isEmpty(metadata.getMetadataEntries()), "There must always be MetadataEntry elements in the Org"); + + // Check parent type + checkResourceType(metadata); + + for (MetadataEntry entry : metadata.getMetadataEntries()) { + // Check required elements and attributes + assertNotNull(entry.getKey(), String.format(FIELD_NOT_NULL_FMT, "Key", "MetadataEntry")); + assertNotNull(entry.getValue(), String.format(FIELD_NOT_NULL_FMT, "Value", "MetadataEntry")); + + // Check parent type + checkResourceType(entry); + } + } + + @Test(testName = "GET /org/{id}/metadata/{key}", dependsOnMethods = { "testGetOrgMetadata" }) + public void testGetOrgMetadataEntry() { + // Call the method being tested + MetadataEntry entry = orgClient.getOrgMetadataEntry(orgRef, "KEY"); + + // NOTE The environment MUST have configured the metadata entry as '{ key="KEY", value="VALUE" )' + + // Check required elements and attributes + assertNotNull(entry.getKey(), String.format(FIELD_NOT_NULL_FMT, "Key", "MetadataEntry")); + assertEquals(entry.getKey(), "KEY", "The Key field must have the value \"KEY\""); + assertNotNull(entry.getValue(), String.format(FIELD_NOT_NULL_FMT, "Value", "MetadataEntry")); + assertEquals(entry.getValue(), "VALUE", "The Value field must have the value \"VALUE\""); + + // Check parent type + checkResourceType(entry); + } +} diff --git a/labs/vcloud-director/src/test/java/org/jclouds/vcloud/director/v1_5/features/TaskClientExpectTest.java b/labs/vcloud-director/src/test/java/org/jclouds/vcloud/director/v1_5/features/TaskClientExpectTest.java index fae7bebf13..716ec3e286 100644 --- a/labs/vcloud-director/src/test/java/org/jclouds/vcloud/director/v1_5/features/TaskClientExpectTest.java +++ b/labs/vcloud-director/src/test/java/org/jclouds/vcloud/director/v1_5/features/TaskClientExpectTest.java @@ -1,15 +1,15 @@ -/** +/* * Licensed to jclouds, Inc. (jclouds) under one or more * contributor license agreements. See the NOTICE file * distributed with this work for additional information - *(Link.builder().regarding copyright ownership. jclouds licenses this file + * 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(Link.builder().required by applicable law or agreed to in writing, + * 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 @@ -80,55 +80,8 @@ public class TaskClientExpectTest extends BaseVCloudDirectorRestClientExpectTest .name("Tasks Lists") .type("application/vnd.vmware.vcloud.tasksList+xml") .href(URI.create("https://vcloudbeta.bluelock.com/api/tasksList/6f312e42-cd2b-488d-a2bb-97519cd57ed0")) - .task(Task.builder() - .type("application/vnd.vmware.vcloud.task+xml") - .name("task") - .id("urn:vcloud:task:5fcd2af3-d0ec-45ce-9451-8c585a2c766b") - .href(URI.create("https://vcloudbeta.bluelock.com/api/task/5fcd2af3-d0ec-45ce-9451-8c585a2c766b")) - .status("success") - .operation("Created Catalog QunyingTestCatalog(7212e451-76e1-4631-b2de-ba1dfd8080e4)") - .operationName("catalogCreateCatalog") - .startTime(dateService.iso8601DateParse("2012-02-07T00:16:28.450-05:00")) - .endTime(dateService.iso8601DateParse("2012-02-07T00:16:28.867-05:00")) - .expiryTime(dateService.iso8601DateParse("2012-05-07T00:16:28.450-04:00")) - .owner(Reference.builder() - .type("application/vnd.vmware.vcloud.catalog+xml") - .name("QunyingTestCatalog") - .href(URI.create("https://vcloudbeta.bluelock.com/api/catalog/7212e451-76e1-4631-b2de-ba1dfd8080e4")) - .build()) - .user(Reference.builder() - .type("application/vnd.vmware.admin.user+xml") - .name("JClouds") - .href(URI.create("https://vcloudbeta.bluelock.com/api/org/6f312e42-cd2b-488d-a2bb-97519cd57ed0")) - .build()) - .org(Reference.builder() - .type("application/vnd.vmware.vcloud.org+xml") - .name("JClouds") - .href(URI.create("https://vcloudbeta.bluelock.com/api/org/6f312e42-cd2b-488d-a2bb-97519cd57ed0")) - .build()) - .build()) - .task(Task.builder() - .type("application/vnd.vmware.vcloud.task+xml") - .name("task") - .id("urn:vcloud:task:bd22e745-9c2a-4f82-a954-0e35b6f76ba5") - .href(URI.create("https://vcloudbeta.bluelock.com/api/task/bd22e745-9c2a-4f82-a954-0e35b6f76ba5")) - .status("success") - .operation("Enabled User (967d317c-4273-4a95-b8a4-bf63b78e9c69)") - .operationName("jobEnable") - .startTime(dateService.iso8601DateParse("2012-02-06T17:30:38.507-05:00")) - .endTime(dateService.iso8601DateParse("2012-02-06T17:30:38.507-05:00")) - .expiryTime(dateService.iso8601DateParse("2012-05-06T17:30:38.507-04:00")) - .user(Reference.builder() - .type("application/vnd.vmware.admin.user+xml") - .name("adrian@jclouds.org") - .href(URI.create("https://vcloudbeta.bluelock.com/api/admin/user/8c360b93-ed25-4c9a-8e24-d48cd9966d93")) - .build()) - .org(Reference.builder() - .type("application/vnd.vmware.vcloud.org+xml") - .name("JClouds") - .href(URI.create("https://vcloudbeta.bluelock.com/api/org/6f312e42-cd2b-488d-a2bb-97519cd57ed0")) - .build()) - .build()) + .task(taskOne()) + .task(taskTwo()) .build(); Reference orgRef = Reference.builder().href(URI.create("https://vcloudbeta.bluelock.com/api/org/6f312e42-cd2b-488d-a2bb-97519cd57ed0")).build(); @@ -248,41 +201,11 @@ public class TaskClientExpectTest extends BaseVCloudDirectorRestClientExpectTest VCloudDirectorClient client = requestsSendResponses(loginRequest, sessionResponse, taskRequest, taskResponse); - Reference taskRef = Reference.builder() - .type("application/vnd.vmware.vcloud.task+xml") - .name("task") - .href(URI.create(endpoint + "/task/5fcd2af3-d0ec-45ce-9451-8c585a2c766b")) - .build(); + URI taskUri = URI.create(endpoint + "/task/5fcd2af3-d0ec-45ce-9451-8c585a2c766b"); - Task expected = Task.builder() - .type("application/vnd.vmware.vcloud.task+xml") - .name("task") - .id("urn:vcloud:task:5fcd2af3-d0ec-45ce-9451-8c585a2c766b") - .href(URI.create("https://vcloudbeta.bluelock.com/api/task/5fcd2af3-d0ec-45ce-9451-8c585a2c766b")) - .status("success") - .operation("Created Catalog QunyingTestCatalog(7212e451-76e1-4631-b2de-ba1dfd8080e4)") - .operationName("catalogCreateCatalog") - .startTime(dateService.iso8601DateParse("2012-02-07T00:16:28.450-05:00")) - .endTime(dateService.iso8601DateParse("2012-02-07T00:16:28.867-05:00")) - .expiryTime(dateService.iso8601DateParse("2012-05-07T00:16:28.450-04:00")) - .owner(Reference.builder() - .type("application/vnd.vmware.vcloud.catalog+xml") - .name("QunyingTestCatalog") - .href(URI.create("https://vcloudbeta.bluelock.com/api/catalog/7212e451-76e1-4631-b2de-ba1dfd8080e4")) - .build()) - .user(Reference.builder() - .type("application/vnd.vmware.admin.user+xml") - .name("JClouds") - .href(URI.create("https://vcloudbeta.bluelock.com/api/org/6f312e42-cd2b-488d-a2bb-97519cd57ed0")) - .build()) - .org(Reference.builder() - .type("application/vnd.vmware.vcloud.org+xml") - .name("JClouds") - .href(URI.create("https://vcloudbeta.bluelock.com/api/org/6f312e42-cd2b-488d-a2bb-97519cd57ed0")) - .build()) - .build(); + Task expected = taskOne(); - assertEquals(client.getTaskClient().getTask(taskRef), expected); + assertEquals(client.getTaskClient().getTask(taskUri), expected); } @Test @@ -296,18 +219,70 @@ public class TaskClientExpectTest extends BaseVCloudDirectorRestClientExpectTest .build()) .build(); - HttpResponse taskResponse = HttpResponse.builder() + HttpResponse taskResponse = HttpResponse.builder() .statusCode(200) .build(); VCloudDirectorClient client = requestsSendResponses(loginRequest, sessionResponse, taskRequest, taskResponse); - Reference taskRef = Reference.builder() - .type("application/vnd.vmware.vcloud.task+xml") - .name("task") - .href(URI.create(endpoint + "/task/5fcd2af3-d0ec-45ce-9451-8c585a2c766b")) - .build(); + URI taskUri = URI.create(endpoint + "/task/5fcd2af3-d0ec-45ce-9451-8c585a2c766b"); - client.getTaskClient().cancelTask(taskRef); + client.getTaskClient().cancelTask(taskUri); + } + + public static Task taskOne() { + return Task.builder() + .type("application/vnd.vmware.vcloud.task+xml") + .name("task") + .id("urn:vcloud:task:5fcd2af3-d0ec-45ce-9451-8c585a2c766b") + .href(URI.create("https://vcloudbeta.bluelock.com/api/task/5fcd2af3-d0ec-45ce-9451-8c585a2c766b")) + .status("success") + .operation("Created Catalog QunyingTestCatalog(7212e451-76e1-4631-b2de-ba1dfd8080e4)") + .operationName("catalogCreateCatalog") + .startTime(dateService.iso8601DateParse("2012-02-07T00:16:28.450-05:00")) + .endTime(dateService.iso8601DateParse("2012-02-07T00:16:28.867-05:00")) + .expiryTime(dateService.iso8601DateParse("2012-05-07T00:16:28.450-04:00")) + .owner(Reference.builder() + .type("application/vnd.vmware.vcloud.catalog+xml") + .name("QunyingTestCatalog") + .href(URI.create("https://vcloudbeta.bluelock.com/api/catalog/7212e451-76e1-4631-b2de-ba1dfd8080e4")) + .build()) + .user(Reference.builder() + .type("application/vnd.vmware.admin.user+xml") + .name("JClouds") + .href(URI.create("https://vcloudbeta.bluelock.com/api/org/6f312e42-cd2b-488d-a2bb-97519cd57ed0")) + .build()) + .org(Reference.builder() + .type("application/vnd.vmware.vcloud.org+xml") + .name("JClouds") + .href(URI.create("https://vcloudbeta.bluelock.com/api/org/6f312e42-cd2b-488d-a2bb-97519cd57ed0")) + .build()) + .build(); + } + + public static Task taskTwo() { + return Task.builder() + .type("application/vnd.vmware.vcloud.task+xml") + .name("task") + .id("urn:vcloud:task:bd22e745-9c2a-4f82-a954-0e35b6f76ba5") + .href(URI.create("https://vcloudbeta.bluelock.com/api/task/bd22e745-9c2a-4f82-a954-0e35b6f76ba5")) + .status("success") + .operation("Enabled User (967d317c-4273-4a95-b8a4-bf63b78e9c69)") + .operationName("jobEnable") + .startTime(dateService.iso8601DateParse("2012-02-06T17:30:38.507-05:00")) + .endTime(dateService.iso8601DateParse("2012-02-06T17:30:38.507-05:00")) + .expiryTime(dateService.iso8601DateParse("2012-05-06T17:30:38.507-04:00")) + .user(Reference.builder() + .type("application/vnd.vmware.admin.user+xml") + .name("adrian@jclouds.org") + .href(URI.create("https://vcloudbeta.bluelock.com/api/admin/user/8c360b93-ed25-4c9a-8e24-d48cd9966d93")) + .build()) + .org(Reference.builder() + .type("application/vnd.vmware.vcloud.org+xml") + .name("JClouds") + .href(URI.create("https://vcloudbeta.bluelock.com/api/org/6f312e42-cd2b-488d-a2bb-97519cd57ed0")) + .build()) + .build(); } } + \ No newline at end of file diff --git a/labs/vcloud-director/src/test/java/org/jclouds/vcloud/director/v1_5/features/TaskClientLiveTest.java b/labs/vcloud-director/src/test/java/org/jclouds/vcloud/director/v1_5/features/TaskClientLiveTest.java new file mode 100644 index 0000000000..622020fb27 --- /dev/null +++ b/labs/vcloud-director/src/test/java/org/jclouds/vcloud/director/v1_5/features/TaskClientLiveTest.java @@ -0,0 +1,95 @@ +/* + * 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.vcloud.director.v1_5.features; + +import static org.jclouds.vcloud.director.v1_5.VCloudDirectorLiveTestConstants.*; +import static org.jclouds.vcloud.director.v1_5.domain.Checks.*; +import static org.testng.Assert.*; + +import java.net.URI; + +import org.jclouds.vcloud.director.v1_5.domain.OrgList; +import org.jclouds.vcloud.director.v1_5.domain.Reference; +import org.jclouds.vcloud.director.v1_5.domain.Task; +import org.jclouds.vcloud.director.v1_5.domain.TasksList; +import org.jclouds.vcloud.director.v1_5.internal.BaseVCloudDirectorClientLiveTest; +import org.testng.annotations.Test; + +import com.google.common.collect.Iterables; + +/** + * Tests live behavior of {@link TaskClient}. + * + * @author grkvlt@apache.org + */ +@Test(groups = { "live", "apitests" }, testName = "TaskClientLiveTest") +public class TaskClientLiveTest extends BaseVCloudDirectorClientLiveTest { + + /* + * Convenience references to API clients. + */ + + private final OrgClient orgClient = context.getApi().getOrgClient(); + private final TaskClient taskClient = context.getApi().getTaskClient(); + + /* + * Shared state between dependant tests. + */ + + private OrgList orgList; + private Reference orgRef; + private TasksList taskList; + private Task task; + private URI taskUri; + + @Test(testName = "GET /tasksList/{id}") + public void testGetTaskList() { + orgList = orgClient.getOrgList(); + orgRef = Iterables.getFirst(orgList.getOrgs(), null); + + // Call the method being tested + taskList = taskClient.getTaskList(orgRef); + + // NOTE The environment MUST have ... + + // Check required elements and attributes + assertFalse(Iterables.isEmpty(taskList.getTasks()), "There must always be Task elements in the TaskList"); + + for (Task task : taskList.getTasks()) { + checkTask(task); + } + } + + @Test(testName = "GET /task/{id}", dependsOnMethods = { "testGetTaskList" }) + public void testGetTask() { + taskUri = Iterables.getFirst(taskList.getTasks(), null).getHref(); + + // Call the method being tested + task = taskClient.getTask(taskUri); + + // Check required elements and attributes + checkTask(task); + } + + @Test(testName = "GET /task/{id}/metadata/", dependsOnMethods = { "testGetTask" }) + public void testCancelTask() { + // Call the method being tested + taskClient.cancelTask(taskUri); + } +} diff --git a/labs/vcloud-director/src/test/java/org/jclouds/vcloud/director/v1_5/internal/BaseVCloudDirectorClientLiveTest.java b/labs/vcloud-director/src/test/java/org/jclouds/vcloud/director/v1_5/internal/BaseVCloudDirectorClientLiveTest.java index 74662b0bdd..c2fd50c785 100644 --- a/labs/vcloud-director/src/test/java/org/jclouds/vcloud/director/v1_5/internal/BaseVCloudDirectorClientLiveTest.java +++ b/labs/vcloud-director/src/test/java/org/jclouds/vcloud/director/v1_5/internal/BaseVCloudDirectorClientLiveTest.java @@ -21,12 +21,12 @@ package org.jclouds.vcloud.director.v1_5.internal; import java.util.Properties; import org.jclouds.compute.BaseVersionedServiceLiveTest; -import org.jclouds.logging.slf4j.config.SLF4JLoggingModule; -import org.jclouds.vcloud.director.v1_5.VCloudDirectorAsyncClient; -import org.jclouds.vcloud.director.v1_5.VCloudDirectorClient; +import org.jclouds.logging.log4j.config.Log4JLoggingModule; import org.jclouds.rest.RestContext; import org.jclouds.rest.RestContextFactory; import org.jclouds.sshj.config.SshjSshClientModule; +import org.jclouds.vcloud.director.v1_5.VCloudDirectorAsyncClient; +import org.jclouds.vcloud.director.v1_5.VCloudDirectorClient; import org.testng.annotations.AfterGroups; import org.testng.annotations.BeforeGroups; import org.testng.annotations.Test; @@ -35,7 +35,7 @@ import com.google.common.collect.ImmutableSet; import com.google.inject.Module; /** - * Tests behavior of {@code VCloudDirectorClient} + * Tests behavior of {@link VCloudDirectorClient} and acts as parent for other client live tests. * * @author Adrian Cole */ @@ -47,12 +47,28 @@ public class BaseVCloudDirectorClientLiveTest extends BaseVersionedServiceLiveTe protected RestContext context; + protected String catalogName; + protected String mediaId; + protected String vAppTemplateId; + protected String networkId; + protected String vDCId; + + @Override + protected void setupCredentials() { + super.setupCredentials(); + catalogName = System.getProperty("test." + provider + ".catalog-name", "Public"); + mediaId = System.getProperty("test." + provider + ".media-id"); + vAppTemplateId = System.getProperty("test." + provider + ".vapptemplate-id"); + networkId = System.getProperty("test." + provider + ".network-id"); + vDCId = System.getProperty("test." + provider + ".vdc-id"); + } + @BeforeGroups(groups = { "live" }) public void setupClient() { setupCredentials(); Properties overrides = setupProperties(); context = new RestContextFactory().createContext(provider, identity, credential, - ImmutableSet. of(new SLF4JLoggingModule(), new SshjSshClientModule()), overrides); + ImmutableSet. of(new Log4JLoggingModule(), new SshjSshClientModule()), overrides); } @AfterGroups(groups = "live") diff --git a/labs/vcloud-director/src/test/java/org/jclouds/vcloud/director/v1_5/internal/BaseVCloudDirectorRestClientExpectTest.java b/labs/vcloud-director/src/test/java/org/jclouds/vcloud/director/v1_5/internal/BaseVCloudDirectorRestClientExpectTest.java index ff01e2a85a..75c4a4ea49 100644 --- a/labs/vcloud-director/src/test/java/org/jclouds/vcloud/director/v1_5/internal/BaseVCloudDirectorRestClientExpectTest.java +++ b/labs/vcloud-director/src/test/java/org/jclouds/vcloud/director/v1_5/internal/BaseVCloudDirectorRestClientExpectTest.java @@ -18,6 +18,9 @@ */ package org.jclouds.vcloud.director.v1_5.internal; +import static com.google.common.base.Preconditions.checkNotNull; +import static org.testng.Assert.assertNotNull; + import java.net.URI; import org.jclouds.date.DateService; @@ -26,13 +29,11 @@ import org.jclouds.http.HttpResponse; import org.jclouds.rest.BaseRestClientExpectTest; import org.jclouds.vcloud.director.v1_5.VCloudDirectorClient; import org.jclouds.vcloud.director.v1_5.VCloudDirectorMediaType; -import org.jclouds.vcloud.director.v1_5.domain.ReferenceType; -import org.testng.annotations.BeforeClass; +import org.testng.annotations.BeforeGroups; -import com.google.common.base.Function; -import com.google.common.base.Splitter; import com.google.common.collect.ImmutableMultimap; -import com.google.common.collect.Iterables; +import com.google.common.collect.LinkedListMultimap; +import com.google.common.collect.Multimap; import com.google.inject.Guice; /** @@ -48,12 +49,12 @@ public class BaseVCloudDirectorRestClientExpectTest extends BaseRestClientExpect public static final String token = "mIaR3/6Lna8DWImd7/JPR5rK8FcUHabt+G/UCJV5pJQ="; public static final String endpoint = "https://vcloudbeta.bluelock.com/api"; - protected DateService dateService; + protected static DateService dateService; - @BeforeClass - protected void setUpInjector() { + @BeforeGroups("unit") + protected static void setUpInjector() { dateService = Guice.createInjector().getInstance(DateService.class); - assert dateService != null; + assertNotNull(dateService); } protected HttpRequest loginRequest = HttpRequest.builder() @@ -80,14 +81,28 @@ public class BaseVCloudDirectorRestClientExpectTest extends BaseRestClientExpect credential = password; } - protected HttpRequest getStandardRequest(String method, String command) { - return getStandardRequest(method, URI.create(endpoint + command)); + protected HttpRequest getStandardRequest(String method, String path) { + return getStandardRequest(method, path, VCloudDirectorMediaType.ANY); } protected HttpRequest getStandardRequest(String method, URI uri) { return getStandardRequest(method, uri, VCloudDirectorMediaType.ANY); } + protected HttpRequest getStandardRequest(String method, String path, String mediaType) { + return getStandardRequest(method, URI.create(endpoint + path), VCloudDirectorMediaType.ANY); + } + + protected HttpRequest getStandardPayloadRequest(String method, String command, String relativeFilePath, + String postMediaType) { + return getStandardPayloadRequest(method, URI.create(endpoint + command), relativeFilePath, postMediaType); + } + + protected HttpRequest getStandardPayloadRequest(String method, URI uri, String relativeFilePath, + String postMediaType) { + return getStandardRequestWithPayload(method, uri, VCloudDirectorMediaType.ANY, relativeFilePath, postMediaType); + } + protected HttpRequest getStandardRequest(String method, URI uri, String mediaType) { return HttpRequest.builder() .method(method) @@ -98,6 +113,31 @@ public class BaseVCloudDirectorRestClientExpectTest extends BaseRestClientExpect .build()) .build(); } + + protected HttpRequest getStandardRequestWithPayload(String method, String path, String relativeFilePath, String mediaType) { + return getStandardRequestWithPayload(method, path, VCloudDirectorMediaType.ANY, relativeFilePath, mediaType); + } + + protected HttpRequest getStandardRequestWithPayload(String method, URI uri, String relativeFilePath, String mediaType) { + return getStandardRequestWithPayload(method, uri, VCloudDirectorMediaType.ANY, relativeFilePath, mediaType); + } + + protected HttpRequest getStandardRequestWithPayload(String method, String path, String acceptType, String relativeFilePath, String mediaType) { + URI uri = URI.create(endpoint + path); + return getStandardRequestWithPayload(method, uri, acceptType, relativeFilePath, mediaType); + } + + protected HttpRequest getStandardRequestWithPayload(String method, URI uri, String acceptType, String relativeFilePath, String mediaType) { + return HttpRequest.builder() + .method(method) + .endpoint(uri) + .headers(ImmutableMultimap. builder() + .put("Accept", acceptType) + .put("x-vcloud-authorization", token) + .build()) + .payload(payloadFromResourceWithContentType(relativeFilePath, mediaType)) + .build(); + } protected HttpResponse getStandardPayloadResponse(String relativeFilePath, String mediaType) { return getStandardPayloadResponse(200, relativeFilePath, mediaType); @@ -106,6 +146,71 @@ public class BaseVCloudDirectorRestClientExpectTest extends BaseRestClientExpect protected HttpResponse getStandardPayloadResponse(int statusCode, String relativeFilePath, String mediaType) { return HttpResponse.builder() .statusCode(statusCode) - .payload(payloadFromResourceWithContentType(relativeFilePath, mediaType + ";version=1.5")).build(); + .payload(payloadFromResourceWithContentType(relativeFilePath, mediaType + ";version=1.5")) + .build(); + } + + /** + * Implicitly adds x-vcloud-authorization header with token. + * Provides convenience methods for priming a HttpRequest.Builder for vCloud testing + * + * @author danikov + * + */ + protected class VcloudHttpRequestPrimer { + private Multimap headers = LinkedListMultimap.create(); + private HttpRequest.Builder builder = HttpRequest.builder(); + + public VcloudHttpRequestPrimer() { + } + + public VcloudHttpRequestPrimer apiCommand(String method, String command) { + builder.method(method).endpoint(URI.create(endpoint + command)); + return this; + } + + public VcloudHttpRequestPrimer xmlFilePayload(String relativeFilePath, String mediaType) { + builder.payload(payloadFromResourceWithContentType(relativeFilePath, mediaType)); + return this; + } + + public VcloudHttpRequestPrimer headers(Multimap headers) { + this.headers.putAll(ImmutableMultimap.copyOf(checkNotNull(headers, "headers"))); + return this; + } + + public VcloudHttpRequestPrimer acceptAnyMedia() { + return acceptMedia(VCloudDirectorMediaType.ANY); + } + + public VcloudHttpRequestPrimer acceptMedia(String media) { + return header("Accept", media); + } + + public VcloudHttpRequestPrimer header(String name, String value) { + headers.put(checkNotNull(name, "header.name"), checkNotNull(value, "header.value")); + return this; + } + + public HttpRequest.Builder httpRequestBuilder() { + header("x-vcloud-authorization", token); + builder.headers(headers); + return builder; + } + } + + protected class VcloudHttpResponsePrimer { + private HttpResponse.Builder builder = HttpResponse.builder(); + + public VcloudHttpResponsePrimer() { + } + + public VcloudHttpResponsePrimer xmlFilePayload(String relativeFilePath, String mediaType) { + builder.payload(payloadFromResourceWithContentType(relativeFilePath, mediaType)); + return this; + } + public HttpResponse.Builder httpResponseBuilder() { + return builder; + } } } diff --git a/labs/vcloud-director/src/test/resources/catalog/catalogItem.xml b/labs/vcloud-director/src/test/resources/catalog/catalogItem.xml index 39021f96d9..6157c73f21 100644 --- a/labs/vcloud-director/src/test/resources/catalog/catalogItem.xml +++ b/labs/vcloud-director/src/test/resources/catalog/catalogItem.xml @@ -1,9 +1,9 @@ - - + + - New Catalog Item + For testing - \ No newline at end of file + diff --git a/labs/vcloud-director/src/test/resources/catalog/catalogItemMetadata.xml b/labs/vcloud-director/src/test/resources/catalog/catalogItemMetadata.xml new file mode 100644 index 0000000000..e642235ba5 --- /dev/null +++ b/labs/vcloud-director/src/test/resources/catalog/catalogItemMetadata.xml @@ -0,0 +1,9 @@ + + + + + + KEY + VALUE + + \ No newline at end of file diff --git a/labs/vcloud-director/src/test/resources/catalog/catalogItemMetadataEntry.xml b/labs/vcloud-director/src/test/resources/catalog/catalogItemMetadataEntry.xml new file mode 100644 index 0000000000..23cef493a4 --- /dev/null +++ b/labs/vcloud-director/src/test/resources/catalog/catalogItemMetadataEntry.xml @@ -0,0 +1,6 @@ + + + + KEY + VALUE + diff --git a/labs/vcloud-director/src/test/resources/catalog/catalogMetadata.xml b/labs/vcloud-director/src/test/resources/catalog/catalogMetadata.xml index 0ff3052583..3db76a66c5 100644 --- a/labs/vcloud-director/src/test/resources/catalog/catalogMetadata.xml +++ b/labs/vcloud-director/src/test/resources/catalog/catalogMetadata.xml @@ -1,8 +1,9 @@ - + - - key - value - + + + KEY + VALUE + \ No newline at end of file diff --git a/labs/vcloud-director/src/test/resources/catalog/catalogMetadataEntry.xml b/labs/vcloud-director/src/test/resources/catalog/catalogMetadataEntry.xml new file mode 100644 index 0000000000..345afec682 --- /dev/null +++ b/labs/vcloud-director/src/test/resources/catalog/catalogMetadataEntry.xml @@ -0,0 +1,6 @@ + + + + KEY + VALUE + diff --git a/labs/vcloud-director/src/test/resources/catalog/createdCatalogItem.xml b/labs/vcloud-director/src/test/resources/catalog/createdCatalogItem.xml new file mode 100644 index 0000000000..39021f96d9 --- /dev/null +++ b/labs/vcloud-director/src/test/resources/catalog/createdCatalogItem.xml @@ -0,0 +1,9 @@ + + + + + + + New Catalog Item + + \ No newline at end of file diff --git a/labs/vcloud-director/src/test/resources/catalog/deleteMetadataEntryTask.xml b/labs/vcloud-director/src/test/resources/catalog/deleteMetadataEntryTask.xml new file mode 100644 index 0000000000..1968b62eea --- /dev/null +++ b/labs/vcloud-director/src/test/resources/catalog/deleteMetadataEntryTask.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/labs/vcloud-director/src/test/resources/catalog/mergeCatalogItemMetadata.xml b/labs/vcloud-director/src/test/resources/catalog/mergeCatalogItemMetadata.xml new file mode 100644 index 0000000000..5f76b5fcd7 --- /dev/null +++ b/labs/vcloud-director/src/test/resources/catalog/mergeCatalogItemMetadata.xml @@ -0,0 +1,7 @@ + + + + KEY + VALUE + + diff --git a/labs/vcloud-director/src/test/resources/catalog/mergeMetadataTask.xml b/labs/vcloud-director/src/test/resources/catalog/mergeMetadataTask.xml new file mode 100644 index 0000000000..bc7beb6a6a --- /dev/null +++ b/labs/vcloud-director/src/test/resources/catalog/mergeMetadataTask.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/labs/vcloud-director/src/test/resources/catalog/setCatalogItemMetadataValue.xml b/labs/vcloud-director/src/test/resources/catalog/setCatalogItemMetadataValue.xml new file mode 100644 index 0000000000..2032bf58cc --- /dev/null +++ b/labs/vcloud-director/src/test/resources/catalog/setCatalogItemMetadataValue.xml @@ -0,0 +1,4 @@ + + + KITTENS + diff --git a/labs/vcloud-director/src/test/resources/catalog/setMetadataValueTask.xml b/labs/vcloud-director/src/test/resources/catalog/setMetadataValueTask.xml new file mode 100644 index 0000000000..6596608513 --- /dev/null +++ b/labs/vcloud-director/src/test/resources/catalog/setMetadataValueTask.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/labs/vcloud-director/src/test/resources/catalog/updateCatalogItem.xml b/labs/vcloud-director/src/test/resources/catalog/updateCatalogItem.xml new file mode 100644 index 0000000000..6157c73f21 --- /dev/null +++ b/labs/vcloud-director/src/test/resources/catalog/updateCatalogItem.xml @@ -0,0 +1,9 @@ + + + + + + + For testing + + diff --git a/labs/vcloud-director/src/test/resources/log4j.xml b/labs/vcloud-director/src/test/resources/log4j.xml new file mode 100644 index 0000000000..63810d3ca0 --- /dev/null +++ b/labs/vcloud-director/src/test/resources/log4j.xml @@ -0,0 +1,151 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/labs/vcloud-director/src/test/resources/media/deleteMediaTask.xml b/labs/vcloud-director/src/test/resources/media/deleteMediaTask.xml new file mode 100644 index 0000000000..7fde5f0513 --- /dev/null +++ b/labs/vcloud-director/src/test/resources/media/deleteMediaTask.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/labs/vcloud-director/src/test/resources/media/deleteMetadataEntryTask.xml b/labs/vcloud-director/src/test/resources/media/deleteMetadataEntryTask.xml new file mode 100644 index 0000000000..2d258bf7a7 --- /dev/null +++ b/labs/vcloud-director/src/test/resources/media/deleteMetadataEntryTask.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/labs/vcloud-director/src/test/resources/media/error400.xml b/labs/vcloud-director/src/test/resources/media/error400.xml new file mode 100644 index 0000000000..981f249e85 --- /dev/null +++ b/labs/vcloud-director/src/test/resources/media/error400.xml @@ -0,0 +1,2 @@ + + diff --git a/labs/vcloud-director/src/test/resources/media/error403-catalog.xml b/labs/vcloud-director/src/test/resources/media/error403-catalog.xml new file mode 100644 index 0000000000..f1f0b7fee5 --- /dev/null +++ b/labs/vcloud-director/src/test/resources/media/error403-catalog.xml @@ -0,0 +1,2 @@ + + diff --git a/labs/vcloud-director/src/test/resources/media/error403-fake.xml b/labs/vcloud-director/src/test/resources/media/error403-fake.xml new file mode 100644 index 0000000000..3b582f3c0c --- /dev/null +++ b/labs/vcloud-director/src/test/resources/media/error403-fake.xml @@ -0,0 +1,2 @@ + + diff --git a/labs/vcloud-director/src/test/resources/media/media.xml b/labs/vcloud-director/src/test/resources/media/media.xml new file mode 100644 index 0000000000..cf0caa5498 --- /dev/null +++ b/labs/vcloud-director/src/test/resources/media/media.xml @@ -0,0 +1,13 @@ + + + + + + + + + Windows 2003 R2 Disk2 Standard 32bit & 64bit + + + + diff --git a/labs/vcloud-director/src/test/resources/media/mergeMetadata.xml b/labs/vcloud-director/src/test/resources/media/mergeMetadata.xml new file mode 100644 index 0000000000..c61ddcd5f1 --- /dev/null +++ b/labs/vcloud-director/src/test/resources/media/mergeMetadata.xml @@ -0,0 +1,12 @@ + + + + + + + + + key + value + + diff --git a/labs/vcloud-director/src/test/resources/media/mergeMetadataTask.xml b/labs/vcloud-director/src/test/resources/media/mergeMetadataTask.xml new file mode 100644 index 0000000000..fb7474751c --- /dev/null +++ b/labs/vcloud-director/src/test/resources/media/mergeMetadataTask.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/labs/vcloud-director/src/test/resources/media/metadata.xml b/labs/vcloud-director/src/test/resources/media/metadata.xml new file mode 100644 index 0000000000..838f7b7d92 --- /dev/null +++ b/labs/vcloud-director/src/test/resources/media/metadata.xml @@ -0,0 +1,12 @@ + + + + + + + + + key + value + + \ No newline at end of file diff --git a/labs/vcloud-director/src/test/resources/media/metadataValue.xml b/labs/vcloud-director/src/test/resources/media/metadataValue.xml new file mode 100644 index 0000000000..ccc04eaa0f --- /dev/null +++ b/labs/vcloud-director/src/test/resources/media/metadataValue.xml @@ -0,0 +1,7 @@ + + + + + + value + diff --git a/labs/vcloud-director/src/test/resources/media/owner.xml b/labs/vcloud-director/src/test/resources/media/owner.xml new file mode 100644 index 0000000000..fe6c4228ff --- /dev/null +++ b/labs/vcloud-director/src/test/resources/media/owner.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/labs/vcloud-director/src/test/resources/media/setMetadataValue.xml b/labs/vcloud-director/src/test/resources/media/setMetadataValue.xml new file mode 100644 index 0000000000..275e5b4b62 --- /dev/null +++ b/labs/vcloud-director/src/test/resources/media/setMetadataValue.xml @@ -0,0 +1,4 @@ + + + value + diff --git a/labs/vcloud-director/src/test/resources/media/setMetadataValueTask.xml b/labs/vcloud-director/src/test/resources/media/setMetadataValueTask.xml new file mode 100644 index 0000000000..459e78a0b1 --- /dev/null +++ b/labs/vcloud-director/src/test/resources/media/setMetadataValueTask.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/labs/vcloud-director/src/test/resources/media/updateMedia.xml b/labs/vcloud-director/src/test/resources/media/updateMedia.xml new file mode 100644 index 0000000000..b7cbb05257 --- /dev/null +++ b/labs/vcloud-director/src/test/resources/media/updateMedia.xml @@ -0,0 +1,13 @@ + + + + + + + + + new test description + + + + \ No newline at end of file diff --git a/labs/vcloud-director/src/test/resources/media/updateMediaTask.xml b/labs/vcloud-director/src/test/resources/media/updateMediaTask.xml new file mode 100644 index 0000000000..9f8c0aff5c --- /dev/null +++ b/labs/vcloud-director/src/test/resources/media/updateMediaTask.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/labs/vcloud-director/src/test/resources/network/error400.xml b/labs/vcloud-director/src/test/resources/network/error400.xml new file mode 100644 index 0000000000..4013d6ff57 --- /dev/null +++ b/labs/vcloud-director/src/test/resources/network/error400.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/labs/vcloud-director/src/test/resources/network/error403-catalog.xml b/labs/vcloud-director/src/test/resources/network/error403-catalog.xml new file mode 100644 index 0000000000..38c90857ee --- /dev/null +++ b/labs/vcloud-director/src/test/resources/network/error403-catalog.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/labs/vcloud-director/src/test/resources/network/error403-fake.xml b/labs/vcloud-director/src/test/resources/network/error403-fake.xml new file mode 100644 index 0000000000..38c90857ee --- /dev/null +++ b/labs/vcloud-director/src/test/resources/network/error403-fake.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/labs/vcloud-director/src/test/resources/network/metadata.xml b/labs/vcloud-director/src/test/resources/network/metadata.xml index 035f8ef25d..947602766b 100644 --- a/labs/vcloud-director/src/test/resources/network/metadata.xml +++ b/labs/vcloud-director/src/test/resources/network/metadata.xml @@ -1,4 +1,8 @@ + + key + value + diff --git a/labs/vcloud-director/src/test/resources/org/org.xml b/labs/vcloud-director/src/test/resources/org/org.xml index 941eb7dbd0..f87c5a9913 100644 --- a/labs/vcloud-director/src/test/resources/org/org.xml +++ b/labs/vcloud-director/src/test/resources/org/org.xml @@ -2,7 +2,7 @@ - + diff --git a/labs/vcloud-director/src/test/resources/org/metadata.xml b/labs/vcloud-director/src/test/resources/org/orgMetadata.xml similarity index 50% rename from labs/vcloud-director/src/test/resources/org/metadata.xml rename to labs/vcloud-director/src/test/resources/org/orgMetadata.xml index 992459fd0d..f8595dc89e 100644 --- a/labs/vcloud-director/src/test/resources/org/metadata.xml +++ b/labs/vcloud-director/src/test/resources/org/orgMetadata.xml @@ -1,4 +1,9 @@ + + + KEY + VALUE + diff --git a/labs/vcloud-director/src/test/resources/org/orgMetadataEntry.xml b/labs/vcloud-director/src/test/resources/org/orgMetadataEntry.xml new file mode 100644 index 0000000000..8cb2bd63c9 --- /dev/null +++ b/labs/vcloud-director/src/test/resources/org/orgMetadataEntry.xml @@ -0,0 +1,6 @@ + + + + KEY + VALUE + diff --git a/labs/virtualbox/pom.xml b/labs/virtualbox/pom.xml index f1c6d35098..ecfa157bfd 100644 --- a/labs/virtualbox/pom.xml +++ b/labs/virtualbox/pom.xml @@ -148,8 +148,8 @@ ${project.artifactId} - org.jclouds.virtualbox.*;version="${project.version}" - org.jclouds.*;version="${project.version}",* + org.jclouds.virtualbox*;version="${project.version}" + org.jclouds*;version="${project.version}",* diff --git a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/compute/VirtualBoxComputeServiceAdapter.java b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/compute/VirtualBoxComputeServiceAdapter.java index 4c0a4e46c6..1b031d1370 100644 --- a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/compute/VirtualBoxComputeServiceAdapter.java +++ b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/compute/VirtualBoxComputeServiceAdapter.java @@ -139,7 +139,7 @@ public class VirtualBoxComputeServiceAdapter implements ComputeServiceAdapter T propogate(Exception e) { - Throwables.propagate(e); - assert false; - return null; - } - private void launchVMProcess(IMachine machine, ISession session) { IProgress prog = machine.launchVMProcess(session, "gui", ""); prog.waitForCompletion(-1); @@ -184,8 +178,7 @@ public class VirtualBoxComputeServiceAdapter implements ComputeServiceAdapter { @@ -88,12 +98,12 @@ public class CreateAndInstallVm implements Function { VmSpec vmSpec = masterSpec.getVmSpec(); IsoSpec isoSpec = masterSpec.getIsoSpec(); String vmName = vmSpec.getVmName(); - + final IMachine vm = createAndRegisterMachineFromIsoIfNotAlreadyExists.apply(masterSpec); // Launch machine and wait for it to come online ensureMachineIsLaunched(vmName); - + URI uri = preConfiguration.getUnchecked(isoSpec); String installationKeySequence = isoSpec.getInstallationKeySequence().replace("PRECONFIGURATION_URL", uri.toASCIIString()); @@ -106,7 +116,13 @@ public class CreateAndInstallVm implements Function { logger.debug(">> awaiting installation of guest additions on vm: %s", vmName); checkState(new GuestAdditionsInstaller(context).apply(vmName)); - + + logger.debug(">> awaiting post-installation actions on vm: %s", vmName); + ListenableFuture execFuture = context.getComputeService().submitScriptOnNode(vmName, + call("cleanupUdevIfNeeded"), RunScriptOptions.NONE); + ExecResponse execResponse = Futures.getUnchecked(execFuture); + checkState(execResponse.getExitCode() == 0); + logger.debug("<< installation of image complete. Powering down node(%s)", vmName); ensureMachineHasPowerDown(vmName); return vm; diff --git a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/predicates/GuestAdditionsInstaller.java b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/predicates/GuestAdditionsInstaller.java index 05afd85a3a..7c8d6c8613 100644 --- a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/predicates/GuestAdditionsInstaller.java +++ b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/predicates/GuestAdditionsInstaller.java @@ -1,26 +1,20 @@ package org.jclouds.virtualbox.predicates; -import static org.jclouds.compute.options.RunScriptOptions.Builder.runAsRoot; - -import java.util.concurrent.ExecutionException; - import javax.annotation.Resource; import javax.inject.Named; import javax.inject.Singleton; import org.jclouds.compute.ComputeServiceContext; -import org.jclouds.compute.RunScriptData; import org.jclouds.compute.domain.ExecResponse; +import org.jclouds.compute.options.RunScriptOptions; import org.jclouds.compute.reference.ComputeServiceConstants; import org.jclouds.logging.Logger; -import org.jclouds.scriptbuilder.domain.StatementList; -import org.jclouds.scriptbuilder.domain.Statements; import org.jclouds.virtualbox.statements.InstallGuestAdditions; import com.google.common.base.Predicate; import com.google.common.base.Splitter; -import com.google.common.base.Throwables; import com.google.common.collect.Iterables; +import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.inject.Inject; @@ -41,27 +35,11 @@ public class GuestAdditionsInstaller implements Predicate { @Override public boolean apply(String vmName) { - StatementList statementList = prepareStatementList(); - - ListenableFuture execFuture = context.getComputeService().submitScriptOnNode(vmName, statementList, - runAsRoot(true).wrapInInitScript(false)); - ExecResponse execResponse = null; - try { - execResponse = execFuture.get(); - } catch (InterruptedException e) { - Throwables.propagate(e); - } catch (ExecutionException e) { - Throwables.propagate(e); - } - return execResponse == null ? false : execResponse.getExitCode() == 0; - } - - private StatementList prepareStatementList() { vboxVersion = Iterables.get(Splitter.on('r').split(context.getProviderSpecificContext().getBuildVersion()), 0); - InstallGuestAdditions installGuestAdditions = new InstallGuestAdditions(vboxVersion); - StatementList statementList = new StatementList(Statements.exec(RunScriptData.aptInstallLazyUpgrade("curl")), - installGuestAdditions); - return statementList; + ListenableFuture execFuture = context.getComputeService().submitScriptOnNode(vmName, + new InstallGuestAdditions(vboxVersion), RunScriptOptions.NONE); + ExecResponse execResponse = Futures.getUnchecked(execFuture); + return execResponse == null ? false : execResponse.getExitStatus() == 0; } } \ No newline at end of file diff --git a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/predicates/SshAvailable.java b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/predicates/SshAvailable.java index ffede70326..418b7dcec9 100644 --- a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/predicates/SshAvailable.java +++ b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/predicates/SshAvailable.java @@ -53,7 +53,7 @@ public class SshAvailable implements Predicate { try { if (context.getComputeService() .runScriptOnNode(nodeId, "id", wrapInInitScript(false).runAsRoot(false)) - .getExitCode() == 0) { + .getExitStatus() == 0) { logger.debug("Got response from ssh daemon running on %s", nodeId); sshDaemonIsRunning = true; } diff --git a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/predicates/SshResponds.java b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/predicates/SshResponds.java index 676f42a169..fe9f8c8917 100644 --- a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/predicates/SshResponds.java +++ b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/predicates/SshResponds.java @@ -39,7 +39,7 @@ public class SshResponds implements Predicate { try { client.connect(); - if (client.exec("id").getExitCode() == 0) { + if (client.exec("id").getExitStatus() == 0) { return true; } } catch (SshException e) { diff --git a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/statements/InstallGuestAdditions.java b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/statements/InstallGuestAdditions.java index 8ba07609ea..6d6e5a7122 100644 --- a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/statements/InstallGuestAdditions.java +++ b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/statements/InstallGuestAdditions.java @@ -22,54 +22,37 @@ package org.jclouds.virtualbox.statements; import static com.google.common.base.Preconditions.checkNotNull; import static org.jclouds.scriptbuilder.domain.Statements.call; import static org.jclouds.scriptbuilder.domain.Statements.exec; +import static org.jclouds.scriptbuilder.domain.Statements.saveHttpResponseTo; import java.net.URI; -import java.util.Collections; -import org.jclouds.scriptbuilder.ScriptBuilder; import org.jclouds.scriptbuilder.domain.OsFamily; -import org.jclouds.scriptbuilder.domain.SaveHttpResponseTo; -import org.jclouds.scriptbuilder.domain.Statement; +import org.jclouds.scriptbuilder.domain.StatementList; -import com.google.common.collect.ImmutableMultimap; - -public class InstallGuestAdditions implements Statement { - - private final String vboxVersion; - private final String mountPoint; +public class InstallGuestAdditions extends StatementList { public InstallGuestAdditions(String vboxVersion) { - this(vboxVersion, "/mnt"); + this(vboxVersion, "/mnt", "VBoxGuestAdditions_" + vboxVersion + ".iso"); } - public InstallGuestAdditions(String vboxVersion, String mountPoint) { - this.vboxVersion = checkNotNull(vboxVersion, "vboxVersion"); - this.mountPoint = checkNotNull(mountPoint, "mountPoint"); + public InstallGuestAdditions(String vboxVersion, String mountPoint, String vboxGuestAdditionsIso) { + this(URI.create("http://download.virtualbox.org/virtualbox/" + vboxVersion + "/" + vboxGuestAdditionsIso), + mountPoint, vboxGuestAdditionsIso); } - @Override - public Iterable functionDependencies(OsFamily family) { - return Collections.emptyList(); + public InstallGuestAdditions(URI download, String mountPoint, String vboxGuestAdditionsIso) { + super(call("setupPublicCurl"), // + saveHttpResponseTo(download, "{tmp}{fs}", vboxGuestAdditionsIso),// + exec(String.format("mount -o loop {tmp}{fs}%s %s", vboxGuestAdditionsIso, mountPoint)), + call("installModuleAssistantIfNeeded"), // + exec(String.format("%s%s", mountPoint, "/VBoxLinuxAdditions.run")), // + exec(String.format("umount %s", mountPoint))); } @Override public String render(OsFamily family) { - checkNotNull(family, "family"); - if (family == OsFamily.WINDOWS) + if (checkNotNull(family, "family") == OsFamily.WINDOWS) throw new UnsupportedOperationException("windows not yet implemented"); - - String vboxGuestAdditionsIso = "VBoxGuestAdditions_" + vboxVersion + ".iso"; - ScriptBuilder scriptBuilder = new ScriptBuilder() - .addStatement( - new SaveHttpResponseTo("{tmp}{fs}", vboxGuestAdditionsIso, "GET", URI - .create("http://download.virtualbox.org/virtualbox/" + vboxVersion + "/" - + vboxGuestAdditionsIso), ImmutableMultimap. of())) - .addStatement(exec(String.format("mount -o loop {tmp}{fs}%s %s", vboxGuestAdditionsIso, mountPoint))) - .addStatement(call("installModuleAssistantIfNeeded")) - .addStatement(exec(String.format("%s%s", mountPoint, "/VBoxLinuxAdditions.run"))) - .addStatement(exec(String.format("umount %s", mountPoint))); - - return scriptBuilder.render(family); + return super.render(family); } - } diff --git a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/statements/Statements.java b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/statements/Statements.java index 6698c8800e..5bfdb1c079 100644 --- a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/statements/Statements.java +++ b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/statements/Statements.java @@ -18,7 +18,7 @@ */ package org.jclouds.virtualbox.statements; -import org.jclouds.scriptbuilder.domain.Call; +import org.jclouds.scriptbuilder.ScriptBuilder; import org.jclouds.scriptbuilder.domain.Statement; /** @@ -35,6 +35,6 @@ public class Statements { * - the vm name */ public static Statement exportIpAddressFromVmNamed(String vmName) { - return new Call("exportIpAddressFromVmNamed", vmName); + return ScriptBuilder.call("exportIpAddressFromVmNamed", vmName); } } diff --git a/labs/virtualbox/src/main/resources/functions/cleanupUdevIfNeeded.sh b/labs/virtualbox/src/main/resources/functions/cleanupUdevIfNeeded.sh new file mode 100644 index 0000000000..59f3d0b2ab --- /dev/null +++ b/labs/virtualbox/src/main/resources/functions/cleanupUdevIfNeeded.sh @@ -0,0 +1,12 @@ +function cleanupUdevIfNeeded { + unset OSNAME; + local OSNAME=`lsb_release -d -s | cut -d ' ' -f 1`; shift + if [ $OSNAME = 'Ubuntu' ] + then + echo "OS is Ubuntu" + rm /etc/udev/rules.d/70-persistent-net.rules; + mkdir /etc/udev/rules.d/70-persistent-net.rules; + rm -rf /dev/.udev/; + rm /lib/udev/rules.d/75-persistent-net-generator.rules + fi +} \ No newline at end of file diff --git a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/compute/VirtualBoxComputeServiceAdapterLiveTest.java b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/compute/VirtualBoxComputeServiceAdapterLiveTest.java index df24afd931..f8bb78a589 100644 --- a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/compute/VirtualBoxComputeServiceAdapterLiveTest.java +++ b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/compute/VirtualBoxComputeServiceAdapterLiveTest.java @@ -50,11 +50,6 @@ public class VirtualBoxComputeServiceAdapterLiveTest extends BaseVirtualBoxClien adapter = context.utils().injector().getInstance(VirtualBoxComputeServiceAdapter.class); } - @Test - public void testListLocations() { - assertFalse(Iterables.isEmpty(adapter.listLocations())); - } - private static final PrioritizeCredentialsFromTemplate prioritizeCredentialsFromTemplate = new PrioritizeCredentialsFromTemplate( new DefaultCredentialsFromImageOrOverridingCredentials()); diff --git a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/domain/InstallGuestAdditionsTest.java b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/domain/InstallGuestAdditionsTest.java index 68df010720..1fdc34ff28 100644 --- a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/domain/InstallGuestAdditionsTest.java +++ b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/domain/InstallGuestAdditionsTest.java @@ -22,8 +22,10 @@ import static org.testng.Assert.assertEquals; import java.io.IOException; +import org.jclouds.scriptbuilder.InitScript; import org.jclouds.scriptbuilder.domain.OsFamily; import org.jclouds.scriptbuilder.domain.ShellToken; +import org.jclouds.scriptbuilder.domain.Statement; import org.jclouds.virtualbox.statements.InstallGuestAdditions; import org.testng.annotations.Test; @@ -33,10 +35,22 @@ import com.google.common.io.Resources; @Test(groups = "unit") public class InstallGuestAdditionsTest { - @Test - public void testUnix() throws IOException { - InstallGuestAdditions statement = new InstallGuestAdditions("4.1.6"); - assertEquals(statement.render(OsFamily.UNIX), CharStreams.toString(Resources.newReaderSupplier(Resources - .getResource("test_guest_additions_installer." + ShellToken.SH.to(OsFamily.UNIX)), Charsets.UTF_8))); - } + @Test + public void testUnixByItself() throws IOException { + InstallGuestAdditions statement = new InstallGuestAdditions("4.1.6"); + assertEquals(statement.render(OsFamily.UNIX), + CharStreams.toString(Resources.newReaderSupplier( + Resources.getResource("test_guest_additions_installer." + ShellToken.SH.to(OsFamily.UNIX)), + Charsets.UTF_8))); + } + + @Test + public void testUnixInInitScript() throws IOException { + Statement statement = InitScript.builder().name("install_guest_additions") + .run(new InstallGuestAdditions("4.1.6")).build(); + + assertEquals(statement.render(OsFamily.UNIX), CharStreams.toString(Resources.newReaderSupplier( + Resources.getResource("test_guest_additions_installer_init." + ShellToken.SH.to(OsFamily.UNIX)), + Charsets.UTF_8))); + } } \ No newline at end of file diff --git a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/functions/CloneAndRegisterMachineFromIsoIfNotAlreadyExistsLiveTest.java b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/functions/CloneAndRegisterMachineFromIsoIfNotAlreadyExistsLiveTest.java index c67956d000..182a5da936 100644 --- a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/functions/CloneAndRegisterMachineFromIsoIfNotAlreadyExistsLiveTest.java +++ b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/functions/CloneAndRegisterMachineFromIsoIfNotAlreadyExistsLiveTest.java @@ -33,6 +33,7 @@ import org.jclouds.virtualbox.domain.StorageController; import org.jclouds.virtualbox.domain.VmSpec; import org.jclouds.virtualbox.functions.CloneAndRegisterMachineFromIMachineIfNotAlreadyExists; import org.jclouds.virtualbox.functions.CreateAndRegisterMachineFromIsoIfNotAlreadyExists; +import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; import org.virtualbox_4_1.CleanupMode; @@ -138,4 +139,5 @@ public class CloneAndRegisterMachineFromIsoIfNotAlreadyExistsLiveTest extends .findMachine(sourceMachineSpec.getVmSpec().getVmId()); } } + } \ No newline at end of file diff --git a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/functions/CreateAndInstallVmLiveTest.java b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/functions/CreateAndInstallVmLiveTest.java index 362868c1a9..a52b0ab05d 100644 --- a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/functions/CreateAndInstallVmLiveTest.java +++ b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/functions/CreateAndInstallVmLiveTest.java @@ -19,10 +19,19 @@ package org.jclouds.virtualbox.functions; -import com.google.common.base.CaseFormat; -import com.google.common.base.Function; -import com.google.inject.Guice; -import com.google.inject.Injector; +import static com.google.common.base.Preconditions.checkState; +import static com.google.common.base.Predicates.equalTo; +import static com.google.common.collect.Iterables.any; +import static com.google.common.collect.Iterables.transform; +import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_IMAGE_PREFIX; +import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_INSTALLATION_KEY_SEQUENCE; +import static org.testng.Assert.assertTrue; + +import java.util.Map; +import java.util.Set; + +import javax.annotation.Nullable; + import org.jclouds.compute.config.BaseComputeServiceContextModule; import org.jclouds.compute.domain.Image; import org.jclouds.compute.domain.OsFamily; @@ -30,25 +39,35 @@ import org.jclouds.compute.reference.ComputeServiceConstants; import org.jclouds.config.ValueOfConfigurationKeyOrNull; import org.jclouds.json.Json; import org.jclouds.json.config.GsonModule; +import org.jclouds.ssh.SshClient; import org.jclouds.virtualbox.BaseVirtualBoxClientLiveTest; -import org.jclouds.virtualbox.domain.*; +import org.jclouds.virtualbox.domain.ExecutionType; +import org.jclouds.virtualbox.domain.HardDisk; +import org.jclouds.virtualbox.domain.IsoSpec; +import org.jclouds.virtualbox.domain.MasterSpec; +import org.jclouds.virtualbox.domain.NatAdapter; +import org.jclouds.virtualbox.domain.NetworkSpec; +import org.jclouds.virtualbox.domain.StorageController; +import org.jclouds.virtualbox.domain.VmSpec; +import org.jclouds.virtualbox.predicates.SshResponds; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; import org.virtualbox_4_1.CleanupMode; import org.virtualbox_4_1.IMachine; +import org.virtualbox_4_1.IProgress; +import org.virtualbox_4_1.ISession; +import org.virtualbox_4_1.LockType; import org.virtualbox_4_1.StorageBus; -import javax.annotation.Nullable; -import java.util.Map; -import java.util.Set; - -import static com.google.common.base.Predicates.equalTo; -import static com.google.common.collect.Iterables.any; -import static com.google.common.collect.Iterables.transform; -import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_IMAGE_PREFIX; -import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_INSTALLATION_KEY_SEQUENCE; -import static org.testng.Assert.assertTrue; +import com.google.common.base.CaseFormat; +import com.google.common.base.Function; +import com.google.common.base.Predicate; +import com.google.common.base.Splitter; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Iterables; +import com.google.inject.Guice; +import com.google.inject.Injector; /** * @author Andrea Turli, Mattias Holmqvist @@ -61,7 +80,12 @@ public class CreateAndInstallVmLiveTest extends BaseVirtualBoxClientLiveTest { .createInjector(new GsonModule()).getInstance(Json.class)); private VmSpec vmSpecification; + private MasterSpec masterSpec; + private Injector injector; + private Function sshClientForIMachine; + private Predicate sshResponds; + @Override @BeforeClass(groups = "live") public void setupClient() { @@ -76,28 +100,31 @@ public class CreateAndInstallVmLiveTest extends BaseVirtualBoxClientLiveTest { .attachISO(0, 0, operatingSystemIso) .attachHardDisk(hardDisk) .attachISO(1, 1, guestAdditionsIso).build(); - vmSpecification = VmSpec.builder().id("jclouds-image-create-and-install-vm-test").name(vmName).memoryMB(512).osTypeId("") + vmSpecification = VmSpec.builder().id(vmName).name(vmName).memoryMB(512).osTypeId("") .controller(ideController) .forceOverwrite(true) .cleanUpMode(CleanupMode.Full).build(); - } - - public void testCreateImageMachineFromIso() throws Exception { - Injector injector = context.utils().injector(); + + injector = context.utils().injector(); Function configProperties = injector .getInstance(ValueOfConfigurationKeyOrNull.class); - MasterSpec masterSpec = MasterSpec.builder().vm(vmSpecification) - .iso(IsoSpec.builder() - .sourcePath(operatingSystemIso) - .installationScript(configProperties - .apply(VIRTUALBOX_INSTALLATION_KEY_SEQUENCE) - .replace("HOSTNAME", vmSpecification.getVmName())) - .build()) - .network(NetworkSpec.builder() - .natNetworkAdapter(0, NatAdapter.builder().tcpRedirectRule("127.0.0.1", 2222, "", 22).build()) - .build()).build(); - IMachine imageMachine = injector.getInstance(CreateAndInstallVm.class).apply(masterSpec); + masterSpec = MasterSpec.builder().vm(vmSpecification) + .iso(IsoSpec.builder() + .sourcePath(operatingSystemIso) + .installationScript(configProperties + .apply(VIRTUALBOX_INSTALLATION_KEY_SEQUENCE) + .replace("HOSTNAME", vmSpecification.getVmName())) + .build()) + .network(NetworkSpec.builder() + .natNetworkAdapter(0, NatAdapter.builder().tcpRedirectRule("127.0.0.1", 2222, "", 22).build()) + .build()).build(); + + undoVm(vmSpecification); + } + + public void testCreateImageMachineFromIso() throws Exception { + IMachine imageMachine = getVmWithGuestAdditionsInstalled(); IMachineToImage iMachineToImage = new IMachineToImage(manager, map); Image newImage = iMachineToImage.apply(imageMachine); @@ -107,6 +134,33 @@ public class CreateAndInstallVmLiveTest extends BaseVirtualBoxClientLiveTest { Iterable imageIds = transform(images, extractId()); assertTrue(any(imageIds, equalTo(newImage.getId()))); } + + @Test + public void testGuestAdditionsAreInstalled() throws Exception { + try { + IMachine machine = getVmWithGuestAdditionsInstalled(); + + machineUtils.applyForMachine(machine.getName(), new LaunchMachineIfNotAlreadyRunning(manager.get(), ExecutionType.GUI, "")); + sshClientForIMachine = injector.getInstance(IMachineToSshClient.class); + SshClient client = sshClientForIMachine.apply(machine); + + sshResponds = injector.getInstance(SshResponds.class); + checkState(sshResponds.apply(client), "timed out waiting for guest %s to be accessible via ssh", machine.getName()); + + assertTrue(machineUtils.lockSessionOnMachineAndApply(machine.getName(), LockType.Shared, new Function() { + @Override + public Boolean apply(ISession session) { + String vboxVersion = Iterables.get(Splitter.on('r').split(context.getProviderSpecificContext().getBuildVersion()), 0); + return session.getMachine().getGuestPropertyValue("/VirtualBox/GuestAdd/Version").equals(vboxVersion); + } + })); + } finally { + for (VmSpec spec : ImmutableSet.of( + vmSpecification)) { + ensureMachineHasPowerDown(spec.getVmName()); + } + } + } private Function extractId() { return new Function() { @@ -118,10 +172,37 @@ public class CreateAndInstallVmLiveTest extends BaseVirtualBoxClientLiveTest { }; } + private IMachine getVmWithGuestAdditionsInstalled() { + try { + Injector injector = context.utils().injector(); + return injector.getInstance( + CreateAndInstallVm.class).apply( + masterSpec); + } catch (IllegalStateException e) { + // already created + return manager.get().getVBox() + .findMachine(masterSpec.getVmSpec().getVmId()); + } + } + + private void ensureMachineHasPowerDown(String vmName) { + machineUtils.lockSessionOnMachineAndApply(vmName, LockType.Shared, new Function() { + @Override + public Void apply(ISession session) { + IProgress powerDownProgress = session.getConsole().powerDown(); + powerDownProgress.waitForCompletion(-1); + return null; + } + }); + } + @Override @AfterClass(groups = "live") protected void tearDown() throws Exception { - undoVm(vmSpecification); + for (VmSpec spec : ImmutableSet.of( + vmSpecification)) { + undoVm(spec); + } super.tearDown(); } } diff --git a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/predicates/IMachinePredicatesLiveTest.java b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/predicates/IMachinePredicatesLiveTest.java index 085f225a9d..00d2196579 100644 --- a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/predicates/IMachinePredicatesLiveTest.java +++ b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/predicates/IMachinePredicatesLiveTest.java @@ -96,17 +96,6 @@ public class IMachinePredicatesLiveTest extends BaseVirtualBoxClientLiveTest { assertTrue(isLinkedClone().apply(clone)); } - /* - * public void testFullClone() { IMachine master = - * context.utils().injector(). - * getInstance(CreateAndRegisterMachineFromIsoIfNotAlreadyExists.class) - * .apply(masterSpec); IMachine clone = new - * CloneAndRegisterMachineFromIMachineIfNotAlreadyExists(manager, workingDir, - * cloneSpec, !IS_LINKED_CLONE).apply(master); - * - * assertFalse(new IsLinkedClone(manager).apply(clone)); } - */ - @BeforeMethod @AfterMethod void cleanUpVms() { diff --git a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/statements/GuestAdditionsInstaller.java b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/statements/GuestAdditionsInstaller.java index 77e37c309c..e66f2677f5 100644 --- a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/statements/GuestAdditionsInstaller.java +++ b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/statements/GuestAdditionsInstaller.java @@ -1,23 +1,16 @@ package org.jclouds.virtualbox.statements; -import static com.google.common.base.Preconditions.checkNotNull; -import static org.jclouds.compute.options.RunScriptOptions.Builder.runAsRoot; - -import java.util.concurrent.ExecutionException; - import javax.annotation.Resource; import javax.inject.Named; import javax.inject.Singleton; import org.jclouds.compute.ComputeServiceContext; -import org.jclouds.compute.RunScriptData; import org.jclouds.compute.callables.RunScriptOnNode.Factory; import org.jclouds.compute.domain.ExecResponse; import org.jclouds.compute.domain.NodeMetadata; +import org.jclouds.compute.options.RunScriptOptions; import org.jclouds.compute.reference.ComputeServiceConstants; import org.jclouds.logging.Logger; -import org.jclouds.scriptbuilder.domain.StatementList; -import org.jclouds.scriptbuilder.domain.Statements; import org.jclouds.ssh.SshClient; import org.jclouds.virtualbox.domain.ExecutionType; import org.jclouds.virtualbox.functions.CreateAndRegisterMachineFromIsoIfNotAlreadyExists; @@ -30,7 +23,7 @@ import org.virtualbox_4_1.VirtualBoxManager; import com.google.common.base.Function; import com.google.common.base.Predicate; import com.google.common.base.Supplier; -import com.google.common.base.Throwables; +import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.inject.Inject; @@ -49,7 +42,6 @@ public class GuestAdditionsInstaller implements Function { // TODO remove this hardcoded value private String vboxVersion = "4.1.6"; - @Inject public GuestAdditionsInstaller(ComputeServiceContext context, Supplier manager, CreateAndRegisterMachineFromIsoIfNotAlreadyExists createAndRegisterMachineFromIsoIfNotAlreadyExists, @@ -67,26 +59,16 @@ public class GuestAdditionsInstaller implements Function { IMachine vm = manager.get().getVBox().findMachine(vmName); ensureMachineIsLaunched(vmName); - InstallGuestAdditions installGuestAdditions = new InstallGuestAdditions(vboxVersion); - StatementList statementList = new StatementList(Statements.exec(RunScriptData.aptInstallLazyUpgrade("curl")), - installGuestAdditions); - NodeMetadata vmMetadata = new IMachineToNodeMetadata().apply(vm); - ListenableFuture execFuture = context.getComputeService().submitScriptOnNode(vmMetadata.getId(), statementList, - runAsRoot(true).wrapInInitScript(false)); - try { - execFuture.get(); - } catch (InterruptedException e) { - Throwables.propagate(e); - } catch (ExecutionException e) { - Throwables.propagate(e); - } + ListenableFuture execFuture = context.getComputeService().submitScriptOnNode(vmMetadata.getId(), + new InstallGuestAdditions(vboxVersion), RunScriptOptions.NONE); + Futures.getUnchecked(execFuture); return vm; } private void ensureMachineIsLaunched(String vmName) { machineUtils.applyForMachine(vmName, new LaunchMachineIfNotAlreadyRunning(manager.get(), executionType, "")); } - + } \ No newline at end of file diff --git a/labs/virtualbox/src/test/resources/test_export_ip_address_from_vm_named.sh b/labs/virtualbox/src/test/resources/test_export_ip_address_from_vm_named.sh index ebfd770645..52fd3b904c 100644 --- a/labs/virtualbox/src/test/resources/test_export_ip_address_from_vm_named.sh +++ b/labs/virtualbox/src/test/resources/test_export_ip_address_from_vm_named.sh @@ -26,4 +26,4 @@ function exportIpAddressFromVmNamed { export PATH=/usr/ucb/bin:/bin:/sbin:/usr/bin:/usr/sbin exportIpAddressFromVmNamed $@ || exit 1 echo $FOUND_IP_ADDRESS -exit 0 +exit $? diff --git a/labs/virtualbox/src/test/resources/test_guest_additions_installer.sh b/labs/virtualbox/src/test/resources/test_guest_additions_installer.sh index 6d6e7bd1a8..493a1df018 100644 --- a/labs/virtualbox/src/test/resources/test_guest_additions_installer.sh +++ b/labs/virtualbox/src/test/resources/test_guest_additions_installer.sh @@ -1,26 +1,6 @@ -#!/bin/bash -set +u -shopt -s xpg_echo -shopt -s expand_aliases -unset PATH JAVA_HOME LD_LIBRARY_PATH -function abort { - echo "aborting: $@" 1>&2 - exit 1 -} -function installModuleAssistantIfNeeded { - unset OSNAME; - local OSNAME=`lsb_release -d -s | cut -d ' ' -f 1`; shift - if [ $OSNAME = 'Ubuntu' ] - then - echo "OS is Ubuntu" - apt-get -f -y -qq --force-yes install build-essential module-assistant; - m-a prepare -i - fi -} -export PATH=/usr/ucb/bin:/bin:/sbin:/usr/bin:/usr/sbin +setupPublicCurl || return 1 (mkdir -p /tmp/ && cd /tmp/ && [ ! -f VBoxGuestAdditions_4.1.6.iso ] && curl -q -s -S -L --connect-timeout 10 --max-time 600 --retry 20 -C - -X GET http://download.virtualbox.org/virtualbox/4.1.6/VBoxGuestAdditions_4.1.6.iso >VBoxGuestAdditions_4.1.6.iso) mount -o loop /tmp/VBoxGuestAdditions_4.1.6.iso /mnt -installModuleAssistantIfNeeded || exit 1 +installModuleAssistantIfNeeded || return 1 /mnt/VBoxLinuxAdditions.run umount /mnt -exit 0 diff --git a/labs/virtualbox/src/test/resources/test_guest_additions_installer_init.sh b/labs/virtualbox/src/test/resources/test_guest_additions_installer_init.sh new file mode 100644 index 0000000000..47c37dbe14 --- /dev/null +++ b/labs/virtualbox/src/test/resources/test_guest_additions_installer_init.sh @@ -0,0 +1,217 @@ +#!/bin/bash +set +u +shopt -s xpg_echo +shopt -s expand_aliases +unset PATH JAVA_HOME LD_LIBRARY_PATH +function abort { + echo "aborting: $@" 1>&2 + exit 1 +} +function default { + export INSTANCE_NAME="install_guest_additions" +export INSTANCE_HOME="/tmp/$INSTANCE_NAME" +export LOG_DIR="$INSTANCE_HOME" + return $? +} +function install_guest_additions { + return $? +} +function findPid { + unset FOUND_PID; + [ $# -eq 1 ] || { + abort "findPid requires a parameter of pattern to match" + return 1 + } + local PATTERN="$1"; shift + local _FOUND=`ps auxwww|grep "$PATTERN"|grep -v " $0"|grep -v grep|grep -v $$|awk '{print $2}'` + [ -n "$_FOUND" ] && { + export FOUND_PID=$_FOUND + return 0 + } || { + return 1 + } +} +function forget { + unset FOUND_PID; + [ $# -eq 3 ] || { + abort "forget requires parameters INSTANCE_NAME SCRIPT LOG_DIR" + return 1 + } + local INSTANCE_NAME="$1"; shift + local SCRIPT="$1"; shift + local LOG_DIR="$1"; shift + mkdir -p $LOG_DIR + findPid $INSTANCE_NAME + [ -n "$FOUND_PID" -a -f $LOG_DIR/stdout.log ] && { + echo $INSTANCE_NAME already running pid [$FOUND_PID] + return 1; + } || { + nohup $SCRIPT >$LOG_DIR/stdout.log 2>$LOG_DIR/stderr.log & + RETURN=$? + # this is generally followed by findPid, so we shouldn't exit + # immediately as the proc may not have registered in ps, yet + test $RETURN && sleep 1 + return $RETURN; + } +} +export PATH=/usr/ucb/bin:/bin:/sbin:/usr/bin:/usr/sbin +case $1 in +init) + default || exit 1 + install_guest_additions || exit 1 + mkdir -p $INSTANCE_HOME + + # create runscript header + cat > $INSTANCE_HOME/install_guest_additions.sh <<-'END_OF_JCLOUDS_SCRIPT' + #!/bin/bash + set +u + shopt -s xpg_echo + shopt -s expand_aliases + + PROMPT_COMMAND='echo -ne \"\033]0;install_guest_additions\007\"' + export PATH=/usr/ucb/bin:/bin:/sbin:/usr/bin:/usr/sbin + + export INSTANCE_NAME='install_guest_additions' +END_OF_JCLOUDS_SCRIPT + cat >> $INSTANCE_HOME/install_guest_additions.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/install_guest_additions.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 +} +function installModuleAssistantIfNeeded { + unset OSNAME; + local OSNAME=`lsb_release -d -s | cut -d ' ' -f 1`; shift + if [ $OSNAME = 'Ubuntu' ] + then + echo "OS is Ubuntu" + apt-get -f -y -qq --force-yes install build-essential module-assistant; + m-a prepare -i + fi +} + +END_OF_JCLOUDS_SCRIPT + + # add desired commands from the user + cat >> $INSTANCE_HOME/install_guest_additions.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 + + (mkdir -p /tmp/ && cd /tmp/ && [ ! -f VBoxGuestAdditions_4.1.6.iso ] && curl -q -s -S -L --connect-timeout 10 --max-time 600 --retry 20 -C - -X GET http://download.virtualbox.org/virtualbox/4.1.6/VBoxGuestAdditions_4.1.6.iso >VBoxGuestAdditions_4.1.6.iso) + + mount -o loop /tmp/VBoxGuestAdditions_4.1.6.iso /mnt + + installModuleAssistantIfNeeded || exit 1 + + /mnt/VBoxLinuxAdditions.run + + umount /mnt + +END_OF_JCLOUDS_SCRIPT + + # add runscript footer + cat >> $INSTANCE_HOME/install_guest_additions.sh <<-'END_OF_JCLOUDS_SCRIPT' + exit $? + +END_OF_JCLOUDS_SCRIPT + + chmod u+x $INSTANCE_HOME/install_guest_additions.sh + ;; +status) + default || exit 1 + findPid $INSTANCE_NAME || exit 1 + echo [$FOUND_PID] + ;; +stop) + default || exit 1 + findPid $INSTANCE_NAME || exit 1 + [ -n "$FOUND_PID" ] && { + echo stopping $FOUND_PID + kill -9 $FOUND_PID + } + ;; +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 + ;; +tailerr) + default || exit 1 + tail $LOG_DIR/stderr.log + ;; +run) + default || exit 1 + $INSTANCE_HOME/$INSTANCE_NAME.sh + ;; +esac +exit $? diff --git a/loadbalancer/pom.xml b/loadbalancer/pom.xml index 59a3bec2c9..8801b175e1 100644 --- a/loadbalancer/pom.xml +++ b/loadbalancer/pom.xml @@ -89,8 +89,8 @@ ${project.artifactId} - org.jclouds.loadbalancer.*;version="${project.version}" - org.jclouds.*;version="${project.version}",* + org.jclouds.loadbalancer*;version="${project.version}" + org.jclouds*;version="${project.version}",* jclouds-core;bundle-version="[1.3,2)" diff --git a/providers/aws-cloudwatch/pom.xml b/providers/aws-cloudwatch/pom.xml index 531faecb93..d341f23f99 100644 --- a/providers/aws-cloudwatch/pom.xml +++ b/providers/aws-cloudwatch/pom.xml @@ -115,8 +115,8 @@ ${project.artifactId} - org.jclouds.aws.cloudwatch.*;version="${project.version}" - org.jclouds.*;version="${project.version}",* + org.jclouds.aws.cloudwatch*;version="${project.version}" + org.jclouds*;version="${project.version}",* diff --git a/providers/aws-ec2/pom.xml b/providers/aws-ec2/pom.xml index a5faa44953..8884235746 100644 --- a/providers/aws-ec2/pom.xml +++ b/providers/aws-ec2/pom.xml @@ -139,13 +139,13 @@ ${project.artifactId} - org.jclouds.aws.ec2.*;version="${project.version}" + org.jclouds.aws.ec2*;version="${project.version}" org.jclouds.compute.internal;version="${project.version}", org.jclouds.rest.internal;version="${project.version}", org.jclouds.aws;version="${project.version}", - org.jclouds.aws.*;version="${project.version}", - org.jclouds.*;version="${project.version}", + org.jclouds.aws*;version="${project.version}", + org.jclouds*;version="${project.version}", * diff --git a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/compute/AWSEC2ComputeService.java b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/compute/AWSEC2ComputeService.java index d8c3ac4dbe..d54c7ed19d 100644 --- a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/compute/AWSEC2ComputeService.java +++ b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/compute/AWSEC2ComputeService.java @@ -25,9 +25,9 @@ import static org.jclouds.aws.ec2.reference.AWSEC2Constants.PROPERTY_EC2_GENERAT import java.util.Map; import java.util.Set; -import java.util.Map.Entry; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ExecutorService; +import java.util.concurrent.atomic.AtomicReference; import javax.inject.Inject; import javax.inject.Named; @@ -100,9 +100,9 @@ public class AWSEC2ComputeService extends EC2ComputeService { DestroyNodeStrategy destroyNodeStrategy, ResumeNodeStrategy startNodeStrategy, SuspendNodeStrategy stopNodeStrategy, Provider templateBuilderProvider, Provider templateOptionsProvider, - @Named("NODE_RUNNING") Predicate nodeRunning, - @Named("NODE_TERMINATED") Predicate nodeTerminated, - @Named("NODE_SUSPENDED") Predicate nodeSuspended, + @Named("NODE_RUNNING") Predicate> nodeRunning, + @Named("NODE_TERMINATED") Predicate> nodeTerminated, + @Named("NODE_SUSPENDED") Predicate> nodeSuspended, InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory, RunScriptOnNode.Factory runScriptOnNodeFactory, InitAdminAccess initAdminAccess, PersistNodeCredentials persistNodeCredentials, Timeouts timeouts, diff --git a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/compute/strategy/AWSEC2CreateNodesInGroupThenAddToSet.java b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/compute/strategy/AWSEC2CreateNodesInGroupThenAddToSet.java index 260a1643ec..04f83f6a19 100644 --- a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/compute/strategy/AWSEC2CreateNodesInGroupThenAddToSet.java +++ b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/compute/strategy/AWSEC2CreateNodesInGroupThenAddToSet.java @@ -23,6 +23,7 @@ import static com.google.common.collect.Iterables.transform; import static org.jclouds.aws.ec2.reference.AWSEC2Constants.PROPERTY_EC2_GENERATE_INSTANCE_NAMES; import java.util.Map; +import java.util.concurrent.atomic.AtomicReference; import javax.annotation.Resource; import javax.inject.Inject; @@ -79,7 +80,7 @@ public class AWSEC2CreateNodesInGroupThenAddToSet extends EC2CreateNodesInGroupT protected AWSEC2CreateNodesInGroupThenAddToSet( AWSEC2Client client, @Named("ELASTICIP") LoadingCache elasticIpCache, - @Named("NODE_RUNNING") Predicate nodeRunning, + @Named("NODE_RUNNING") Predicate> nodeRunning, AWSEC2AsyncClient aclient, @Named(PROPERTY_EC2_GENERATE_INSTANCE_NAMES) boolean generateInstanceNames, Provider templateBuilderProvider, diff --git a/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/services/PlacementGroupClientLiveTest.java b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/services/PlacementGroupClientLiveTest.java index 96f40025d6..f5cbb645d1 100644 --- a/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/services/PlacementGroupClientLiveTest.java +++ b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/services/PlacementGroupClientLiveTest.java @@ -21,7 +21,6 @@ package org.jclouds.aws.ec2.services; import static com.google.common.collect.Iterables.getOnlyElement; import static com.google.common.collect.Lists.newArrayList; import static com.google.common.collect.Sets.newTreeSet; -import static org.jclouds.compute.ComputeTestUtils.buildScript; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNotNull; @@ -50,6 +49,7 @@ import org.jclouds.ec2.domain.InstanceType; import org.jclouds.logging.log4j.config.Log4JLoggingModule; import org.jclouds.predicates.RetryablePredicate; import org.jclouds.scriptbuilder.domain.Statements; +import org.jclouds.scriptbuilder.statements.java.InstallJDK; import org.jclouds.scriptbuilder.statements.login.AdminAccess; import org.jclouds.sshj.config.SshjSshClientModule; import org.testng.annotations.AfterTest; @@ -149,8 +149,7 @@ public class PlacementGroupClientLiveTest extends BaseVersionedServiceLiveTest { assertEquals(template.getImage().getUserMetadata().get("hypervisor"), "xen"); template.getOptions().runScript( - Statements.newStatementList(AdminAccess.standard(), - buildScript(template.getImage().getOperatingSystem()))); + Statements.newStatementList(AdminAccess.standard(), InstallJDK.fromURL())); String group = PREFIX + "cccluster"; context.getComputeService().destroyNodesMatching(NodePredicates.inGroup(group)); diff --git a/providers/aws-s3/pom.xml b/providers/aws-s3/pom.xml index 921b0ed791..504b13d31f 100644 --- a/providers/aws-s3/pom.xml +++ b/providers/aws-s3/pom.xml @@ -150,9 +150,9 @@ ${project.artifactId} - org.jclouds.aws.s3.*;version="${project.version}" + org.jclouds.aws.s3*;version="${project.version}" - org.jclouds.*;version="${project.version}", + org.jclouds*;version="${project.version}", org.jclouds.http.options;version="${project.version}", * diff --git a/providers/azureblob/pom.xml b/providers/azureblob/pom.xml index 61560e106f..d06fd0a561 100644 --- a/providers/azureblob/pom.xml +++ b/providers/azureblob/pom.xml @@ -120,8 +120,8 @@ ${project.artifactId} - org.jclouds.azureblob.*;version="${project.version}" - org.jclouds.*;version="${project.version}",* + org.jclouds.azureblob*;version="${project.version}" + org.jclouds*;version="${project.version}",* diff --git a/providers/bluelock-vcloud-zone01/pom.xml b/providers/bluelock-vcloud-zone01/pom.xml index ee2994f228..965c6148c8 100644 --- a/providers/bluelock-vcloud-zone01/pom.xml +++ b/providers/bluelock-vcloud-zone01/pom.xml @@ -128,11 +128,11 @@ ${project.artifactId} - org.jclouds.bluelock.vcloud.zone01.*;version="${project.version}" + org.jclouds.bluelock.vcloud.zone01*;version="${project.version}" org.jclouds.compute.internal;version="${project.version}", org.jclouds.rest.internal;version="${project.version}", - org.jclouds.*;version="${project.version}", + org.jclouds*;version="${project.version}", * diff --git a/providers/cloudfiles-uk/pom.xml b/providers/cloudfiles-uk/pom.xml index cb471d2b54..bd14deabdf 100644 --- a/providers/cloudfiles-uk/pom.xml +++ b/providers/cloudfiles-uk/pom.xml @@ -135,8 +135,8 @@ ${project.artifactId} - org.jclouds.rackspace.cloudfiles.*;version="${project.version}" - org.jclouds.*;version="${project.version}",* + org.jclouds.rackspace.cloudfiles*;version="${project.version}" + org.jclouds*;version="${project.version}",* diff --git a/providers/cloudfiles-us/pom.xml b/providers/cloudfiles-us/pom.xml index f16ba6d3ac..5f060dcd16 100644 --- a/providers/cloudfiles-us/pom.xml +++ b/providers/cloudfiles-us/pom.xml @@ -135,8 +135,8 @@ ${project.artifactId} - org.jclouds.rackspace.cloudfiles.*;version="${project.version}" - org.jclouds.*;version="${project.version}",* + org.jclouds.rackspace.cloudfiles*;version="${project.version}" + org.jclouds*;version="${project.version}",* diff --git a/providers/cloudloadbalancers-uk/pom.xml b/providers/cloudloadbalancers-uk/pom.xml index 45f6da92a5..3bf8bed256 100644 --- a/providers/cloudloadbalancers-uk/pom.xml +++ b/providers/cloudloadbalancers-uk/pom.xml @@ -132,8 +132,8 @@ ${project.artifactId} - org.jclouds.rackspace.cloudloadbalancers.*;version="${project.version}" - org.jclouds.*;version="${project.version}",* + org.jclouds.rackspace.cloudloadbalancers*;version="${project.version}" + org.jclouds*;version="${project.version}",* diff --git a/providers/cloudloadbalancers-us/pom.xml b/providers/cloudloadbalancers-us/pom.xml index 49ae67e38c..ddc4d94598 100644 --- a/providers/cloudloadbalancers-us/pom.xml +++ b/providers/cloudloadbalancers-us/pom.xml @@ -132,8 +132,8 @@ ${project.artifactId} - org.jclouds.rackspace.cloudloadbalancers.*;version="${project.version}" - org.jclouds.*;version="${project.version}",* + org.jclouds.rackspace.cloudloadbalancers*;version="${project.version}" + org.jclouds*;version="${project.version}",* diff --git a/providers/cloudonestorage/pom.xml b/providers/cloudonestorage/pom.xml index d03e38f2f3..73ff163f5a 100644 --- a/providers/cloudonestorage/pom.xml +++ b/providers/cloudonestorage/pom.xml @@ -128,8 +128,8 @@ ${project.artifactId} - org.jclouds.cloudonestorage.*;version="${project.version}" - org.jclouds.*;version="${project.version}",* + org.jclouds.cloudonestorage*;version="${project.version}" + org.jclouds*;version="${project.version}",* diff --git a/providers/cloudservers-uk/pom.xml b/providers/cloudservers-uk/pom.xml index 8cba92968b..2d321b589e 100644 --- a/providers/cloudservers-uk/pom.xml +++ b/providers/cloudservers-uk/pom.xml @@ -133,11 +133,11 @@ ${project.artifactId} - org.jclouds.rackspace.cloudservers.*;version="${project.version}" + org.jclouds.rackspace.cloudservers*;version="${project.version}" org.jclouds.compute.internal;version="${project.version}", org.jclouds.rest.internal;version="${project.version}", - org.jclouds.*;version="${project.version}", + org.jclouds*;version="${project.version}", * diff --git a/providers/cloudservers-us/pom.xml b/providers/cloudservers-us/pom.xml index 190fa47861..30d1d29751 100644 --- a/providers/cloudservers-us/pom.xml +++ b/providers/cloudservers-us/pom.xml @@ -134,11 +134,11 @@ ${project.artifactId} - org.jclouds.rackspace.cloudservers.*;version="${project.version}" + org.jclouds.rackspace.cloudservers*;version="${project.version}" org.jclouds.compute.internal;version="${project.version}", org.jclouds.rest.internal;version="${project.version}", - org.jclouds.*;version="${project.version}", + org.jclouds*;version="${project.version}", * diff --git a/providers/cloudsigma-lvs/pom.xml b/providers/cloudsigma-lvs/pom.xml index 012f017fb5..79a99bf03e 100644 --- a/providers/cloudsigma-lvs/pom.xml +++ b/providers/cloudsigma-lvs/pom.xml @@ -128,11 +128,11 @@ ${project.artifactId} - org.jclouds.cloudsigma.*;version="${project.version}" + org.jclouds.cloudsigma*;version="${project.version}" org.jclouds.compute.internal;version="${project.version}", org.jclouds.rest.internal;version="${project.version}", - org.jclouds.*;version="${project.version}", + org.jclouds*;version="${project.version}", * diff --git a/providers/cloudsigma-zrh/pom.xml b/providers/cloudsigma-zrh/pom.xml index c461de8051..b055df3123 100644 --- a/providers/cloudsigma-zrh/pom.xml +++ b/providers/cloudsigma-zrh/pom.xml @@ -128,11 +128,11 @@ ${project.artifactId} - org.jclouds.cloudsigma.*;version="${project.version}" + org.jclouds.cloudsigma*;version="${project.version}" org.jclouds.compute.internal;version="${project.version}", org.jclouds.rest.internal;version="${project.version}", - org.jclouds.*;version="${project.version}", + org.jclouds*;version="${project.version}", * diff --git a/providers/elastichosts-lax-p/pom.xml b/providers/elastichosts-lax-p/pom.xml index 7f1ecff605..250a691183 100644 --- a/providers/elastichosts-lax-p/pom.xml +++ b/providers/elastichosts-lax-p/pom.xml @@ -124,11 +124,11 @@ ${project.artifactId} - org.jclouds.elastichosts.*;version="${project.version}" + org.jclouds.elastichosts*;version="${project.version}" org.jclouds.compute.internal;version="${project.version}", org.jclouds.rest.internal;version="${project.version}", - org.jclouds.*;version="${project.version}", + org.jclouds*;version="${project.version}", * diff --git a/providers/elastichosts-lon-b/pom.xml b/providers/elastichosts-lon-b/pom.xml index a0443cf6f8..20a2e6a392 100644 --- a/providers/elastichosts-lon-b/pom.xml +++ b/providers/elastichosts-lon-b/pom.xml @@ -124,11 +124,11 @@ ${project.artifactId} - org.jclouds.elastichosts.*;version="${project.version}" + org.jclouds.elastichosts*;version="${project.version}" org.jclouds.compute.internal;version="${project.version}", org.jclouds.rest.internal;version="${project.version}", - org.jclouds.*;version="${project.version}", + org.jclouds*;version="${project.version}", * diff --git a/providers/elastichosts-lon-p/pom.xml b/providers/elastichosts-lon-p/pom.xml index a944fe6e75..95e8ff17fc 100644 --- a/providers/elastichosts-lon-p/pom.xml +++ b/providers/elastichosts-lon-p/pom.xml @@ -124,11 +124,11 @@ ${project.artifactId} - org.jclouds.elastichosts.*;version="${project.version}" + org.jclouds.elastichosts*;version="${project.version}" org.jclouds.compute.internal;version="${project.version}", org.jclouds.rest.internal;version="${project.version}", - org.jclouds.*;version="${project.version}", + org.jclouds*;version="${project.version}", * diff --git a/providers/elastichosts-sat-p/pom.xml b/providers/elastichosts-sat-p/pom.xml index fd5df6adc3..c3ba01d40e 100644 --- a/providers/elastichosts-sat-p/pom.xml +++ b/providers/elastichosts-sat-p/pom.xml @@ -124,11 +124,11 @@ ${project.artifactId} - org.jclouds.elastichosts.*;version="${project.version}" + org.jclouds.elastichosts*;version="${project.version}" org.jclouds.compute.internal;version="${project.version}", org.jclouds.rest.internal;version="${project.version}", - org.jclouds.*;version="${project.version}", + org.jclouds*;version="${project.version}", * diff --git a/providers/elastichosts-tor-p/pom.xml b/providers/elastichosts-tor-p/pom.xml index 15bb9e7134..02eb2abebc 100644 --- a/providers/elastichosts-tor-p/pom.xml +++ b/providers/elastichosts-tor-p/pom.xml @@ -124,11 +124,11 @@ ${project.artifactId} - org.jclouds.elastichosts.*;version="${project.version}" + org.jclouds.elastichosts*;version="${project.version}" org.jclouds.compute.internal;version="${project.version}", org.jclouds.rest.internal;version="${project.version}", - org.jclouds.*;version="${project.version}", + org.jclouds*;version="${project.version}", * diff --git a/providers/eucalyptus-partnercloud-ec2/pom.xml b/providers/eucalyptus-partnercloud-ec2/pom.xml index fa8812517e..214e2b4d1d 100644 --- a/providers/eucalyptus-partnercloud-ec2/pom.xml +++ b/providers/eucalyptus-partnercloud-ec2/pom.xml @@ -140,11 +140,11 @@ ${project.artifactId} - org.jclouds.epc.*;version="${project.version}" + org.jclouds.epc*;version="${project.version}" org.jclouds.compute.internal;version="${project.version}", org.jclouds.rest.internal;version="${project.version}", - org.jclouds.*;version="${project.version}", + org.jclouds*;version="${project.version}", * diff --git a/providers/eucalyptus-partnercloud-s3/pom.xml b/providers/eucalyptus-partnercloud-s3/pom.xml index 86c1727b93..0fa8f0d78c 100644 --- a/providers/eucalyptus-partnercloud-s3/pom.xml +++ b/providers/eucalyptus-partnercloud-s3/pom.xml @@ -137,9 +137,9 @@ ${project.artifactId} - org.jclouds.epc.*;version="${project.version}" + org.jclouds.epc*;version="${project.version}" - org.jclouds.*;version="${project.version}", + org.jclouds*;version="${project.version}", * diff --git a/providers/go2cloud-jhb1/pom.xml b/providers/go2cloud-jhb1/pom.xml index a4937d2b14..87063ab955 100644 --- a/providers/go2cloud-jhb1/pom.xml +++ b/providers/go2cloud-jhb1/pom.xml @@ -124,11 +124,11 @@ ${project.artifactId} - org.jclouds.go2cloud.*;version="${project.version}" + org.jclouds.go2cloud*;version="${project.version}" org.jclouds.compute.internal;version="${project.version}", org.jclouds.rest.internal;version="${project.version}", - org.jclouds.*;version="${project.version}", + org.jclouds*;version="${project.version}", * diff --git a/providers/gogrid/pom.xml b/providers/gogrid/pom.xml index a7cfa2fa6d..23a0921d2d 100644 --- a/providers/gogrid/pom.xml +++ b/providers/gogrid/pom.xml @@ -117,11 +117,11 @@ ${project.artifactId} - org.jclouds.gogrid.*;version="${project.version}" + org.jclouds.gogrid*;version="${project.version}" org.jclouds.compute.internal;version="${project.version}", org.jclouds.rest.internal;version="${project.version}", - org.jclouds.*;version="${project.version}", + org.jclouds*;version="${project.version}", * diff --git a/providers/gogrid/src/main/java/org/jclouds/gogrid/compute/GoGridComputeService.java b/providers/gogrid/src/main/java/org/jclouds/gogrid/compute/GoGridComputeService.java index 679f840634..b03aadf71d 100644 --- a/providers/gogrid/src/main/java/org/jclouds/gogrid/compute/GoGridComputeService.java +++ b/providers/gogrid/src/main/java/org/jclouds/gogrid/compute/GoGridComputeService.java @@ -21,6 +21,7 @@ package org.jclouds.gogrid.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; @@ -68,9 +69,9 @@ public class GoGridComputeService extends BaseComputeService { RebootNodeStrategy rebootNodeStrategy, DestroyNodeStrategy destroyNodeStrategy, ResumeNodeStrategy resumeNodeStrategy, SuspendNodeStrategy suspendNodeStrategy, Provider templateBuilderProvider, Provider templateOptionsProvider, - @Named("NODE_RUNNING") Predicate nodeRunning, - @Named("NODE_TERMINATED") Predicate nodeTerminated, - @Named("NODE_SUSPENDED") Predicate nodeSuspended, + @Named("NODE_RUNNING") Predicate> nodeRunning, + @Named("NODE_TERMINATED") Predicate> nodeTerminated, + @Named("NODE_SUSPENDED") Predicate> nodeSuspended, InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory, InitAdminAccess initAdminAccess, RunScriptOnNode.Factory runScriptOnNodeFactory, PersistNodeCredentials persistNodeCredentials, Timeouts timeouts, @Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor) { diff --git a/providers/greenhousedata-element-vcloud/pom.xml b/providers/greenhousedata-element-vcloud/pom.xml index 9bf65baf73..9c1e60df64 100644 --- a/providers/greenhousedata-element-vcloud/pom.xml +++ b/providers/greenhousedata-element-vcloud/pom.xml @@ -128,11 +128,11 @@ ${project.artifactId} - org.jclouds.greenhousedata.element.vcloud.*;version="${project.version}" + org.jclouds.greenhousedata.element.vcloud*;version="${project.version}" org.jclouds.compute.internal;version="${project.version}", org.jclouds.rest.internal;version="${project.version}", - org.jclouds.*;version="${project.version}", + org.jclouds*;version="${project.version}", * diff --git a/providers/hpcloud-objectstorage-lvs/pom.xml b/providers/hpcloud-objectstorage-lvs/pom.xml index 41d30d9b33..a66078be26 100644 --- a/providers/hpcloud-objectstorage-lvs/pom.xml +++ b/providers/hpcloud-objectstorage-lvs/pom.xml @@ -157,8 +157,8 @@ ${project.artifactId} - org.jclouds.hpcloud.objectstorage.lvs.*;version="${project.version}" - org.jclouds.*;version="${project.version}",* + org.jclouds.hpcloud.objectstorage.lvs*;version="${project.version}" + org.jclouds*;version="${project.version}",* diff --git a/providers/ninefold-compute/pom.xml b/providers/ninefold-compute/pom.xml index 6fe641deed..043a3b345a 100644 --- a/providers/ninefold-compute/pom.xml +++ b/providers/ninefold-compute/pom.xml @@ -129,11 +129,11 @@ ${project.artifactId} - org.jclouds.ninefold.compute.*;version="${project.version}" + org.jclouds.ninefold.compute*;version="${project.version}" org.jclouds.compute.internal;version="${project.version}", org.jclouds.rest.internal;version="${project.version}", - org.jclouds.*;version="${project.version}", + org.jclouds*;version="${project.version}", * diff --git a/providers/ninefold-storage/pom.xml b/providers/ninefold-storage/pom.xml index bad90f2152..746355dd38 100644 --- a/providers/ninefold-storage/pom.xml +++ b/providers/ninefold-storage/pom.xml @@ -127,8 +127,8 @@ ${project.artifactId} - org.jclouds.ninefold.storage.*;version="${project.version}" - org.jclouds.*;version="${project.version}",* + org.jclouds.ninefold.storage*;version="${project.version}" + org.jclouds*;version="${project.version}",* diff --git a/providers/openhosting-east1/pom.xml b/providers/openhosting-east1/pom.xml index ba526f68bb..2f4fc2d066 100644 --- a/providers/openhosting-east1/pom.xml +++ b/providers/openhosting-east1/pom.xml @@ -124,11 +124,11 @@ ${project.artifactId} - org.jclouds.openhosting.*;version="${project.version}" + org.jclouds.openhosting*;version="${project.version}" org.jclouds.compute.internal;version="${project.version}", org.jclouds.rest.internal;version="${project.version}", - org.jclouds.*;version="${project.version}", + org.jclouds*;version="${project.version}", * diff --git a/providers/rimuhosting/pom.xml b/providers/rimuhosting/pom.xml index 0a449a17d1..08fa382bf3 100644 --- a/providers/rimuhosting/pom.xml +++ b/providers/rimuhosting/pom.xml @@ -124,11 +124,11 @@ ${project.artifactId} - org.jclouds.rimuhosting.miro.*;version="${project.version}" + org.jclouds.rimuhosting.miro*;version="${project.version}" org.jclouds.compute.internal;version="${project.version}", org.jclouds.rest.internal;version="${project.version}", - org.jclouds.*;version="${project.version}", + org.jclouds*;version="${project.version}", * diff --git a/providers/savvis-symphonyvpdc/pom.xml b/providers/savvis-symphonyvpdc/pom.xml index e385be2568..7d1fe0c925 100644 --- a/providers/savvis-symphonyvpdc/pom.xml +++ b/providers/savvis-symphonyvpdc/pom.xml @@ -141,11 +141,11 @@ ${project.artifactId} - org.jclouds.savvis.vpdc.*;version="${project.version}" + org.jclouds.savvis.vpdc*;version="${project.version}" org.jclouds.compute.internal;version="${project.version}", org.jclouds.rest.internal;version="${project.version}", - org.jclouds.*;version="${project.version}", + org.jclouds*;version="${project.version}", * diff --git a/providers/serverlove-z1-man/pom.xml b/providers/serverlove-z1-man/pom.xml index 97759e9dea..9d70165979 100644 --- a/providers/serverlove-z1-man/pom.xml +++ b/providers/serverlove-z1-man/pom.xml @@ -124,11 +124,11 @@ ${project.artifactId} - org.jclouds.serverlove.*;version="${project.version}" + org.jclouds.serverlove*;version="${project.version}" org.jclouds.compute.internal;version="${project.version}", org.jclouds.rest.internal;version="${project.version}", - org.jclouds.*;version="${project.version}", + org.jclouds*;version="${project.version}", * diff --git a/providers/skalicloud-sdg-my/pom.xml b/providers/skalicloud-sdg-my/pom.xml index 2b4073bf76..5f824806d3 100644 --- a/providers/skalicloud-sdg-my/pom.xml +++ b/providers/skalicloud-sdg-my/pom.xml @@ -124,11 +124,11 @@ ${project.artifactId} - org.jclouds.skalicloud.*;version="${project.version}" + org.jclouds.skalicloud*;version="${project.version}" org.jclouds.compute.internal;version="${project.version}", org.jclouds.rest.internal;version="${project.version}", - org.jclouds.*;version="${project.version}", + org.jclouds*;version="${project.version}", * diff --git a/providers/slicehost/pom.xml b/providers/slicehost/pom.xml index 5367eb92ad..f1ae925b3c 100644 --- a/providers/slicehost/pom.xml +++ b/providers/slicehost/pom.xml @@ -116,11 +116,11 @@ ${project.artifactId} - org.jclouds.slicehost.*;version="${project.version}" + org.jclouds.slicehost*;version="${project.version}" org.jclouds.compute.internal;version="${project.version}", org.jclouds.rest.internal;version="${project.version}", - org.jclouds.*;version="${project.version}", + org.jclouds*;version="${project.version}", * diff --git a/providers/softlayer/pom.xml b/providers/softlayer/pom.xml index a3f686b0c8..d37ec00884 100644 --- a/providers/softlayer/pom.xml +++ b/providers/softlayer/pom.xml @@ -133,11 +133,11 @@ ${project.artifactId} - org.jclouds.softlayer.*;version="${project.version}" + org.jclouds.softlayer*;version="${project.version}" org.jclouds.compute.internal;version="${project.version}", org.jclouds.rest.internal;version="${project.version}", - org.jclouds.*;version="${project.version}", + org.jclouds*;version="${project.version}", * diff --git a/providers/stratogen-vcloud-mycloud/pom.xml b/providers/stratogen-vcloud-mycloud/pom.xml index 3b656e9ac3..f39e9ff056 100644 --- a/providers/stratogen-vcloud-mycloud/pom.xml +++ b/providers/stratogen-vcloud-mycloud/pom.xml @@ -128,11 +128,11 @@ ${project.artifactId} - org.jclouds.stratogen.vcloud.mycloud.*;version="${project.version}" + org.jclouds.stratogen.vcloud.mycloud*;version="${project.version}" org.jclouds.compute.internal;version="${project.version}", org.jclouds.rest.internal;version="${project.version}", - org.jclouds.*;version="${project.version}", + org.jclouds*;version="${project.version}", * diff --git a/providers/synaptic-storage/pom.xml b/providers/synaptic-storage/pom.xml index 7f0413761e..3bdfd71a8b 100644 --- a/providers/synaptic-storage/pom.xml +++ b/providers/synaptic-storage/pom.xml @@ -127,8 +127,8 @@ ${project.artifactId} - org.jclouds.synaptic.storage.*;version="${project.version}" - org.jclouds.*;version="${project.version}",* + org.jclouds.synaptic.storage*;version="${project.version}" + org.jclouds*;version="${project.version}",* diff --git a/providers/trmk-ecloud/pom.xml b/providers/trmk-ecloud/pom.xml index 4a0ec8a0af..c6682dd1af 100644 --- a/providers/trmk-ecloud/pom.xml +++ b/providers/trmk-ecloud/pom.xml @@ -127,11 +127,11 @@ ${project.artifactId} - org.jclouds.trmk.ecloud.*;version="${project.version}" + org.jclouds.trmk.ecloud*;version="${project.version}" org.jclouds.compute.internal;version="${project.version}", org.jclouds.rest.internal;version="${project.version}", - org.jclouds.*;version="${project.version}", + org.jclouds*;version="${project.version}", * diff --git a/providers/trmk-vcloudexpress/pom.xml b/providers/trmk-vcloudexpress/pom.xml index f00ef9eea7..66db21a08c 100644 --- a/providers/trmk-vcloudexpress/pom.xml +++ b/providers/trmk-vcloudexpress/pom.xml @@ -125,11 +125,11 @@ ${project.artifactId} - org.jclouds.trmk.ecloud.*;version="${project.version}" + org.jclouds.trmk.ecloud*;version="${project.version}" org.jclouds.compute.internal;version="${project.version}", org.jclouds.rest.internal;version="${project.version}", - org.jclouds.*;version="${project.version}", + org.jclouds*;version="${project.version}", * diff --git a/sandbox-apis/elb/pom.xml b/sandbox-apis/elb/pom.xml index 292faf0357..11362160b8 100644 --- a/sandbox-apis/elb/pom.xml +++ b/sandbox-apis/elb/pom.xml @@ -144,8 +144,8 @@ ${project.artifactId} - org.jclouds.elb.*;version="${project.version}" - org.jclouds.*;version="${project.version}",* + org.jclouds.elb*;version="${project.version}" + org.jclouds*;version="${project.version}",* diff --git a/sandbox-apis/libvirt/pom.xml b/sandbox-apis/libvirt/pom.xml index 549e568ab2..7f22ade9dc 100644 --- a/sandbox-apis/libvirt/pom.xml +++ b/sandbox-apis/libvirt/pom.xml @@ -150,8 +150,8 @@ ${project.artifactId} - org.jclouds.libvirt.*;version="${project.version}" - org.jclouds.*;version="${project.version}",* + org.jclouds.libvirt*;version="${project.version}" + org.jclouds*;version="${project.version}",* diff --git a/sandbox-apis/nirvanix/pom.xml b/sandbox-apis/nirvanix/pom.xml index 4e32e3aa93..925eb7832d 100644 --- a/sandbox-apis/nirvanix/pom.xml +++ b/sandbox-apis/nirvanix/pom.xml @@ -129,8 +129,8 @@ ${project.artifactId} - org.jclouds.nirvanix.sdn.*;version="${project.version}" - org.jclouds.*;version="${project.version}",* + org.jclouds.nirvanix.sdn*;version="${project.version}" + org.jclouds*;version="${project.version}",* diff --git a/sandbox-apis/pcs/pom.xml b/sandbox-apis/pcs/pom.xml index 2042adcd7b..93e715e4a1 100644 --- a/sandbox-apis/pcs/pom.xml +++ b/sandbox-apis/pcs/pom.xml @@ -129,8 +129,8 @@ ${project.artifactId} - org.jclouds.mezeo.pcs.*;version="${project.version}" - org.jclouds.*;version="${project.version}",* + org.jclouds.mezeo.pcs*;version="${project.version}" + org.jclouds*;version="${project.version}",* diff --git a/sandbox-apis/scality-rs2/pom.xml b/sandbox-apis/scality-rs2/pom.xml index 1ba133adde..4ecd6fcc6d 100644 --- a/sandbox-apis/scality-rs2/pom.xml +++ b/sandbox-apis/scality-rs2/pom.xml @@ -127,8 +127,8 @@ ${project.artifactId} - org.jclouds.scality.rs2.*;version="${project.version}" - org.jclouds.*;version="${project.version}",* + org.jclouds.scality.rs2*;version="${project.version}" + org.jclouds*;version="${project.version}",* diff --git a/sandbox-apis/simpledb/pom.xml b/sandbox-apis/simpledb/pom.xml index 98249402b8..f2eb35cca4 100644 --- a/sandbox-apis/simpledb/pom.xml +++ b/sandbox-apis/simpledb/pom.xml @@ -102,8 +102,8 @@ ${project.artifactId} - org.jclouds.simpledb.*;version="${project.version}" - org.jclouds.*;version="${project.version}",* + org.jclouds.simpledb*;version="${project.version}" + org.jclouds*;version="${project.version}",* diff --git a/sandbox-apis/sqs/pom.xml b/sandbox-apis/sqs/pom.xml index b3b68ee7ac..0f786b6ab8 100644 --- a/sandbox-apis/sqs/pom.xml +++ b/sandbox-apis/sqs/pom.xml @@ -102,8 +102,8 @@ ${project.artifactId} - org.jclouds.sqs.*;version="${project.version}" - org.jclouds.*;version="${project.version}",* + org.jclouds.sqs*;version="${project.version}" + org.jclouds*;version="${project.version}",* diff --git a/sandbox-drivers/asynchttpclient/pom.xml b/sandbox-drivers/asynchttpclient/pom.xml index 0df55732c0..ee0d487922 100644 --- a/sandbox-drivers/asynchttpclient/pom.xml +++ b/sandbox-drivers/asynchttpclient/pom.xml @@ -77,8 +77,8 @@ ${project.artifactId} - org.jclouds.http.ning.*;version="${project.version}" - org.jclouds.*;version="${project.version}",* + org.jclouds.http.ning*;version="${project.version}" + org.jclouds*;version="${project.version}",* diff --git a/sandbox-providers/aws-elb/pom.xml b/sandbox-providers/aws-elb/pom.xml index 471b6e6ced..0227cb482c 100644 --- a/sandbox-providers/aws-elb/pom.xml +++ b/sandbox-providers/aws-elb/pom.xml @@ -150,8 +150,8 @@ ${project.artifactId} - org.jclouds.aws.elb.*;version="${project.version}" - org.jclouds.*;version="${project.version}",* + org.jclouds.aws.elb*;version="${project.version}" + org.jclouds*;version="${project.version}",* diff --git a/sandbox-providers/aws-simpledb/pom.xml b/sandbox-providers/aws-simpledb/pom.xml index a0e9969dd0..5f3d512932 100644 --- a/sandbox-providers/aws-simpledb/pom.xml +++ b/sandbox-providers/aws-simpledb/pom.xml @@ -116,8 +116,8 @@ ${project.artifactId} - org.jclouds.aws.simpledb.*;version="${project.version}" - org.jclouds.*;version="${project.version}",* + org.jclouds.aws.simpledb*;version="${project.version}" + org.jclouds*;version="${project.version}",* diff --git a/sandbox-providers/azurequeue/pom.xml b/sandbox-providers/azurequeue/pom.xml index 94a5ced713..9ac7b86682 100644 --- a/sandbox-providers/azurequeue/pom.xml +++ b/sandbox-providers/azurequeue/pom.xml @@ -109,8 +109,8 @@ ${project.artifactId} - org.jclouds.azurequeue.*;version="${project.version}" - org.jclouds.*;version="${project.version}",* + org.jclouds.azurequeue*;version="${project.version}" + org.jclouds*;version="${project.version}",* diff --git a/sandbox-providers/boxdotnet/pom.xml b/sandbox-providers/boxdotnet/pom.xml index 77bbfbbd48..9402b6712d 100644 --- a/sandbox-providers/boxdotnet/pom.xml +++ b/sandbox-providers/boxdotnet/pom.xml @@ -120,8 +120,8 @@ ${project.artifactId} - org.jclouds.boxdotnet.*;version="${project.version}" - org.jclouds.*;version="${project.version}",* + org.jclouds.boxdotnet*;version="${project.version}" + org.jclouds*;version="${project.version}",* diff --git a/sandbox-providers/dunkel-vcd/pom.xml b/sandbox-providers/dunkel-vcd/pom.xml index ba0b19a574..3ee62987b9 100644 --- a/sandbox-providers/dunkel-vcd/pom.xml +++ b/sandbox-providers/dunkel-vcd/pom.xml @@ -127,8 +127,8 @@ ${project.artifactId} - org.jclouds.dunkel.vcd.*;version="${project.version}" - org.jclouds.*;version="${project.version}",* + org.jclouds.dunkel.vcd*;version="${project.version}" + org.jclouds*;version="${project.version}",* diff --git a/sandbox-providers/googlestorage/pom.xml b/sandbox-providers/googlestorage/pom.xml index fc99979aeb..64e3d81458 100644 --- a/sandbox-providers/googlestorage/pom.xml +++ b/sandbox-providers/googlestorage/pom.xml @@ -127,8 +127,8 @@ ${project.artifactId} - org.jclouds.googlestorage.*;version="${project.version}" - org.jclouds.*;version="${project.version}",* + org.jclouds.googlestorage*;version="${project.version}" + org.jclouds*;version="${project.version}",* diff --git a/sandbox-providers/hosteurope-storage/pom.xml b/sandbox-providers/hosteurope-storage/pom.xml index 0f905f3871..162cf90d30 100644 --- a/sandbox-providers/hosteurope-storage/pom.xml +++ b/sandbox-providers/hosteurope-storage/pom.xml @@ -134,8 +134,8 @@ ${project.artifactId} - org.jclouds.hosteurope.storage.*;version="${project.version}" - org.jclouds.*;version="${project.version}",* + org.jclouds.hosteurope.storage*;version="${project.version}" + org.jclouds*;version="${project.version}",* diff --git a/sandbox-providers/ibm-smartcloud/pom.xml b/sandbox-providers/ibm-smartcloud/pom.xml index a318bfb5cc..9f11432c2a 100644 --- a/sandbox-providers/ibm-smartcloud/pom.xml +++ b/sandbox-providers/ibm-smartcloud/pom.xml @@ -134,8 +134,8 @@ ${project.artifactId} - org.jclouds.ibm.smartcloud.*;version="${project.version}" - org.jclouds.*;version="${project.version}",* + org.jclouds.ibm.smartcloud*;version="${project.version}" + org.jclouds*;version="${project.version}",* diff --git a/sandbox-providers/scaleup-storage/pom.xml b/sandbox-providers/scaleup-storage/pom.xml index dfd5cdc7e6..ad334e7815 100644 --- a/sandbox-providers/scaleup-storage/pom.xml +++ b/sandbox-providers/scaleup-storage/pom.xml @@ -134,8 +134,8 @@ ${project.artifactId} - org.jclouds.scaleup.storage.*;version="${project.version}" - org.jclouds.*;version="${project.version}",* + org.jclouds.scaleup.storage*;version="${project.version}" + org.jclouds*;version="${project.version}",* diff --git a/sandbox-providers/tiscali-storage/pom.xml b/sandbox-providers/tiscali-storage/pom.xml index aff9eaa622..d8ecf017fd 100644 --- a/sandbox-providers/tiscali-storage/pom.xml +++ b/sandbox-providers/tiscali-storage/pom.xml @@ -135,8 +135,8 @@ ${project.artifactId} - org.jclouds.tiscali.storage.*;version="${project.version}" - org.jclouds.*;version="${project.version}",* + org.jclouds.tiscali.storage*;version="${project.version}" + org.jclouds*;version="${project.version}",* diff --git a/sandbox-providers/twitter/pom.xml b/sandbox-providers/twitter/pom.xml index 3dc78f6c14..2844ae7b61 100644 --- a/sandbox-providers/twitter/pom.xml +++ b/sandbox-providers/twitter/pom.xml @@ -121,8 +121,8 @@ ${project.artifactId} - org.jclouds.twitter.*;version="${project.version}" - org.jclouds.*;version="${project.version}",* + org.jclouds.twitter*;version="${project.version}" + org.jclouds*;version="${project.version}",* diff --git a/sandbox-providers/virtacore-publiccloud-lax/pom.xml b/sandbox-providers/virtacore-publiccloud-lax/pom.xml index 9c4d4e4ae6..571f5cdc5a 100644 --- a/sandbox-providers/virtacore-publiccloud-lax/pom.xml +++ b/sandbox-providers/virtacore-publiccloud-lax/pom.xml @@ -127,8 +127,8 @@ ${project.artifactId} - org.jclouds.virtacore.publiccloud.*;version="${project.version}" - org.jclouds.*;version="${project.version}",* + org.jclouds.virtacore.publiccloud*;version="${project.version}" + org.jclouds*;version="${project.version}",* diff --git a/scriptbuilder/pom.xml b/scriptbuilder/pom.xml index 5dbb4b69fd..a71432bc77 100644 --- a/scriptbuilder/pom.xml +++ b/scriptbuilder/pom.xml @@ -50,8 +50,8 @@ ${project.artifactId} - org.jclouds.scriptbuilder.*;version="${project.version}" - org.jclouds.*;version="${project.version}",* + org.jclouds.scriptbuilder*;version="${project.version}" + org.jclouds*;version="${project.version}",* diff --git a/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/ExitInsteadOfReturn.java b/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/ExitInsteadOfReturn.java new file mode 100644 index 0000000000..d079cd9f2b --- /dev/null +++ b/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/ExitInsteadOfReturn.java @@ -0,0 +1,55 @@ +/** + * 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.scriptbuilder; + +import org.jclouds.scriptbuilder.domain.OsFamily; +import org.jclouds.scriptbuilder.domain.ShellToken; +import org.jclouds.scriptbuilder.domain.Statement; + +import com.google.common.collect.ForwardingObject; + +/** + * you cannot return from a top-level script, so if you are using snippets that + * issue {@code return} then you'll want to wrap them in this. + * + * @author Adrian Cole + * + */ +public class ExitInsteadOfReturn extends ForwardingObject implements Statement { + private final Statement delegate; + + public ExitInsteadOfReturn(Statement delegate) { + this.delegate = delegate; + } + + @Override + public Iterable functionDependencies(OsFamily family) { + return delegate().functionDependencies(family); + } + + @Override + public String render(OsFamily family) { + return delegate().render(family).toString().replaceAll(ShellToken.RETURN.to(family), ShellToken.EXIT.to(family)); + } + + @Override + protected Statement delegate() { + return delegate; + } +} \ No newline at end of file diff --git a/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/InitBuilder.java b/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/InitBuilder.java index f19db77aa3..74fc896a3f 100644 --- a/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/InitBuilder.java +++ b/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/InitBuilder.java @@ -19,10 +19,7 @@ package org.jclouds.scriptbuilder; import static com.google.common.base.Preconditions.checkNotNull; -import static org.jclouds.scriptbuilder.domain.Statements.call; import static org.jclouds.scriptbuilder.domain.Statements.createRunScript; -import static org.jclouds.scriptbuilder.domain.Statements.findPid; -import static org.jclouds.scriptbuilder.domain.Statements.forget; import static org.jclouds.scriptbuilder.domain.Statements.interpret; import static org.jclouds.scriptbuilder.domain.Statements.kill; import static org.jclouds.scriptbuilder.domain.Statements.newStatementList; @@ -41,8 +38,10 @@ import com.google.common.collect.Iterables; /** * Creates an init script file * + * @see InitScript * @author Adrian Cole */ +@Deprecated public class InitBuilder extends ScriptBuilder { private final String instanceName; @@ -51,68 +50,67 @@ public class InitBuilder extends ScriptBuilder { private final StatementList initStatement; private final CreateRunScript createRunScript; + public InitBuilder(String instanceName, Statement initStatement, Statement runStatement) { + this(instanceName, ImmutableSet.of(initStatement), ImmutableSet.of(runStatement)); + } + + public InitBuilder(String instanceName, Iterable initStatements, Iterable statements) { + this(instanceName, String.format("{tmp}{fs}{varl}INSTANCE_NAME{varr}", instanceName), String.format( + "{tmp}{fs}{varl}INSTANCE_NAME{varr}", instanceName), ImmutableMap. of(), initStatements, + statements); + } + public InitBuilder(String instanceName, String instanceHome, String logDir, Map variables, - Iterable statements) { + Iterable statements) { this(instanceName, instanceHome, logDir, variables, ImmutableSet. of(), statements); } public InitBuilder(String instanceName, String instanceHome, String logDir, Map variables, - Iterable initStatements, Iterable statements) { + Iterable initStatements, Iterable statements) { Map defaultVariables = ImmutableMap.of("instanceName", instanceName, "instanceHome", - instanceHome, "logDir", logDir); + instanceHome, "logDir", logDir); this.initStatement = new StatementList(initStatements); this.createRunScript = createRunScript(instanceName,// TODO: convert - // so - // that - // createRunScript - // can take from a - // variable - Iterables.concat(variables.keySet(), defaultVariables.keySet()), "{varl}INSTANCE_HOME{varr}", statements); + // so + // that + // createRunScript + // can take from a + // variable + Iterables.concat(variables.keySet(), defaultVariables.keySet()), "{varl}INSTANCE_HOME{varr}", statements); this.instanceName = checkNotNull(instanceName, "instanceName"); this.instanceHome = checkNotNull(instanceHome, "instanceHome"); this.logDir = checkNotNull(logDir, "logDir"); addEnvironmentVariableScope("default", defaultVariables) - .addEnvironmentVariableScope(instanceName, variables) - .addStatement( - switchArg( - 1, - new ImmutableMap.Builder() - .put( - "init", - newStatementList(call("default"), call(instanceName), initStatement, - createRunScript)) - .put( - "status", - newStatementList(call("default"), - findPid("{varl}INSTANCE_NAME{varr}"), - interpret("echo [{varl}FOUND_PID{varr}]{lf}"))) - .put( - "stop", - newStatementList(call("default"), - findPid("{varl}INSTANCE_NAME{varr}"), kill())) - .put( - "start", - newStatementList( - call("default"), - forget( - "{varl}INSTANCE_NAME{varr}", - "{varl}INSTANCE_HOME{varr}{fs}{varl}INSTANCE_NAME{varr}.{sh}", - "{varl}LOG_DIR{varr}"))) - .put( - "tail", - newStatementList(call("default"), - interpret("tail {varl}LOG_DIR{varr}{fs}stdout.log{lf}"))) - .put( - "tailerr", - newStatementList(call("default"), - interpret("tail {varl}LOG_DIR{varr}{fs}stderr.log{lf}"))) - .put( - "run", - newStatementList( - call("default"), - interpret("{varl}INSTANCE_HOME{varr}{fs}{varl}INSTANCE_NAME{varr}.{sh}{lf}"))) - .build())); + .addEnvironmentVariableScope(instanceName, variables) + .addStatement( + switchArg( + 1, + new ImmutableMap.Builder() + .put("init", + newStatementList(call("default"), call(instanceName), initStatement, + createRunScript)) + .put("status", + newStatementList(call("default"), findPid("{varl}INSTANCE_NAME{varr}"), + interpret("echo [{varl}FOUND_PID{varr}]{lf}"))) + .put("stop", + newStatementList(call("default"), findPid("{varl}INSTANCE_NAME{varr}"), kill())) + .put("start", + newStatementList( + call("default"), + forget("{varl}INSTANCE_NAME{varr}", + "{varl}INSTANCE_HOME{varr}{fs}{varl}INSTANCE_NAME{varr}.{sh}", + "{varl}LOG_DIR{varr}"))) + .put("tail", + newStatementList(call("default"), + interpret("tail {varl}LOG_DIR{varr}{fs}stdout.log{lf}"))) + .put("tailerr", + newStatementList(call("default"), + interpret("tail {varl}LOG_DIR{varr}{fs}stderr.log{lf}"))) + .put("run", + newStatementList(call("default"), + interpret("{varl}INSTANCE_HOME{varr}{fs}{varl}INSTANCE_NAME{varr}.{sh}{lf}"))) + .build())); } @Override diff --git a/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/InitScript.java b/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/InitScript.java new file mode 100644 index 0000000000..439c96f1b6 --- /dev/null +++ b/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/InitScript.java @@ -0,0 +1,329 @@ +/** + * 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.scriptbuilder; + +import static com.google.common.base.Objects.equal; +import static com.google.common.base.Objects.toStringHelper; +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.collect.Iterables.concat; +import static java.lang.String.format; +import static org.jclouds.scriptbuilder.ScriptBuilder.call; +import static org.jclouds.scriptbuilder.ScriptBuilder.findPid; +import static org.jclouds.scriptbuilder.ScriptBuilder.forget; +import static org.jclouds.scriptbuilder.domain.Statements.createRunScript; +import static org.jclouds.scriptbuilder.domain.Statements.interpret; +import static org.jclouds.scriptbuilder.domain.Statements.kill; +import static org.jclouds.scriptbuilder.domain.Statements.newStatementList; +import static org.jclouds.scriptbuilder.domain.Statements.switchArg; + +import java.util.Map; + +import org.jclouds.scriptbuilder.domain.AcceptsStatementVisitor; +import org.jclouds.scriptbuilder.domain.CreateRunScript; +import org.jclouds.scriptbuilder.domain.OsFamily; +import org.jclouds.scriptbuilder.domain.Statement; +import org.jclouds.scriptbuilder.domain.StatementList; +import org.jclouds.scriptbuilder.domain.StatementVisitor; + +import com.google.common.base.Objects; +import com.google.common.collect.ForwardingObject; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; + +/** + * Creates an init script file + * + * @author Adrian Cole + */ +public class InitScript extends ForwardingObject implements Statement, AcceptsStatementVisitor { + + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + protected String instanceName; + protected String instanceHome = "{tmp}{fs}{varl}INSTANCE_NAME{varr}"; + protected String logDir = "{varl}INSTANCE_HOME{varr}"; + protected Map exports = ImmutableMap.of(); + protected StatementList init = new StatementList(); + protected StatementList run = new StatementList(); + + /** + * @see InitScript#getInstanceName() + */ + public Builder name(String instanceName) { + this.instanceName = checkNotNull(instanceName, "instanceName"); + return this; + } + + /** + * @see InitScript#getInstanceHome() + */ + public Builder home(String instanceHome) { + this.instanceHome = checkNotNull(instanceHome, "instanceHome"); + return this; + } + + /** + * @see InitScript#getLogDir() + */ + public Builder logDir(String logDir) { + this.logDir = checkNotNull(logDir, "logDir"); + return this; + } + + /** + * @see InitScript#getExportedVariables() + */ + public Builder exportVariables(Map exports) { + this.exports = ImmutableMap.copyOf(checkNotNull(exports, "exports")); + return this; + } + + /** + * @see InitScript#getRun() + */ + public Builder run(Statement run) { + this.run = new StatementList(checkNotNull(run, "run")); + return this; + } + + /** + * @see InitScript#getRun() + */ + public Builder run(Statement... run) { + this.run = new StatementList(checkNotNull(run, "run")); + return this; + } + + /** + * @see InitScript#getRun() + */ + public Builder run(Iterable run) { + this.run = new StatementList(checkNotNull(run, "run")); + return this; + } + + /** + * @see InitScript#getRun() + */ + public Builder run(StatementList run) { + this.run = checkNotNull(run, "run"); + return this; + } + + /** + * @see InitScript#getInit() + */ + public Builder init(Statement init) { + this.init = new StatementList(checkNotNull(init, "init")); + return this; + } + + /** + * @see InitScript#getInit() + */ + public Builder init(Statement... init) { + this.init = new StatementList(checkNotNull(init, "init")); + return this; + } + + /** + * @see InitScript#getInit() + */ + public Builder init(Iterable init) { + this.init = new StatementList(checkNotNull(init, "init")); + return this; + } + + /** + * @see InitScript#getInit() + */ + public Builder init(StatementList init) { + this.init = checkNotNull(init, "init"); + return this; + } + + public InitScript build() { + return new InitScript(instanceName, instanceHome, logDir, exports, init, run); + } + + } + + protected final String instanceName; + protected final String instanceHome; + protected final String logDir; + protected final Map exports; + protected final StatementList init; + protected final StatementList run; + protected final ScriptBuilder delegate; + + protected InitScript(String instanceName, String instanceHome, String logDir, Map exports, + StatementList init, StatementList run) { + this.instanceName = checkNotNull(instanceName, "instanceName"); + this.instanceHome = checkNotNull(instanceHome, "instanceHome"); + this.logDir = checkNotNull(logDir, "logDir"); + this.exports = ImmutableMap. copyOf(checkNotNull(exports, "exports")); + this.init = checkNotNull(init, "init"); + this.run = checkNotNull(run, "run"); + checkArgument(run.delegate().size() > 0, "you must specify at least one statement to run"); + this.delegate = makeInitScriptStatement(instanceName, instanceHome, logDir, exports, init, run); + } + + public static ScriptBuilder makeInitScriptStatement(String instanceName, String instanceHome, String logDir, + Map exports, StatementList init, StatementList run) { + Map defaultExports = ImmutableMap.of("instanceName", instanceName, "instanceHome", instanceHome, + "logDir", logDir); + String exitStatusFile = format("%s/rc", logDir); + run = new StatementList(ImmutableList. builder().add(interpret("rm -f " + exitStatusFile)) + .add(interpret(format("trap 'echo $?>%s' 0 1 2 3 15", exitStatusFile))).addAll(run.delegate()).build()); + + CreateRunScript createRunScript = createRunScript(instanceName, + concat(exports.keySet(), defaultExports.keySet()), "{varl}INSTANCE_HOME{varr}", run); + + return new ScriptBuilder() + .addEnvironmentVariableScope("default", defaultExports) + .addEnvironmentVariableScope(instanceName, exports) + .addStatement( + switchArg( + 1, + new ImmutableMap.Builder() + .put("init", newStatementList(call("default"), call(instanceName), init, createRunScript)) + .put("status", + newStatementList(call("default"), findPid("{varl}INSTANCE_NAME{varr}"), + interpret("echo [{varl}FOUND_PID{varr}]{lf}"))) + .put("stop", + newStatementList(call("default"), findPid("{varl}INSTANCE_NAME{varr}"), kill())) + .put("start", + newStatementList( + call("default"), + forget("{varl}INSTANCE_NAME{varr}", + "{varl}INSTANCE_HOME{varr}{fs}{varl}INSTANCE_NAME{varr}.{sh}", + "{varl}LOG_DIR{varr}"))) + .put("stdout", + newStatementList(call("default"), + interpret("cat {varl}LOG_DIR{varr}{fs}stdout.log{lf}"))) + .put("stderr", + newStatementList(call("default"), + interpret("cat {varl}LOG_DIR{varr}{fs}stderr.log{lf}"))) + .put("exitstatus", + newStatementList(call("default"), + interpret("[ -f $LOG_DIR/rc ] && cat $LOG_DIR/rc"))) + .put("tail", + newStatementList(call("default"), + interpret("tail {varl}LOG_DIR{varr}{fs}stdout.log{lf}"))) + .put("tailerr", + newStatementList(call("default"), + interpret("tail {varl}LOG_DIR{varr}{fs}stderr.log{lf}"))) + .put("run", + newStatementList(call("default"), + interpret("{varl}INSTANCE_HOME{varr}{fs}{varl}INSTANCE_NAME{varr}.{sh}{lf}"))) + .build())); + } + + /** + * + * @return what will be bound to the INSTANCE_NAME variable, and uniquely + * identifies the process + */ + public String getInstanceName() { + return instanceName; + } + + /** + * default {@code /tmp/$INSTANCE_NAME} + *
    + *

    note

    The parent directory + * should be set with unix sticky-bit or otherwise made available to all + * users. Otherwise, new instances by other users may fail due to not being + * able to create a directory. This is why the default is set to {@code /tmp} + * + * @return what will be bound to the INSTANCE_HOME variable, and represents + * the working directory of the instance + */ + public String getInstanceHome() { + return instanceHome; + } + + /** + * default {@code $INSTANCE_HOME} + * + * @return what will be bound to the LOG_DIR variable, and represents where + * stdout and stderr.logs are written. + */ + public String getLogDir() { + return logDir; + } + + /** + * + * @return statements that will be executed upon the init command + */ + public StatementList getInitStatement() { + return init; + } + + /** + * + * @return statements that will be executed upon the run or start commands + */ + public StatementList getRunStatement() { + return init; + } + + @Override + public int hashCode() { + return Objects.hashCode(instanceName); + } + + @Override + public boolean equals(Object that) { + if (that == null) + return false; + return equal(this.toString(), that.toString()); + } + + @Override + public String toString() { + return toStringHelper(this).add("instanceName", instanceName).toString(); + } + + @Override + public void accept(StatementVisitor visitor) { + delegate().accept(visitor); + } + + @Override + public Iterable functionDependencies(OsFamily family) { + return delegate().functionDependencies(family); + } + + @Override + public String render(OsFamily family) { + return delegate().render(family); + } + + @Override + protected ScriptBuilder delegate() { + return delegate; + } + +} \ No newline at end of file diff --git a/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/ScriptBuilder.java b/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/ScriptBuilder.java index 22362f2fc5..6b29ac5966 100644 --- a/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/ScriptBuilder.java +++ b/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/ScriptBuilder.java @@ -23,20 +23,25 @@ import static com.google.common.base.Preconditions.checkNotNull; import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.Set; import org.jclouds.scriptbuilder.domain.AcceptsStatementVisitor; import org.jclouds.scriptbuilder.domain.OsFamily; import org.jclouds.scriptbuilder.domain.ShellToken; import org.jclouds.scriptbuilder.domain.Statement; import org.jclouds.scriptbuilder.domain.StatementVisitor; +import org.jclouds.scriptbuilder.domain.Statements; import org.jclouds.scriptbuilder.util.Utils; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Function; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableMap.Builder; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; import com.google.common.collect.Maps; +import com.google.common.collect.Sets; /** * Creates a shell script. @@ -75,6 +80,20 @@ public class ScriptBuilder implements Statement, AcceptsStatementVisitor { return this; } + // TODO: make scriptbuilder smart enough to know when a statement is a direct + // child of the script, and automatically convert + public static Statement forget(String instanceName, String script, String logDir) { + return new ExitInsteadOfReturn(Statements.forget(instanceName, script, logDir)); + } + + public static Statement findPid(String pid) { + return new ExitInsteadOfReturn(Statements.findPid(pid)); + } + + public static Statement call(String fn, String... args) { + return new ExitInsteadOfReturn(Statements.call(fn, args)); + } + /** * builds the shell script, by adding the following *
      @@ -93,63 +112,66 @@ public class ScriptBuilder implements Statement, AcceptsStatementVisitor { functions.put("abort", Utils.writeFunctionFromResource("abort", osFamily)); for (Entry> entry : variableScopes.entrySet()) { - functions.put(entry.getKey(), Utils.writeFunction(entry.getKey(), Utils.writeVariableExporters(entry - .getValue()))); + functions.put(entry.getKey(), + Utils.writeFunction(entry.getKey(), Utils.writeVariableExporters(entry.getValue()))); } final Map tokenValueMap = ShellToken.tokenValueMap(osFamily); StringBuilder builder = new StringBuilder(); builder.append(ShellToken.BEGIN_SCRIPT.to(osFamily)); - builder.append(Utils.writeUnsetVariables(Lists.newArrayList(Iterables.transform(variablesToUnset, - new Function() { - @Override - public String apply(String from) { - if (tokenValueMap.containsKey(from + "Variable")) - return Utils.FUNCTION_UPPER_UNDERSCORE_TO_LOWER_CAMEL.apply(tokenValueMap - .get(from + "Variable")); - return from; - } + builder.append(Utils.writeUnsetVariables( + Lists.newArrayList(Iterables.transform(variablesToUnset, new Function() { + @Override + public String apply(String from) { + if (tokenValueMap.containsKey(from + "Variable")) + return Utils.FUNCTION_UPPER_UNDERSCORE_TO_LOWER_CAMEL.apply(tokenValueMap.get(from + "Variable")); + return from; + } - })), osFamily)); - resolveFunctionDependencies(functions, osFamily); - if (functions.size() > 0) { - builder.append(ShellToken.BEGIN_FUNCTIONS.to(osFamily)); - for (String function : functions.values()) { - builder.append(Utils.replaceTokens(function, tokenValueMap)); - } - builder.append(ShellToken.END_FUNCTIONS.to(osFamily)); - } + })), osFamily)); + Map functionsToWrite = resolveFunctionDependenciesForStatements(functions, statements, osFamily); + writeFunctions(functionsToWrite, osFamily, builder); builder.append(Utils.writeZeroPath(osFamily)); StringBuilder statementBuilder = new StringBuilder(); for (Statement statement : statements) { statementBuilder.append(statement.render(osFamily)); } - builder.append(statementBuilder.toString().replaceAll(ShellToken.RETURN.to(osFamily), - ShellToken.EXIT.to(osFamily))); + builder.append(statementBuilder.toString()); builder.append(ShellToken.END_SCRIPT.to(osFamily)); return builder.toString(); } - @VisibleForTesting - void resolveFunctionDependencies(Map functions, final OsFamily osFamily) { - Iterable dependentFunctions = Iterables.concat(Iterables.transform(statements, - new Function>() { - @Override - public Iterable apply(Statement from) { - return from.functionDependencies(osFamily); - } - })); - List unresolvedFunctions = Lists.newArrayList(dependentFunctions); - Iterables.removeAll(unresolvedFunctions, functions.keySet()); - for (String functionName : unresolvedFunctions) { - functions.put(functionName, Utils.writeFunctionFromResource(functionName, osFamily)); + public static void writeFunctions(Map functionsToWrite, OsFamily osFamily, StringBuilder builder) { + if (functionsToWrite.size() > 0) { + builder.append(ShellToken.BEGIN_FUNCTIONS.to(osFamily)); + for (String function : functionsToWrite.values()) { + builder.append(Utils.replaceTokens(function, ShellToken.tokenValueMap(osFamily))); + } + builder.append(ShellToken.END_FUNCTIONS.to(osFamily)); } } + @VisibleForTesting + public static Map resolveFunctionDependenciesForStatements(Map knownFunctions, + Iterable statements, final OsFamily osFamily) { + Builder builder = ImmutableMap. builder(); + builder.putAll(knownFunctions); + Set dependentFunctions = ImmutableSet.copyOf(Iterables.concat(Iterables.transform(statements, + new Function>() { + @Override + public Iterable apply(Statement from) { + return from.functionDependencies(osFamily); + } + }))); + for (String unresolved : Sets.difference(dependentFunctions, knownFunctions.keySet())) + builder.put(unresolved, Utils.writeFunctionFromResource(unresolved, osFamily)); + return builder.build(); + } + @Override public Iterable functionDependencies(OsFamily family) { return ImmutableSet. of(); } - + @Override public void accept(StatementVisitor visitor) { for (Statement statement : statements) { diff --git a/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/domain/AppendFile.java b/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/domain/AppendFile.java index 3d16d26352..4f674cf5de 100644 --- a/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/domain/AppendFile.java +++ b/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/domain/AppendFile.java @@ -23,13 +23,12 @@ import static com.google.common.base.Preconditions.checkState; import static org.jclouds.scriptbuilder.domain.Statements.interpret; import java.util.Collections; -import java.util.List; import java.util.Map; import java.util.Map.Entry; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; -import com.google.common.collect.Lists; import com.google.common.collect.Maps; /** @@ -38,21 +37,66 @@ import com.google.common.collect.Maps; * @author Adrian Cole */ public class AppendFile implements Statement { - public static final String MARKER = "END_OF_FILE"; + public static final String DELIMETER = "END_OF_JCLOUDS_FILE"; - final String path; - final Iterable lines; - final String marker; - - public AppendFile(String path, Iterable lines) { - this(path, lines, MARKER); + public static Builder builder() { + return new Builder(); } - public AppendFile(String path, Iterable lines, String marker) { + public static class Builder { + protected String path; + protected Iterable lines = ImmutableSet.of(); + protected String delimeter = DELIMETER; + protected boolean expandVariables; + + /** + * @see AppendFile#getPath() + */ + public Builder path(String path) { + this.path = path; + return this; + } + + /** + * @see AppendFile#getLines() + */ + public Builder lines(Iterable lines) { + this.lines = ImmutableList.copyOf(lines); + return this; + } + + /** + * @see AppendFile#getDelimeter() + */ + public Builder delimeter(String delimeter) { + this.delimeter = delimeter; + return this; + } + + /** + * @see AppendFile#shouldExpandVariables() + */ + public Builder expandVariables(boolean expandVariables) { + this.expandVariables = expandVariables; + return this; + } + + public AppendFile build() { + return new AppendFile(path, lines, delimeter, expandVariables); + } + } + + protected final String path; + protected final Iterable lines; + protected final String delimeter; + protected final boolean expandVariables; + + protected AppendFile(String path, Iterable lines, String delimeter, boolean expandVariables) { this.path = checkNotNull(path, "path"); this.lines = checkNotNull(lines, "lines"); - this.marker = checkNotNull(marker, "marker"); + this.delimeter = checkNotNull(delimeter, "delimeter"); checkState(Iterables.size(lines) > 0, "you must pass something to execute"); + this.expandVariables = expandVariables; } public static String escapeVarTokens(String toEscape, OsFamily family) { @@ -76,35 +120,45 @@ public class AppendFile implements Statement { @Override public String render(OsFamily family) { - List statements = Lists.newArrayList(); if (family == OsFamily.UNIX) { - StringBuilder builder = new StringBuilder(); - hereFile(path, builder); - statements.add(interpret(builder.toString())); + return interpret(hereFile()).render(family); } else { - for (String line : lines) { - statements.add(appendToFile(line, path, family)); - } + return interpret(appendToWindowsFile()).render(family); } - return new StatementList(statements).render(family); } - protected void hereFile(String path, StringBuilder builder) { - builder.append("cat >> ").append(path).append(" <<'").append(marker).append("'\n"); + protected String appendToWindowsFile() { + StringBuilder builder = new StringBuilder(); for (String line : lines) { - builder.append(line).append("\n"); + builder.append(appendLineToWindowsFile(line, path)); } - builder.append(marker).append("\n"); + return builder.toString(); } - protected Statement appendToFile(String line, String path, OsFamily family) { + protected String hereFile() { + StringBuilder hereFile = startHereFile(); + for (String line : lines) { + hereFile.append('\t').append(line).append("\n"); + } + hereFile.append(delimeter).append("\n"); + return hereFile.toString(); + } + + public StringBuilder startHereFile() { + StringBuilder hereFile = new StringBuilder().append("cat >> ").append(path); + if (expandVariables) + return hereFile.append(" <<-").append(delimeter).append("\n"); + return hereFile.append(" <<-'").append(delimeter).append("'\n"); + } + + protected String appendLineToWindowsFile(String line, String path) { String quote = ""; - if (!ShellToken.VQ.to(family).equals("")) { + if (!ShellToken.VQ.to(OsFamily.WINDOWS).equals("")) { quote = "'"; } else { - line = escapeVarTokens(line, family); + line = escapeVarTokens(line, OsFamily.WINDOWS); } - return interpret(String.format("echo %s%s%s >>%s{lf}", quote, line, quote, path)); + return String.format("echo %s%s%s >>%s{lf}", quote, line, quote, path); } } \ No newline at end of file diff --git a/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/domain/CreateFile.java b/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/domain/CreateFile.java deleted file mode 100644 index 8636fafa56..0000000000 --- a/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/domain/CreateFile.java +++ /dev/null @@ -1,118 +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. - */ -package org.jclouds.scriptbuilder.domain; - -import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.base.Preconditions.checkState; -import static org.jclouds.scriptbuilder.domain.Statements.interpret; - -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.regex.Pattern; - -import com.google.common.collect.ImmutableList; -import com.google.common.collect.Iterables; -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; - -/** - * Creates a run script - * - * @author Adrian Cole - */ -public class CreateFile implements Statement { - public static final String MARKER = "END_OF_FILE"; - - final String path; - final Iterable lines; - final String marker; - - public CreateFile(String path, Iterable lines) { - this(path, lines, MARKER); - } - - public CreateFile(String path, Iterable lines, String marker) { - this.path = checkNotNull(path, "path"); - this.lines = checkNotNull(lines, "lines"); - this.marker = checkNotNull(marker, "marker"); - checkState(Iterables.size(lines) > 0, "you must pass something to execute"); - } - - public static String escapeVarTokens(String toEscape, OsFamily family) { - Map inputToEscape = Maps.newHashMap(); - for (ShellToken token : ImmutableList.of(ShellToken.VARL, ShellToken.VARR)) { - if (!token.to(family).equals("")) { - String tokenS = "{" + token.toString().toLowerCase() + "}"; - inputToEscape.put(tokenS, "{escvar}" + tokenS); - } - } - for (Entry entry : inputToEscape.entrySet()) { - toEscape = toEscape.replace(entry.getKey(), entry.getValue()); - } - return toEscape; - } - - @Override - public Iterable functionDependencies(OsFamily family) { - return Collections.emptyList(); - } - - @Override - public String render(OsFamily family) { - List statements = Lists.newArrayList(); - if (family == OsFamily.UNIX) { - StringBuilder builder = new StringBuilder(); - hereFile(path, builder); - statements.add(interpret(builder.toString())); - } else { - for (String line : lines) { - statements.add(appendToFile(line, path, family)); - } - } - return new StatementList(statements).render(family); - } - - private void hereFile(String path, StringBuilder builder) { - builder.append("cat > ").append(path).append(" <<'").append(marker).append("'\n"); - for (String line : lines) { - builder.append(line).append("\n"); - } - builder.append(marker).append("\n"); - } - - private Statement appendToFile(String line, String path, OsFamily family) { - String quote = ""; - if (!ShellToken.VQ.to(family).equals("")) { - quote = "'"; - } else { - line = escapeVarTokens(line, family); - } - return interpret(addSpaceToEnsureWeDontAccidentallyRedirectFd(String.format("echo %s%s%s>>%s{lf}", quote, line, - quote, path))); - } - - public static final Pattern REDIRECT_FD_PATTERN = Pattern.compile(".*[0-2]>>.*"); - - static String addSpaceToEnsureWeDontAccidentallyRedirectFd(String line) { - return REDIRECT_FD_PATTERN.matcher(line).matches() ? line.replace(">>", " >>") : line; - } - -} \ No newline at end of file diff --git a/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/domain/CreateOrOverwriteFile.java b/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/domain/CreateOrOverwriteFile.java index 701c2977a6..04bb3ab03f 100644 --- a/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/domain/CreateOrOverwriteFile.java +++ b/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/domain/CreateOrOverwriteFile.java @@ -18,11 +18,6 @@ */ package org.jclouds.scriptbuilder.domain; -import static org.jclouds.scriptbuilder.domain.Statements.interpret; - -import java.util.List; - -import com.google.common.collect.Lists; /** * Creates a run script @@ -30,38 +25,54 @@ import com.google.common.collect.Lists; * @author Adrian Cole */ public class CreateOrOverwriteFile extends AppendFile { - - public CreateOrOverwriteFile(String path, Iterable lines) { - super(path, lines); + public static Builder builder() { + return new Builder(); } - public CreateOrOverwriteFile(String path, Iterable lines, String marker) { - super(path, lines, marker); + public static class Builder extends AppendFile.Builder { + + @Override + public Builder path(String path) { + return Builder.class.cast(super.path(path)); + } + + @Override + public Builder lines(Iterable lines) { + return Builder.class.cast(super.lines(lines)); + } + + @Override + public Builder delimeter(String delimeter) { + return Builder.class.cast(super.delimeter(delimeter)); + } + + @Override + public Builder expandVariables(boolean expandVariables) { + return Builder.class.cast(super.expandVariables(expandVariables)); + } + + @Override + public CreateOrOverwriteFile build() { + return new CreateOrOverwriteFile(path, lines, delimeter, expandVariables); + } + + } + + protected CreateOrOverwriteFile(String path, Iterable lines, String delimeter, boolean expandVariables) { + super(path, lines, delimeter, expandVariables); } @Override - public String render(OsFamily family) { - List statements = Lists.newArrayList(); - if (family == OsFamily.UNIX) { - StringBuilder builder = new StringBuilder(); - hereFile(path, builder); - statements.add(interpret(builder.toString())); - } else { - // Windows: - statements.add(interpret(String.format("copy /y CON %s{lf}", path))); // This clears the file - for (String line : lines) { - statements.add(appendToFile(line, path, family)); - } - } - return new StatementList(statements).render(family); + protected String appendToWindowsFile() { + return String.format("copy /y CON %s{lf}", path) + super.appendToWindowsFile(); } - protected void hereFile(String path, StringBuilder builder) { - builder.append("cat > ").append(path).append(" <<'").append(marker).append("'\n"); - for (String line : lines) { - builder.append(line).append("\n"); - } - builder.append(marker).append("\n"); + @Override + public StringBuilder startHereFile() { + StringBuilder hereFile = new StringBuilder().append("cat > ").append(path); + if (expandVariables) + return hereFile.append(" <<-").append(delimeter).append("\n"); + return hereFile.append(" <<-'").append(delimeter).append("'\n"); } } \ No newline at end of file diff --git a/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/domain/CreateRunScript.java b/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/domain/CreateRunScript.java index d935860444..ad680797e4 100644 --- a/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/domain/CreateRunScript.java +++ b/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/domain/CreateRunScript.java @@ -19,22 +19,30 @@ package org.jclouds.scriptbuilder.domain; import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Predicates.instanceOf; +import static com.google.common.collect.Iterables.any; +import static com.google.common.collect.Lists.newArrayList; +import static java.lang.String.format; +import static org.jclouds.scriptbuilder.domain.Statements.appendFile; +import static org.jclouds.scriptbuilder.domain.Statements.createOrOverwriteFile; +import static org.jclouds.scriptbuilder.domain.Statements.exec; import static org.jclouds.scriptbuilder.domain.Statements.interpret; import java.util.Collections; import java.util.List; import java.util.Map; -import java.util.Map.Entry; -import java.util.regex.Pattern; +import org.jclouds.scriptbuilder.ExitInsteadOfReturn; +import org.jclouds.scriptbuilder.ScriptBuilder; import org.jclouds.scriptbuilder.util.Utils; import com.google.common.base.CaseFormat; +import com.google.common.base.Function; 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.Lists; -import com.google.common.collect.Maps; +import com.google.common.collect.Iterables; /** * Creates a run script @@ -42,7 +50,7 @@ import com.google.common.collect.Maps; * @author Adrian Cole */ public class CreateRunScript extends StatementList { - public final static String MARKER = "END_OF_SCRIPT"; + public final static String DELIMETER = "END_OF_JCLOUDS_SCRIPT"; final String instanceName; final Iterable exports; final String pwd; @@ -54,45 +62,17 @@ public class CreateRunScript extends StatementList { this.pwd = checkNotNull(pwd, "pwd").replaceAll("[/\\\\]", "{fs}"); } - public static class AddTitleToFile implements Statement { - final String title; - final String file; - - public AddTitleToFile(String title, String file) { - this.title = checkNotNull(title, "title"); - this.file = checkNotNull(file, "file"); - } - - public static final Map OS_TO_TITLE_PATTERN = ImmutableMap.of(OsFamily.UNIX, - "echo \"PROMPT_COMMAND='echo -ne \\\"\\033]0;{title}\\007\\\"'\">>{file}\n", OsFamily.WINDOWS, - "echo title {title}>>{file}\r\n"); - - @Override - public Iterable functionDependencies(OsFamily family) { - return Collections.emptyList(); - } - - @Override - public String render(OsFamily family) { - return addSpaceToEnsureWeDontAccidentallyRedirectFd(Utils.replaceTokens(OS_TO_TITLE_PATTERN.get(family), - ImmutableMap.of("title", title, "file", file))); - } - } - - public static class AddExportToFile implements Statement { + public static class AddExport implements Statement { final String export; final String value; - final String file; - public AddExportToFile(String export, String value, String file) { + public AddExport(String export, String value) { this.export = checkNotNull(CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_UNDERSCORE, export), "export"); this.value = checkNotNull(value, "value"); - this.file = checkNotNull(file, "file"); } public static final Map OS_TO_EXPORT_PATTERN = ImmutableMap.of(OsFamily.UNIX, - "echo \"export {export}='{value}'\">>{file}\n", OsFamily.WINDOWS, - "echo set {export}={value}>>{file}\r\n"); + "export {export}='{value}'\n", OsFamily.WINDOWS, "set {export}={value}\r\n"); @Override public Iterable functionDependencies(OsFamily family) { @@ -101,123 +81,91 @@ public class CreateRunScript extends StatementList { @Override public String render(OsFamily family) { - return addSpaceToEnsureWeDontAccidentallyRedirectFd(Utils.replaceTokens(OS_TO_EXPORT_PATTERN.get(family), - ImmutableMap.of("export", export, "value", value, "file", file))); + return Utils + .replaceTokens(OS_TO_EXPORT_PATTERN.get(family), ImmutableMap.of("export", export, "value", value)); } } - public static String escapeVarTokens(String toEscape, OsFamily family) { - Map inputToEscape = Maps.newHashMap(); - for (ShellToken token : ImmutableList.of(ShellToken.VARL, ShellToken.VARR)) { - if (!token.to(family).equals("")) { - String tokenS = "{" + token.toString().toLowerCase() + "}"; - inputToEscape.put(tokenS, "{escvar}" + tokenS); - } - } - for (Entry entry : inputToEscape.entrySet()) { - toEscape = toEscape.replace(entry.getKey(), entry.getValue()); - } - return toEscape; - } - @Override public Iterable functionDependencies(OsFamily family) { return Collections.emptyList(); } - public static final Map OS_TO_CHMOD_PATTERN = ImmutableMap.of(OsFamily.UNIX, "chmod u+x {file}\n", - OsFamily.WINDOWS, ""); - @Override public String render(OsFamily family) { - List statements = Lists.newArrayList(); - Map tokenMap = ShellToken.tokenValueMap(family); + if (checkNotNull(family, "family") == OsFamily.WINDOWS) + throw new UnsupportedOperationException("windows not yet implemented"); + List statements = newArrayList(); + final Map tokenMap = ShellToken.tokenValueMap(family); String runScript = Utils.replaceTokens(pwd + "{fs}" + instanceName + ".{sh}", tokenMap); statements.add(interpret(String.format("{md} %s{lf}", pwd))); - if (family == OsFamily.UNIX) { - StringBuilder builder = new StringBuilder(); - builder.append("\n"); - addUnixRunScriptHeader(family, runScript, builder); - builder.append("\n"); - addUnixRunScript(runScript, builder); - builder.append("\n"); - addUnixRunScriptFooter(family, runScript, builder); - builder.append("\n"); - statements.add(interpret(builder.toString())); - } else { - statements.add(interpret(String.format("{rm} %s 2{closeFd}{lf}", runScript))); - for (String line : Splitter.on(ShellToken.LF.to(family)).split(ShellToken.BEGIN_SCRIPT.to(family))) { - if (!line.equals("")) - statements.add(appendToFile(line, runScript, family)); - } - statements.add(new AddTitleToFile(instanceName, runScript)); - statements.add(appendToFile(Utils.writeZeroPath(family).replace(ShellToken.LF.to(family), ""), runScript, - family)); - statements.add(new AddExportToFile("instanceName", instanceName, runScript)); - for (String export : exports) { - statements - .add(new AddExportToFile(export, Utils.replaceTokens("{varl}" - + CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_UNDERSCORE, export) + "{varr}", tokenMap), - runScript)); - } - statements.add(appendToFile("{cd} " + pwd, runScript, family)); - statements.addAll(statements); - for (String line : Splitter.on(ShellToken.LF.to(family)).split(ShellToken.END_SCRIPT.to(family))) { - if (!line.equals("")) - statements.add(appendToFile(line, runScript, family)); - } - } - statements - .add(interpret(Utils.replaceTokens(OS_TO_CHMOD_PATTERN.get(family), ImmutableMap.of("file", runScript)))); + StringBuilder builder = new StringBuilder(); + builder.append("\n"); + addUnixRunScriptHeader(runScript, builder); + builder.append("\n"); + addUnixRunScript(runScript, builder); + builder.append("\n"); + addUnixRunScriptFooter(runScript, builder); + builder.append("\n"); + statements.add(interpret(builder.toString())); + statements.add(exec("chmod u+x " + runScript)); return new StatementList(statements).render(family); } - private void addUnixRunScriptFooter(OsFamily family, String runScript, StringBuilder builder) { + private void addUnixRunScriptFooter(String runScript, StringBuilder builder) { builder.append("# add runscript footer\n"); - builder.append("cat >> ").append(runScript).append(" <<'").append(MARKER).append("'\n"); - builder.append(ShellToken.END_SCRIPT.to(family)); - builder.append(MARKER).append("\n"); + Iterable endScript = Splitter.on(ShellToken.LF.to(OsFamily.UNIX)).split( + ShellToken.END_SCRIPT.to(OsFamily.UNIX)); + builder.append(appendFile(runScript, endScript, DELIMETER).render(OsFamily.UNIX)); } private void addUnixRunScript(String runScript, StringBuilder builder) { builder.append("# add desired commands from the user\n"); - builder.append("cat >> ").append(runScript).append(" <<'").append(MARKER).append("'\n"); - builder.append("cd ").append(pwd).append("\n"); + Builder userCommands = ImmutableList.builder(); + userCommands.add("cd " + pwd); for (Statement statement : statements) { - builder.append(statement.render(OsFamily.UNIX)).append("\n"); + if (statement instanceof Call + || (statement instanceof StatementList && any(StatementList.class.cast(statement).delegate(), + instanceOf(Call.class)))) { + statement = new ExitInsteadOfReturn(statement); + } + userCommands.addAll(Splitter.on('\n').split(statement.render(OsFamily.UNIX))); } - builder.append(MARKER).append("\n"); + builder.append(appendFile(runScript, userCommands.build(), DELIMETER).render(OsFamily.UNIX)); } - private void addUnixRunScriptHeader(OsFamily family, String runScript, StringBuilder builder) { + private void addUnixRunScriptHeader(String runScript, StringBuilder builder) { builder.append("# create runscript header\n"); - builder.append("cat > ").append(runScript).append(" <<").append(MARKER).append("\n"); - builder.append(ShellToken.BEGIN_SCRIPT.to(family)); - builder.append("PROMPT_COMMAND='echo -ne \"\\033]0;").append(instanceName).append("\\007\"'\n"); - builder.append(Utils.writeZeroPath(family)); - builder.append("export INSTANCE_NAME='").append(instanceName).append("'\n"); - for (String export : exports) { - String variableNameInUpper = CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_UNDERSCORE, export); - builder.append("export ").append(variableNameInUpper).append("='$").append(variableNameInUpper).append("'\n"); + + Builder beginningOfFile = ImmutableList. builder(); + beginningOfFile.addAll(Splitter.on(ShellToken.LF.to(OsFamily.UNIX)).split( + ShellToken.BEGIN_SCRIPT.to(OsFamily.UNIX))); + beginningOfFile.add(format("PROMPT_COMMAND='echo -ne \\\"\\033]0;%s\\007\\\"'", instanceName)); + beginningOfFile.add(Utils.writeZeroPath(OsFamily.UNIX)); + beginningOfFile.add(format("export INSTANCE_NAME='%s'", instanceName)); + builder.append(createOrOverwriteFile(runScript, beginningOfFile.build(), DELIMETER).render(OsFamily.UNIX)); + + // expanding variables here. + builder.append(AppendFile.builder().path(runScript).delimeter(DELIMETER).expandVariables(true) + .lines(Iterables.transform(exports, new Function() { + + @Override + public String apply(String export) { + String variableNameInUpper = CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_UNDERSCORE, export); + return new StringBuilder().append("export ").append(variableNameInUpper).append("='$") + .append(variableNameInUpper).append("'").toString(); + } + })).build().render(OsFamily.UNIX)); + + Map functionsToWrite = ScriptBuilder.resolveFunctionDependenciesForStatements( + ImmutableMap. of("abort", Utils.writeFunctionFromResource("abort", OsFamily.UNIX)), + statements, OsFamily.UNIX); + + // if there are more functions than simply abort + if (functionsToWrite.size() > 1) { + StringBuilder functions = new StringBuilder(); + ScriptBuilder.writeFunctions(functionsToWrite, OsFamily.UNIX, functions); + builder.append(appendFile(runScript, functions.toString(), DELIMETER).render(OsFamily.UNIX)); } - builder.append(MARKER).append("\n"); } - - private Statement appendToFile(String line, String runScript, OsFamily family) { - String quote = ""; - if (!ShellToken.VQ.to(family).equals("")) { - quote = "'"; - } else { - line = escapeVarTokens(line, family); - } - return interpret(addSpaceToEnsureWeDontAccidentallyRedirectFd(String.format("echo %s%s%s>>%s{lf}", quote, line, - quote, runScript))); - } - - public static final Pattern REDIRECT_FD_PATTERN = Pattern.compile(".*[0-2]>>.*"); - - static String addSpaceToEnsureWeDontAccidentallyRedirectFd(String line) { - return REDIRECT_FD_PATTERN.matcher(line).matches() ? line.replace(">>", " >>") : line; - } - } \ No newline at end of file diff --git a/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/domain/SaveHttpResponseTo.java b/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/domain/SaveHttpResponseTo.java index 615e5ab06d..f2c011fb6b 100644 --- a/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/domain/SaveHttpResponseTo.java +++ b/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/domain/SaveHttpResponseTo.java @@ -46,17 +46,22 @@ public class SaveHttpResponseTo extends InterpretableStatement { * request headers to send */ public SaveHttpResponseTo(String dir, String file, String method, URI endpoint, Multimap headers) { - super(String.format("({md} %s && {cd} %s && [ ! -f %s ] && %s -C - -X %s %s %s >%s)\n", dir, dir, file, CURL, - method, Joiner.on(' ').join( - Iterables.transform(headers.entries(), new Function, String>() { + super(String.format( + "({md} %s && {cd} %s && [ ! -f %s ] && %s -C - -X %s %s %s >%s)\n", + dir, + dir, + file, + CURL, + method, + Joiner.on(' ').join( + Iterables.transform(headers.entries(), new Function, String>() { - @Override - public String apply(Map.Entry from) { - return String.format("-H \"%s: %s\"", from.getKey(), from.getValue()); - } + @Override + public String apply(Map.Entry from) { + return String.format("-H \"%s: %s\"", from.getKey(), from.getValue()); + } - })), endpoint.toASCIIString(), file)); + })), endpoint.toASCIIString(), file)); } - } \ No newline at end of file diff --git a/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/domain/ShellToken.java b/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/domain/ShellToken.java index 7176981696..bf0d4d91e8 100644 --- a/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/domain/ShellToken.java +++ b/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/domain/ShellToken.java @@ -103,7 +103,7 @@ public enum ShellToken { case WINDOWS: return " exit /b 0\r\n"; case UNIX: - return " return 0\n}\n"; + return " return $?\n}\n"; } case ESCVAR: switch (family) { @@ -173,7 +173,7 @@ public enum ShellToken { case WINDOWS: return "exit /b 0\r\n"; case UNIX: - return "exit 0\n"; + return "exit $?\n"; } case EXPORT: switch (family) { diff --git a/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/domain/StatementList.java b/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/domain/StatementList.java index f0da7f8dbc..db5f4a3aaa 100644 --- a/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/domain/StatementList.java +++ b/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/domain/StatementList.java @@ -22,6 +22,7 @@ import static com.google.common.base.Preconditions.checkNotNull; import java.util.List; +import com.google.common.collect.ForwardingList; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList.Builder; @@ -30,7 +31,7 @@ import com.google.common.collect.ImmutableList.Builder; * * @author Adrian Cole */ -public class StatementList implements Statement, AcceptsStatementVisitor { +public class StatementList extends ForwardingList implements Statement, AcceptsStatementVisitor { public final List statements; @@ -44,7 +45,7 @@ public class StatementList implements Statement, AcceptsStatementVisitor { public String render(OsFamily family) { StringBuilder statementsBuilder = new StringBuilder(); - for (Statement statement : statements) { + for (Statement statement : delegate()) { statementsBuilder.append(statement.render(family)); } return statementsBuilder.toString(); @@ -53,41 +54,21 @@ public class StatementList implements Statement, AcceptsStatementVisitor { @Override public Iterable functionDependencies(OsFamily family) { Builder functions = ImmutableList. builder(); - for (Statement statement : statements) { + for (Statement statement : delegate()) { functions.addAll(statement.functionDependencies(family)); } return functions.build(); } - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((statements == null) ? 0 : statements.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - StatementList other = (StatementList) obj; - if (statements == null) { - if (other.statements != null) - return false; - } else if (!statements.equals(other.statements)) - return false; - return true; - } - @Override public void accept(StatementVisitor visitor) { - for (Statement statement : statements) { + for (Statement statement : delegate()) { visitor.visit(statement); } } + + @Override + public List delegate() { + return statements; + } } \ No newline at end of file diff --git a/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/domain/Statements.java b/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/domain/Statements.java index 5fe30ccb85..76c6bf6ed1 100644 --- a/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/domain/Statements.java +++ b/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/domain/Statements.java @@ -22,6 +22,8 @@ import java.net.URI; import java.util.Map; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMultimap; +import com.google.common.collect.ImmutableSet; import com.google.common.collect.Multimap; /** @@ -63,24 +65,28 @@ public class Statements { return new Call(function, args); } + public static Statement appendFile(String path, String line, String delimeter) { + return AppendFile.builder().path(path).lines(ImmutableSet.of(line)).delimeter(delimeter).build(); + } + public static Statement appendFile(String path, Iterable lines) { - return new AppendFile(path, lines); - } + return AppendFile.builder().path(path).lines(lines).build(); + } - public static Statement appendFile(String path, Iterable lines, String marker) { - return new AppendFile(path, lines, marker); - } + public static Statement appendFile(String path, Iterable lines, String delimeter) { + return AppendFile.builder().path(path).lines(lines).delimeter(delimeter).build(); + } - public static Statement createOrOverwriteFile(String path, Iterable lines) { - return new CreateOrOverwriteFile(path, lines); - } + public static Statement createOrOverwriteFile(String path, Iterable lines) { + return CreateOrOverwriteFile.builder().path(path).lines(lines).build(); + } - public static Statement createOrOverwriteFile(String path, Iterable lines, String marker) { - return new CreateOrOverwriteFile(path, lines, marker); - } + public static Statement createOrOverwriteFile(String path, Iterable lines, String delimeter) { + return CreateOrOverwriteFile.builder().path(path).lines(lines).delimeter(delimeter).build(); + } public static CreateRunScript createRunScript(String instanceName, Iterable exports, String pwd, - Iterable statements) {// TODO: convert so + Iterable statements) {// TODO: convert so // that // createRunScript // can take from a @@ -100,7 +106,8 @@ public class Statements { /** * - * Runs the script in a way that it can be matched later with {@link #findPid} + * Runs the script in a way that it can be matched later with + * {@link #findPid} * * @param instanceName * - what to match the process on @@ -118,7 +125,8 @@ public class Statements { } /** - * Kills the pid and subprocesses related to the variable {@code FOUND_PID} if set. + * Kills the pid and subprocesses related to the variable {@code FOUND_PID} + * if set. * * @see #findPid */ @@ -127,7 +135,8 @@ public class Statements { } /** - * statement can have multiple newlines, note you should use {@code lf} to be portable + * statement can have multiple newlines, note you should use {@code lf} to be + * portable * * @see ShellToken */ @@ -154,10 +163,14 @@ public class Statements { * @param directory */ public static Statement extractTargzIntoDirectory(String method, URI endpoint, Multimap headers, - String directory) { + String directory) { return new PipeHttpResponseToTarxpzfIntoDirectory(method, endpoint, headers, directory); } + public static Statement extractTargzIntoDirectory(URI targz, String directory) { + return extractTargzIntoDirectory("GET", targz, ImmutableMultimap. of(), directory); + } + /** * unzip the data received from the request parameters. * @@ -170,10 +183,14 @@ public class Statements { * @param directory */ public static Statement extractZipIntoDirectory(String method, URI endpoint, Multimap headers, - String directory) { + String directory) { return new UnzipHttpResponseIntoDirectory(method, endpoint, headers, directory); } + public static Statement saveHttpResponseTo(URI source, String dir, String file) { + return new SaveHttpResponseTo(dir, file, "GET", source, ImmutableMultimap. of()); + } + /** * exec the data received from the request parameters. * diff --git a/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/domain/SwitchArg.java b/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/domain/SwitchArg.java index 0b3154d38f..289ecc7243 100644 --- a/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/domain/SwitchArg.java +++ b/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/domain/SwitchArg.java @@ -94,11 +94,11 @@ public class SwitchArg implements Statement, AcceptsStatementVisitor { if (shouldIndent) actionBuilder.append(INDENT); actionBuilder.append(line).append(ShellToken.LF.to(family)); - if (line.indexOf(CreateRunScript.MARKER) != -1) { + if (line.indexOf(CreateRunScript.DELIMETER) != -1) { inRunScript = inRunScript ? false : true; } - if (line.indexOf(AppendFile.MARKER) != -1) { + if (line.indexOf(AppendFile.DELIMETER) != -1) { inCreateFile = inCreateFile ? false : true; } shouldIndent = !inCreateFile && !inRunScript; diff --git a/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/statements/java/InstallJDK.java b/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/statements/java/InstallJDK.java new file mode 100644 index 0000000000..30c040acf0 --- /dev/null +++ b/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/statements/java/InstallJDK.java @@ -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.scriptbuilder.statements.java; + +import static org.jclouds.scriptbuilder.domain.Statements.appendFile; +import static org.jclouds.scriptbuilder.domain.Statements.call; +import static org.jclouds.scriptbuilder.domain.Statements.exec; +import static org.jclouds.scriptbuilder.domain.Statements.extractTargzIntoDirectory; + +import java.net.URI; + +import org.jclouds.scriptbuilder.domain.Statement; +import org.jclouds.scriptbuilder.domain.StatementList; + +import com.google.common.collect.ImmutableSet; + +/** + * Installs a default JDK to a host + * + * @author Adrian Cole + */ +public class InstallJDK { + public static Statement fromURL() { + return new FromURL(); + } + + public static Statement fromURL(URI url) { + return new FromURL(url); + } + + public static class FromURL extends StatementList { + + public static final URI JDK7_URL = URI.create(System.getProperty("jdk7-url", + "http://download.oracle.com/otn-pub/java/jdk/7/jdk-7-linux-x64.tar.gz")); + + public FromURL() { + this(JDK7_URL); + } + + public static final ImmutableSet exportJavaHomeAndAddToPath = ImmutableSet.of( + "export JAVA_HOME=/usr/local/jdk", "export PATH=$JAVA_HOME/bin:$PATH"); + + public FromURL(URI jdk7Url) { + super(call("setupPublicCurl"), // + extractTargzIntoDirectory(jdk7Url, "/usr/local"),// + exec("mv /usr/local/jdk* /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")); + } + } +} \ No newline at end of file diff --git a/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/statements/login/AdminAccess.java b/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/statements/login/AdminAccess.java index c7c0bd4233..f222bc8b0b 100644 --- a/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/statements/login/AdminAccess.java +++ b/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/statements/login/AdminAccess.java @@ -19,27 +19,30 @@ package org.jclouds.scriptbuilder.statements.login; import static com.google.common.base.Charsets.UTF_8; +import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; import java.io.File; import java.io.IOException; import java.util.Map; -import org.jclouds.javax.annotation.Nullable; - import org.jclouds.crypto.Sha512Crypt; import org.jclouds.domain.Credentials; +import org.jclouds.javax.annotation.Nullable; import org.jclouds.scriptbuilder.domain.OsFamily; import org.jclouds.scriptbuilder.domain.Statement; import org.jclouds.scriptbuilder.domain.StatementList; import org.jclouds.scriptbuilder.statements.ssh.SshStatements; +import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Function; -import com.google.common.base.Preconditions; +import com.google.common.base.Predicates; import com.google.common.base.Supplier; import com.google.common.base.Throwables; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Iterables; +import com.google.common.collect.Lists; import com.google.common.io.Files; import com.google.inject.ImplementedBy; @@ -288,7 +291,8 @@ public class AdminAccess implements Statement { } } - private Config config; + @VisibleForTesting + Config config; protected AdminAccess(Config in) { this.config = checkNotNull(in, "in"); @@ -344,14 +348,19 @@ public class AdminAccess implements Statement { checkNotNull(family, "family"); if (family == OsFamily.WINDOWS) throw new UnsupportedOperationException("windows not yet implemented"); + checkArgument(!"root".equals(config.getAdminUsername()), "cannot create admin user 'root'; " + + "ensure jclouds is not running as root, or specify an explicit non-root username in AdminAccess"); + if (Iterables.any( + Lists.newArrayList(config.getAdminUsername(), config.getAdminPassword(), config.getAdminPublicKey(), + config.getAdminPrivateKey(), config.getLoginPassword()), Predicates.isNull())) + init(new DefaultConfiguration()); + checkNotNull(config.getAdminUsername(), "adminUsername"); - Preconditions.checkArgument(!"root".equals(config.getAdminUsername()), "cannot create admin user 'root'; " + - "ensure jclouds is not running as root, or specify an explicit non-root username in AdminAccess"); checkNotNull(config.getAdminPassword(), "adminPassword"); checkNotNull(config.getAdminPublicKey(), "adminPublicKey"); checkNotNull(config.getAdminPrivateKey(), "adminPrivateKey"); checkNotNull(config.getLoginPassword(), "loginPassword"); - + ImmutableList.Builder statements = ImmutableList. builder(); UserAdd.Builder userBuilder = UserAdd.builder(); userBuilder.login(config.getAdminUsername()); diff --git a/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/statements/login/Sudoers.java b/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/statements/login/Sudoers.java index fa61ba4763..6e2bab2ecf 100644 --- a/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/statements/login/Sudoers.java +++ b/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/statements/login/Sudoers.java @@ -19,7 +19,7 @@ package org.jclouds.scriptbuilder.statements.login; import static com.google.common.base.Preconditions.checkNotNull; -import static org.jclouds.scriptbuilder.domain.Statements.appendFile; +import static org.jclouds.scriptbuilder.domain.Statements.createOrOverwriteFile; import static org.jclouds.scriptbuilder.domain.Statements.exec; import org.jclouds.scriptbuilder.domain.OsFamily; @@ -45,8 +45,7 @@ public class Sudoers implements Statement { if (family == OsFamily.WINDOWS) throw new UnsupportedOperationException("windows not yet implemented"); Builder statements = ImmutableList. builder(); - statements.add(exec("{rm} " + sudoers)); - statements.add(appendFile(sudoers, ImmutableSet.of("root ALL = (ALL) ALL", "%wheel ALL = (ALL) NOPASSWD:ALL"))); + statements.add(createOrOverwriteFile(sudoers, ImmutableSet.of("root ALL = (ALL) ALL", "%wheel ALL = (ALL) NOPASSWD:ALL"))); statements.add(exec("chmod 0440 " + sudoers)); return new StatementList(statements.build()).render(family); } diff --git a/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/statements/ssh/SshdConfig.java b/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/statements/ssh/SshdConfig.java index f151e88b57..2264f89f91 100644 --- a/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/statements/ssh/SshdConfig.java +++ b/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/statements/ssh/SshdConfig.java @@ -49,7 +49,7 @@ public class SshdConfig implements Statement { Statement prependSshdConfig = exec(String.format( "exec 3<> %1$s && awk -v TEXT=\"%2$s\n\" 'BEGIN {print TEXT}{print}' %1$s >&3", sshdConfig, linesToPrepend)); - Statement reloadSshdConfig = exec("/etc/init.d/sshd reload||/etc/init.d/ssh reload"); + Statement reloadSshdConfig = exec("hash service 2>/dev/null && service ssh reload || /etc/init.d/ssh* reload"); return newStatementList(prependSshdConfig, reloadSshdConfig).render(family); } diff --git a/scriptbuilder/src/main/resources/functions/setupPublicCurl.sh b/scriptbuilder/src/main/resources/functions/setupPublicCurl.sh new file mode 100644 index 0000000000..005f891c83 --- /dev/null +++ b/scriptbuilder/src/main/resources/functions/setupPublicCurl.sh @@ -0,0 +1,50 @@ +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 +} diff --git a/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/InitBuilderTest.java b/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/InitBuilderTest.java index 86e0c3e372..0981d6b72b 100644 --- a/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/InitBuilderTest.java +++ b/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/InitBuilderTest.java @@ -18,8 +18,8 @@ */ package org.jclouds.scriptbuilder; -import static org.jclouds.scriptbuilder.domain.Statements.call; import static org.jclouds.scriptbuilder.domain.Statements.appendFile; +import static org.jclouds.scriptbuilder.domain.Statements.exec; import static org.testng.Assert.assertEquals; import java.io.IOException; @@ -45,48 +45,54 @@ import com.google.common.io.Resources; public class InitBuilderTest { InitBuilder testInitBuilder = new InitBuilder("mkebsboot", "/mnt/tmp", "/mnt/tmp", ImmutableMap.of("tmpDir", - "/mnt/tmp"), ImmutableList. of( - appendFile("{tmp}{fs}{uid}{fs}scripttest{fs}temp.txt", ImmutableList. of("hello world")), call("find /"))); + "/mnt/tmp"), ImmutableList. of( + appendFile("{tmp}{fs}{uid}{fs}scripttest{fs}temp.txt", ImmutableList. of("hello world")), + exec("find /"))); - @Test + @Test(expectedExceptions = UnsupportedOperationException.class) public void testBuildSimpleWindows() throws MalformedURLException, IOException { - assertEquals(testInitBuilder.render(OsFamily.WINDOWS), CharStreams.toString(Resources.newReaderSupplier(Resources - .getResource("test_init." + ShellToken.SH.to(OsFamily.WINDOWS)), Charsets.UTF_8))); + testInitBuilder.render(OsFamily.WINDOWS); } @Test public void testBuildSimpleUNIX() throws MalformedURLException, IOException { - assertEquals(testInitBuilder.render(OsFamily.UNIX), CharStreams.toString(Resources.newReaderSupplier(Resources - .getResource("test_init." + ShellToken.SH.to(OsFamily.UNIX)), Charsets.UTF_8))); + assertEquals( + testInitBuilder.render(OsFamily.UNIX), + CharStreams.toString(Resources.newReaderSupplier( + Resources.getResource("test_init." + ShellToken.SH.to(OsFamily.UNIX)), Charsets.UTF_8))); } @Test public void testBuildEBS() throws MalformedURLException, IOException { assertEquals( - 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"),// variables - // used - // inside - // of - // the - // script - ImmutableList. of(Statements.interpret("echo creating a filesystem and mounting the ebs volume",// what to execute - "{md} {varl}IMAGE_DIR{varr} {varl}EBS_MOUNT_POINT{varr}", - "rm -rf {varl}IMAGE_DIR{varr}/*", - "yes| mkfs -t ext3 {varl}EBS_DEVICE{varr} 2>&-", - "mount {varl}EBS_DEVICE{varr} {varl}EBS_MOUNT_POINT{varr}", - "echo making a local working copy of the boot disk", - "rsync -ax --exclude /ubuntu/.bash_history --exclude /home/*/.bash_history --exclude /etc/ssh/ssh_host_* --exclude /etc/ssh/moduli --exclude /etc/udev/rules.d/*persistent-net.rules --exclude /var/lib/ec2/* --exclude=/mnt/* --exclude=/proc/* --exclude=/tmp/* --exclude=/dev/log / {varl}IMAGE_DIR{varr}", - "echo preparing the local working copy", - "touch {varl}IMAGE_DIR{varr}/etc/init.d/ec2-init-user-data", - "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 ----COMPLETE----") - )).render(OsFamily.UNIX), CharStreams.toString(Resources.newReaderSupplier(Resources - .getResource("test_ebs." + ShellToken.SH.to(OsFamily.UNIX)), Charsets.UTF_8))); + 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"),// variables + // used + // inside + // of + // the + // script + ImmutableList. of(Statements + .interpret( + "echo creating a filesystem and mounting the ebs volume",// what + // to + // execute + "{md} {varl}IMAGE_DIR{varr} {varl}EBS_MOUNT_POINT{varr}", + "rm -rf {varl}IMAGE_DIR{varr}/*", + "yes| mkfs -t ext3 {varl}EBS_DEVICE{varr} 2>&-", + "mount {varl}EBS_DEVICE{varr} {varl}EBS_MOUNT_POINT{varr}", + "echo making a local working copy of the boot disk", + "rsync -ax --exclude /ubuntu/.bash_history --exclude /home/*/.bash_history --exclude /etc/ssh/ssh_host_* --exclude /etc/ssh/moduli --exclude /etc/udev/rules.d/*persistent-net.rules --exclude /var/lib/ec2/* --exclude=/mnt/* --exclude=/proc/* --exclude=/tmp/* --exclude=/dev/log / {varl}IMAGE_DIR{varr}", + "echo preparing the local working copy", + "touch {varl}IMAGE_DIR{varr}/etc/init.d/ec2-init-user-data", + "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 ----COMPLETE----"))).render(OsFamily.UNIX), + CharStreams.toString(Resources.newReaderSupplier( + Resources.getResource("test_ebs." + ShellToken.SH.to(OsFamily.UNIX)), Charsets.UTF_8))); } } diff --git a/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/InitScriptTest.java b/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/InitScriptTest.java new file mode 100644 index 0000000000..51e407b5a2 --- /dev/null +++ b/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/InitScriptTest.java @@ -0,0 +1,105 @@ +/** + * 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.scriptbuilder; + +import static org.jclouds.scriptbuilder.domain.Statements.appendFile; +import static org.jclouds.scriptbuilder.domain.Statements.call; +import static org.jclouds.scriptbuilder.domain.Statements.exec; +import static org.jclouds.scriptbuilder.domain.Statements.interpret; +import static org.testng.Assert.assertEquals; + +import java.io.IOException; +import java.net.MalformedURLException; + +import org.jclouds.scriptbuilder.domain.OsFamily; +import org.jclouds.scriptbuilder.domain.ShellToken; +import org.testng.annotations.Test; + +import com.google.common.base.Charsets; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.common.io.CharStreams; +import com.google.common.io.Resources; + +/** + * Tests possible uses of InitScript + * + * @author Adrian Cole + */ +public class InitScriptTest { + InitScript testInitScript = InitScript + .builder() + .name("mkebsboot") + .home("/mnt/tmp") + .exportVariables(ImmutableMap.of("tmpDir", "/mnt/tmp")) + .run(appendFile("{tmp}{fs}{uid}{fs}scripttest{fs}temp.txt", ImmutableList. of("hello world")), + exec("find /")).build(); + + public void testBuildSimpleWindows() throws MalformedURLException, IOException { + assertEquals( + testInitScript.render(OsFamily.WINDOWS), + CharStreams.toString(Resources.newReaderSupplier( + Resources.getResource("test_init." + ShellToken.SH.to(OsFamily.WINDOWS)), Charsets.UTF_8))); + } + + public void testBuildSimpleUNIX() throws MalformedURLException, IOException { + assertEquals( + testInitScript.render(OsFamily.UNIX), + CharStreams.toString(Resources.newReaderSupplier( + Resources.getResource("test_init." + ShellToken.SH.to(OsFamily.UNIX)), Charsets.UTF_8))); + } + + public void testBuildEBS() throws MalformedURLException, IOException { + assertEquals(InitScript + .builder() + .name("mkebsboot") + .home("tmp") + .logDir("/tmp/logs") + .exportVariables(ImmutableMap.of("imageDir", "/mnt/tmp", "ebsDevice", "/dev/sdh", "ebsMountPoint", "/mnt/ebs")) + .run(interpret( + "echo creating a filesystem and mounting the ebs volume", + "{md} {varl}IMAGE_DIR{varr} {varl}EBS_MOUNT_POINT{varr}", + "rm -rf {varl}IMAGE_DIR{varr}/*", + "yes| mkfs -t ext3 {varl}EBS_DEVICE{varr} 2>&-", + "mount {varl}EBS_DEVICE{varr} {varl}EBS_MOUNT_POINT{varr}", + "echo making a local working copy of the boot disk", + "rsync -ax --exclude /ubuntu/.bash_history --exclude /home/*/.bash_history --exclude /etc/ssh/ssh_host_* --exclude /etc/ssh/moduli --exclude /etc/udev/rules.d/*persistent-net.rules --exclude /var/lib/ec2/* --exclude=/mnt/* --exclude=/proc/* --exclude=/tmp/* --exclude=/dev/log / {varl}IMAGE_DIR{varr}", + "echo preparing the local working copy", + "touch {varl}IMAGE_DIR{varr}/etc/init.d/ec2-init-user-data", + "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 ----COMPLETE----")).build().render(OsFamily.UNIX), + CharStreams.toString(Resources.newReaderSupplier( + Resources.getResource("test_ebs." + ShellToken.SH.to(OsFamily.UNIX)), Charsets.UTF_8))); + } + + InitScript testCallInRun = InitScript.builder().name("testcall").init(exec("echo hello")) + .run(call("sourceEnvFile", "foo"), exec("find /")).build(); + + @Test + public void testCallInRunUNIX() throws MalformedURLException, IOException { + assertEquals( + testCallInRun.render(OsFamily.UNIX), + CharStreams.toString(Resources.newReaderSupplier( + Resources.getResource("test_init_script." + ShellToken.SH.to(OsFamily.UNIX)), Charsets.UTF_8))); + } + +} diff --git a/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/ScriptBuilderTest.java b/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/ScriptBuilderTest.java index 5c8e727db9..2710927bfc 100644 --- a/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/ScriptBuilderTest.java +++ b/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/ScriptBuilderTest.java @@ -18,9 +18,9 @@ */ package org.jclouds.scriptbuilder; -import static org.jclouds.scriptbuilder.domain.Statements.call; +import static org.jclouds.scriptbuilder.ScriptBuilder.call; +import static org.jclouds.scriptbuilder.ScriptBuilder.findPid; import static org.jclouds.scriptbuilder.domain.Statements.appendFile; -import static org.jclouds.scriptbuilder.domain.Statements.findPid; import static org.jclouds.scriptbuilder.domain.Statements.interpret; import static org.jclouds.scriptbuilder.domain.Statements.kill; import static org.jclouds.scriptbuilder.domain.Statements.newStatementList; @@ -49,50 +49,53 @@ import com.google.common.io.Resources; public class ScriptBuilderTest { ScriptBuilder testScriptBuilder = new ScriptBuilder() - .unsetEnvironmentVariable("runtime") - .addEnvironmentVariableScope("default", ImmutableMap.of("runtime", "Moo")) - .addStatement( - switchArg( - 1, - ImmutableMap - .of( - "start", - newStatementList(call("default"), - interpret("echo start {varl}RUNTIME{varr}{lf}")), - "stop", - newStatementList(call("default"), - interpret("echo stop {varl}RUNTIME{varr}{lf}")), - "status", - newStatementList( - appendFile("{tmp}{fs}{uid}{fs}scripttest{fs}temp.txt", - ImmutableList. of("hello world")), - interpret("echo {vq}the following should be []: [{varl}RUNTIME{varr}]{vq}{lf}"))))); + .unsetEnvironmentVariable("runtime") + .addEnvironmentVariableScope("default", ImmutableMap.of("runtime", "Moo")) + .addStatement( + switchArg(1, ImmutableMap.of( + "start", + newStatementList(call("default"), interpret("echo start {varl}RUNTIME{varr}{lf}")), + "stop", + newStatementList(call("default"), interpret("echo stop {varl}RUNTIME{varr}{lf}")), + "status", + newStatementList( + appendFile("{tmp}{fs}{uid}{fs}scripttest{fs}temp.txt", + ImmutableList. of("hello world")), + interpret("echo {vq}the following should be []: [{varl}RUNTIME{varr}]{vq}{lf}"))))); @Test public void testBuildSimpleWindows() throws MalformedURLException, IOException { - assertEquals(testScriptBuilder.render(OsFamily.WINDOWS), CharStreams.toString(Resources.newReaderSupplier( - Resources.getResource("test_script." + ShellToken.SH.to(OsFamily.WINDOWS)), Charsets.UTF_8))); + assertEquals( + testScriptBuilder.render(OsFamily.WINDOWS), + CharStreams.toString(Resources.newReaderSupplier( + Resources.getResource("test_script." + ShellToken.SH.to(OsFamily.WINDOWS)), Charsets.UTF_8))); } @Test public void testBuildSimpleUNIX() throws MalformedURLException, IOException { - assertEquals(testScriptBuilder.render(OsFamily.UNIX), CharStreams.toString(Resources.newReaderSupplier(Resources - .getResource("test_script." + ShellToken.SH.to(OsFamily.UNIX)), Charsets.UTF_8))); + assertEquals( + testScriptBuilder.render(OsFamily.UNIX), + CharStreams.toString(Resources.newReaderSupplier( + Resources.getResource("test_script." + ShellToken.SH.to(OsFamily.UNIX)), Charsets.UTF_8))); } ScriptBuilder findPidBuilder = new ScriptBuilder().addStatement(findPid("{args}")).addStatement( - interpret("echo {varl}FOUND_PID{varr}{lf}")); + interpret("echo {varl}FOUND_PID{varr}{lf}")); @Test public void testFindPidWindows() throws MalformedURLException, IOException { - assertEquals(findPidBuilder.render(OsFamily.WINDOWS), CharStreams.toString(Resources.newReaderSupplier(Resources - .getResource("test_find_pid." + ShellToken.SH.to(OsFamily.WINDOWS)), Charsets.UTF_8))); + assertEquals( + findPidBuilder.render(OsFamily.WINDOWS), + CharStreams.toString(Resources.newReaderSupplier( + Resources.getResource("test_find_pid." + ShellToken.SH.to(OsFamily.WINDOWS)), Charsets.UTF_8))); } @Test public void testFindPidUNIX() throws MalformedURLException, IOException { - assertEquals(findPidBuilder.render(OsFamily.UNIX), CharStreams.toString(Resources.newReaderSupplier(Resources - .getResource("test_find_pid." + ShellToken.SH.to(OsFamily.UNIX)), Charsets.UTF_8))); + assertEquals( + findPidBuilder.render(OsFamily.UNIX), + CharStreams.toString(Resources.newReaderSupplier( + Resources.getResource("test_find_pid." + ShellToken.SH.to(OsFamily.UNIX)), Charsets.UTF_8))); } ScriptBuilder seekAndDestroyBuilder = new ScriptBuilder().addStatement(findPid("{args}")).addStatement(kill()); @@ -100,22 +103,24 @@ public class ScriptBuilderTest { @Test public void testSeekAndDestroyWindows() throws MalformedURLException, IOException { assertEquals(seekAndDestroyBuilder.render(OsFamily.WINDOWS), CharStreams.toString(Resources.newReaderSupplier( - Resources.getResource("test_seek_and_destroy." + ShellToken.SH.to(OsFamily.WINDOWS)), Charsets.UTF_8))); + Resources.getResource("test_seek_and_destroy." + ShellToken.SH.to(OsFamily.WINDOWS)), Charsets.UTF_8))); } @Test public void testSeekAndDestroyUNIX() throws MalformedURLException, IOException { - assertEquals(seekAndDestroyBuilder.render(OsFamily.UNIX), CharStreams.toString(Resources.newReaderSupplier( - Resources.getResource("test_seek_and_destroy." + ShellToken.SH.to(OsFamily.UNIX)), Charsets.UTF_8))); + assertEquals( + seekAndDestroyBuilder.render(OsFamily.UNIX), + CharStreams.toString(Resources.newReaderSupplier( + Resources.getResource("test_seek_and_destroy." + ShellToken.SH.to(OsFamily.UNIX)), Charsets.UTF_8))); } @Test public void testSwitchOn() { ScriptBuilder builder = new ScriptBuilder(); - builder.addStatement(switchArg(1, ImmutableMap.of("start", interpret("echo started{lf}"), "stop", - interpret("echo stopped{lf}")))); + builder.addStatement(switchArg(1, + ImmutableMap.of("start", interpret("echo started{lf}"), "stop", interpret("echo stopped{lf}")))); assertEquals(builder.statements, ImmutableList.of(new SwitchArg(1, ImmutableMap.of("start", - interpret("echo started{lf}"), "stop", interpret("echo stopped{lf}"))))); + interpret("echo started{lf}"), "stop", interpret("echo stopped{lf}"))))); } @Test diff --git a/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/domain/CreateRunScriptTest.java b/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/domain/CreateRunScriptTest.java index 3a404c2372..f984e974be 100644 --- a/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/domain/CreateRunScriptTest.java +++ b/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/domain/CreateRunScriptTest.java @@ -18,7 +18,7 @@ */ package org.jclouds.scriptbuilder.domain; -import static org.jclouds.scriptbuilder.domain.Statements.call; +import static org.jclouds.scriptbuilder.domain.Statements.exec; import static org.jclouds.scriptbuilder.domain.Statements.appendFile; import static org.jclouds.scriptbuilder.domain.Statements.createRunScript; import static org.testng.Assert.assertEquals; @@ -43,26 +43,19 @@ public class CreateRunScriptTest { "{tmp}{fs}{uid}{fs}scripttest", ImmutableList . of( - call("echo hello"), + exec("echo hello"), appendFile("{tmp}{fs}{uid}{fs}scripttest{fs}temp.txt", ImmutableList . of("hello world")), - call("echo {varl}JAVA_HOME{varr}{fs}bin{fs}java -DinstanceName={varl}INSTANCE_NAME{varr} myServer.Main"))); + exec("echo {varl}JAVA_HOME{varr}{fs}bin{fs}java -DinstanceName={varl}INSTANCE_NAME{varr} myServer.Main"))); public void testUNIX() throws IOException { assertEquals(statement.render(OsFamily.UNIX), CharStreams.toString(Resources.newReaderSupplier(Resources .getResource("test_runrun." + ShellToken.SH.to(OsFamily.UNIX)), Charsets.UTF_8))); } - public void testWINDOWS() throws IOException { - assertEquals(statement.render(OsFamily.WINDOWS), CharStreams.toString(Resources.newReaderSupplier(Resources - .getResource("test_runrun." + ShellToken.SH.to(OsFamily.WINDOWS)), Charsets.UTF_8))); - } - - public void testRedirectGuard() { - assertEquals(CreateRunScript.addSpaceToEnsureWeDontAccidentallyRedirectFd("foo>>"), "foo>>"); - assertEquals(CreateRunScript.addSpaceToEnsureWeDontAccidentallyRedirectFd("foo0>>"), "foo0 >>"); - assertEquals(CreateRunScript.addSpaceToEnsureWeDontAccidentallyRedirectFd("foo1>>"), "foo1 >>"); - assertEquals(CreateRunScript.addSpaceToEnsureWeDontAccidentallyRedirectFd("foo2>>"), "foo2 >>"); + @Test(expectedExceptions = UnsupportedOperationException.class) + public void testWINDOWSUnimplemented() throws IOException { + statement.render(OsFamily.WINDOWS); } } diff --git a/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/domain/SaveHttpResponseToTest.java b/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/domain/SaveHttpResponseToTest.java new file mode 100644 index 0000000000..ed5e950b15 --- /dev/null +++ b/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/domain/SaveHttpResponseToTest.java @@ -0,0 +1,45 @@ +/** + * 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.scriptbuilder.domain; + +import static org.testng.Assert.assertEquals; + +import java.net.URI; + +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableMultimap; + +/** + * @author Adrian Cole + */ +@Test(groups = "unit", testName = "SaveHttpResponseToTest") +public class SaveHttpResponseToTest { + + public void testSaveHttpResponseToDirAndFileUNIX() { + SaveHttpResponseTo testWithDir = new SaveHttpResponseTo("/tmp", "install", "GET", + URI.create("https://adriancolehappy.s3.amazonaws.com/java/install"), ImmutableMultimap.of("Host", + "adriancolehappy.s3.amazonaws.com", "Date", "Sun, 12 Sep 2010 08:25:19 GMT", "Authorization", + "AWS 0ASHDJAS82:JASHFDA=")); + assertEquals( + testWithDir.render(OsFamily.UNIX), + "(mkdir -p /tmp && cd /tmp && [ ! -f install ] && curl -q -s -S -L --connect-timeout 10 --max-time 600 --retry 20 -C - -X GET -H \"Host: adriancolehappy.s3.amazonaws.com\" -H \"Date: Sun, 12 Sep 2010 08:25:19 GMT\" -H \"Authorization: AWS 0ASHDJAS82:JASHFDA=\" https://adriancolehappy.s3.amazonaws.com/java/install >install)\n"); + } + +} diff --git a/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/domain/ShellTokenTest.java b/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/domain/ShellTokenTest.java index a5edfd2756..5c7c6cbf6a 100644 --- a/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/domain/ShellTokenTest.java +++ b/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/domain/ShellTokenTest.java @@ -40,9 +40,9 @@ public class ShellTokenTest { "args", "$@").put("varl", "$").put("return", "return").put("exit", "exit").put( "varr", "").put("libraryPathVariable", "LD_LIBRARY_PATH").put("beginScript", "#!/bin/bash\nset +u\nshopt -s xpg_echo\nshopt -s expand_aliases\n").put( - "endScript", "exit 0\n").put("vq", "\"").put("beginFunctions", "").put( + "endScript", "exit $?\n").put("vq", "\"").put("beginFunctions", "").put( "endFunctions", "").put("fncl", "function ").put("fncr", " {\n").put("fnce", - " return 0\n}\n").put("export", "export").put("rm", "rm").put("cd", "cd").put( + " return $?\n}\n").put("export", "export").put("rm", "rm").put("cd", "cd").put( "tmp", "/tmp").put("uid", "$USER").put("root", "/").put("closeFd", ">&-").put("md", "mkdir -p").put("escvar", "\\").build(); assertEquals(ShellToken.tokenValueMap(OsFamily.UNIX), expected); diff --git a/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/domain/StatementsTest.java b/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/domain/StatementsTest.java new file mode 100644 index 0000000000..af30767aba --- /dev/null +++ b/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/domain/StatementsTest.java @@ -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.scriptbuilder.domain; + +import static org.testng.Assert.assertEquals; + +import java.net.URI; + +import org.testng.annotations.Test; + +/** + * @author Adrian Cole + */ +@Test(groups = "unit", testName = "StatementsTest") +public class StatementsTest { + + public void testSaveHttpResponseToUNIX() { + Statement save = Statements.saveHttpResponseTo( + URI.create("https://s3.amazonaws.com/MinecraftDownload/launcher/minecraft_server.jar"), "/opt/minecraft", + "minecraft_server.jar"); + assertEquals( + save.render(OsFamily.UNIX), + "(mkdir -p /opt/minecraft && cd /opt/minecraft && [ ! -f minecraft_server.jar ] && curl -q -s -S -L --connect-timeout 10 --max-time 600 --retry 20 -C - -X GET https://s3.amazonaws.com/MinecraftDownload/launcher/minecraft_server.jar >minecraft_server.jar)\n"); + } + + public void testExtractTargzIntoDirectoryUNIX() { + Statement save = Statements + .extractTargzIntoDirectory( + URI.create("https://s3.amazonaws.com/MinecraftDownload/launcher/minecraft_server.tar.gz"), + "/opt/minecraft"); + assertEquals( + save.render(OsFamily.UNIX), + "curl -q -s -S -L --connect-timeout 10 --max-time 600 --retry 20 -X GET https://s3.amazonaws.com/MinecraftDownload/launcher/minecraft_server.tar.gz |(mkdir -p /opt/minecraft &&cd /opt/minecraft &&tar -xpzf -)\n"); + } + +} diff --git a/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/domain/SwitchArgTest.java b/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/domain/SwitchArgTest.java index e7407640dc..fdde97d12c 100644 --- a/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/domain/SwitchArgTest.java +++ b/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/domain/SwitchArgTest.java @@ -39,7 +39,17 @@ public class SwitchArgTest { assertEquals(new SwitchArg(1, ImmutableMap.of("0", newStatementList(appendFile( "{tmp}{fs}{uid}{fs}scripttest{fs}temp.txt", Collections.singleton("hello world")), interpret("echo hello zero{lf}")), "1", interpret("echo hello one{lf}"))).render(OsFamily.UNIX), - "case $1 in\n0)\n cat >> /tmp/$USER/scripttest/temp.txt <<'END_OF_FILE'\nhello world\nEND_OF_FILE\n echo hello zero\n ;;\n1)\n echo hello one\n ;;\nesac\n"); + "case $1 in\n"+ + "0)\n"+ + " cat >> /tmp/$USER/scripttest/temp.txt <<-'END_OF_JCLOUDS_FILE'\n"+ + "\thello world\n"+ + "END_OF_JCLOUDS_FILE\n"+ + " echo hello zero\n"+ + " ;;\n"+ + "1)\n"+ + " echo hello one\n"+ + " ;;\n"+ + "esac\n"); } public void testSwitchArgWindows() { diff --git a/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/functions/CredentialsFromAdminAccessTest.java b/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/functions/CredentialsFromAdminAccessTest.java index 3088d6622f..e2dc7f91a4 100644 --- a/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/functions/CredentialsFromAdminAccessTest.java +++ b/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/functions/CredentialsFromAdminAccessTest.java @@ -18,20 +18,19 @@ */ package org.jclouds.scriptbuilder.functions; +import static org.easymock.EasyMock.createMock; 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.replay; +import static org.easymock.EasyMock.verify; import static org.testng.Assert.assertEquals; import org.jclouds.domain.Credentials; -import org.jclouds.scriptbuilder.InitBuilder; +import org.jclouds.scriptbuilder.InitScript; import org.jclouds.scriptbuilder.domain.Statement; import org.jclouds.scriptbuilder.domain.Statements; import org.jclouds.scriptbuilder.statements.login.AdminAccess; import org.testng.annotations.Test; -import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; /** @@ -97,8 +96,8 @@ public class CredentialsFromAdminAccessTest { replay(statement); replay(creds); - InitBuilder testInitBuilder = new InitBuilder("mkebsboot", "/mnt/tmp", "/mnt/tmp", ImmutableMap.of("tmpDir", - "/mnt/tmp"), ImmutableList. of(statement)); + InitScript testInitBuilder = InitScript.builder().name("mkebsboot").home("/mnt/tmp") + .exportVariables(ImmutableMap.of("tmpDir", "/mnt/tmp")).run(statement).build(); assertEquals(CredentialsFromAdminAccess.INSTANCE.apply(testInitBuilder), creds); diff --git a/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/functions/InitAdminAccessTest.java b/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/functions/InitAdminAccessTest.java index 5a007d95a8..f57e1aea6a 100644 --- a/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/functions/InitAdminAccessTest.java +++ b/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/functions/InitAdminAccessTest.java @@ -18,18 +18,16 @@ */ package org.jclouds.scriptbuilder.functions; +import static org.easymock.EasyMock.createMock; 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.replay; +import static org.easymock.EasyMock.verify; -import org.jclouds.scriptbuilder.InitBuilder; -import org.jclouds.scriptbuilder.domain.Statement; +import org.jclouds.scriptbuilder.InitScript; import org.jclouds.scriptbuilder.domain.Statements; import org.jclouds.scriptbuilder.statements.login.AdminAccess; import org.testng.annotations.Test; -import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; /** @@ -100,9 +98,9 @@ public class InitAdminAccessTest { replay(configuration); replay(statement); replay(newStatement); - - InitBuilder testInitBuilder = new InitBuilder("mkebsboot", "/mnt/tmp", "/mnt/tmp", ImmutableMap.of("tmpDir", - "/mnt/tmp"), ImmutableList. of(statement)); + + InitScript testInitBuilder = InitScript.builder().name("mkebsboot").home("/mnt/tmp") + .exportVariables(ImmutableMap.of("tmpDir", "/mnt/tmp")).run(statement).build(); InitAdminAccess initAdminAccess = new InitAdminAccess(configuration); diff --git a/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/statements/java/InstallJDKTest.java b/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/statements/java/InstallJDKTest.java new file mode 100644 index 0000000000..4730ffbc6a --- /dev/null +++ b/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/statements/java/InstallJDKTest.java @@ -0,0 +1,65 @@ +/** + * 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.scriptbuilder.statements.java; + +import static org.testng.Assert.assertEquals; + +import java.io.IOException; +import java.net.URI; + +import org.jclouds.scriptbuilder.InitScript; +import org.jclouds.scriptbuilder.domain.OsFamily; +import org.jclouds.scriptbuilder.domain.ShellToken; +import org.jclouds.scriptbuilder.domain.Statement; +import org.testng.annotations.Test; + +import com.google.common.base.Charsets; +import com.google.common.io.CharStreams; +import com.google.common.io.Resources; + +/** + * @author Adrian Cole + */ +@Test(groups = "unit", testName = "InstallJDKTest") +public class InstallJDKTest { + + Statement installJDK = InstallJDK.fromURL(); + + public void testInstallJDKUNIX() throws IOException { + assertEquals(InstallJDK.fromURL().render(OsFamily.UNIX), CharStreams.toString(Resources.newReaderSupplier( + Resources.getResource("test_install_jdk_from_url." + ShellToken.SH.to(OsFamily.UNIX)), Charsets.UTF_8))); + } + + public void testInstallJDKUNIXInScriptBuilderSourcesSetupPublicCurl() throws IOException { + assertEquals(InitScript.builder().name("install_jdk").run(InstallJDK.fromURL()).build().render(OsFamily.UNIX), + CharStreams.toString(Resources.newReaderSupplier( + Resources.getResource("test_install_jdk_scriptbuilder." + ShellToken.SH.to(OsFamily.UNIX)), + Charsets.UTF_8))); + } + + public void testInstallJDKUNIXWithURL() throws IOException { + assertEquals( + InstallJDK.fromURL(URI.create("http://foo")).render(OsFamily.UNIX), + CharStreams.toString( + Resources.newReaderSupplier( + Resources.getResource("test_install_jdk_from_url." + ShellToken.SH.to(OsFamily.UNIX)), + Charsets.UTF_8)).replace(InstallJDK.FromURL.JDK7_URL.toASCIIString(), "http://foo")); + } + +} diff --git a/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/statements/login/AdminAccessTest.java b/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/statements/login/AdminAccessTest.java index c3c599293b..0d389fec19 100644 --- a/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/statements/login/AdminAccessTest.java +++ b/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/statements/login/AdminAccessTest.java @@ -19,6 +19,7 @@ package org.jclouds.scriptbuilder.statements.login; import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; import java.io.IOException; @@ -76,9 +77,9 @@ public class AdminAccessTest { public void testCreateWheelWindowsNotSupported() { AdminAccess.standard().init(TestConfiguration.INSTANCE).render(OsFamily.WINDOWS); } - - @Test(expectedExceptions=IllegalArgumentException.class) - //for issue 682 + + @Test(expectedExceptions = IllegalArgumentException.class) + // for issue 682 public void testRootNotAllowed() throws IOException { TestConfiguration.INSTANCE.reset(); try { @@ -88,4 +89,34 @@ public class AdminAccessTest { } } + @Test(expectedExceptions = NullPointerException.class) + public void testFamilyRequiredAllowed() throws IOException { + AdminAccess.standard().render(null); + } + + public void testWhenUninitializedLazyInitWithDefaultConfiguration() throws IOException { + AdminAccess access = AdminAccess.standard(); + // before rendered, holder is empty + assertEquals(access.config.getAdminUsername(), null); + assertEquals(access.config.getAdminPassword(), null); + assertEquals(access.config.getAdminPublicKey(), null); + assertEquals(access.config.getAdminPrivateKey(), null); + assertEquals(access.config.getLoginPassword(), null); + access.render(OsFamily.UNIX); + // DefaultConfiguration + try { + assertEquals(access.config.getAdminUsername(), System.getProperty("user.name")); + assertNotNull(access.config.getAdminPassword()); + assertNotNull(access.config.getAdminPublicKey()); + assertNotNull(access.config.getAdminPrivateKey()); + assertNotNull(access.config.getLoginPassword()); + } catch (AssertionError e) { + throw e; + } catch (Throwable e) { + // we are catching throwables here, in case the test runner doesn't + // have ssh keys setup + } + + } + } diff --git a/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/statements/login/SudoStatementsTest.java b/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/statements/login/SudoStatementsTest.java index 3364297b18..afbf0d4a91 100644 --- a/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/statements/login/SudoStatementsTest.java +++ b/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/statements/login/SudoStatementsTest.java @@ -32,7 +32,11 @@ public class SudoStatementsTest { public void testCreateWheelUNIX() { assertEquals( SudoStatements.createWheel().render(OsFamily.UNIX), - "rm /etc/sudoers\ncat >> /etc/sudoers <<'END_OF_FILE'\nroot ALL = (ALL) ALL\n%wheel ALL = (ALL) NOPASSWD:ALL\nEND_OF_FILE\nchmod 0440 /etc/sudoers\n"); + "cat > /etc/sudoers <<-'END_OF_JCLOUDS_FILE'\n"+ + "\troot ALL = (ALL) ALL\n"+ + "\t%wheel ALL = (ALL) NOPASSWD:ALL\n"+ + "END_OF_JCLOUDS_FILE\n"+ + "chmod 0440 /etc/sudoers\n"); } @Test(expectedExceptions = UnsupportedOperationException.class) diff --git a/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/statements/login/UserAddTest.java b/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/statements/login/UserAddTest.java index ac570a1eb9..e9d6bf3ecc 100644 --- a/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/statements/login/UserAddTest.java +++ b/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/statements/login/UserAddTest.java @@ -61,13 +61,13 @@ public class UserAddTest { public void testWithSshAuthorizedKeyUNIX() { assertEquals( UserAdd.builder().login("me").authorizeRSAPublicKey("rsapublickey").build().render(OsFamily.UNIX), - "mkdir -p /home/users\nuseradd -s /bin/bash -m -d /home/users/me me\nmkdir -p /home/users/me/.ssh\ncat >> /home/users/me/.ssh/authorized_keys <<'END_OF_FILE'\nrsapublickey\nEND_OF_FILE\nchmod 600 /home/users/me/.ssh/authorized_keys\nchown -R me /home/users/me\n"); + "mkdir -p /home/users\nuseradd -s /bin/bash -m -d /home/users/me me\nmkdir -p /home/users/me/.ssh\ncat >> /home/users/me/.ssh/authorized_keys <<-'END_OF_JCLOUDS_FILE'\n\trsapublickey\nEND_OF_JCLOUDS_FILE\nchmod 600 /home/users/me/.ssh/authorized_keys\nchown -R me /home/users/me\n"); } public void testWithSshInstalledKeyUNIX() { assertEquals( UserAdd.builder().login("me").installRSAPrivateKey("rsaprivate").build().render(OsFamily.UNIX), - "mkdir -p /home/users\nuseradd -s /bin/bash -m -d /home/users/me me\nmkdir -p /home/users/me/.ssh\nrm /home/users/me/.ssh/id_rsa\ncat >> /home/users/me/.ssh/id_rsa <<'END_OF_FILE'\nrsaprivate\nEND_OF_FILE\nchmod 600 /home/users/me/.ssh/id_rsa\nchown -R me /home/users/me\n"); + "mkdir -p /home/users\nuseradd -s /bin/bash -m -d /home/users/me me\nmkdir -p /home/users/me/.ssh\nrm /home/users/me/.ssh/id_rsa\ncat >> /home/users/me/.ssh/id_rsa <<-'END_OF_JCLOUDS_FILE'\n\trsaprivate\nEND_OF_JCLOUDS_FILE\nchmod 600 /home/users/me/.ssh/id_rsa\nchown -R me /home/users/me\n"); } @Test(expectedExceptions = UnsupportedOperationException.class) diff --git a/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/statements/ssh/AuthorizeRSAPublicKeyTest.java b/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/statements/ssh/AuthorizeRSAPublicKeyTest.java index 4c17a66dd1..4a772301db 100644 --- a/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/statements/ssh/AuthorizeRSAPublicKeyTest.java +++ b/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/statements/ssh/AuthorizeRSAPublicKeyTest.java @@ -34,26 +34,46 @@ public class AuthorizeRSAPublicKeyTest { public void testAuthorizeRSAPublicKeyUNIXCurrentUser() { assertEquals( new AuthorizeRSAPublicKeys(ImmutableSet.of("ssh-dss AAAAB")).render(OsFamily.UNIX), - "mkdir -p ~/.ssh\ncat >> ~/.ssh/authorized_keys <<'END_OF_FILE'\nssh-dss AAAAB\nEND_OF_FILE\nchmod 600 ~/.ssh/authorized_keys\n"); + "mkdir -p ~/.ssh\n"+ + "cat >> ~/.ssh/authorized_keys <<-'END_OF_JCLOUDS_FILE'\n"+ + "\tssh-dss AAAAB\n"+ + "END_OF_JCLOUDS_FILE\n"+ + "chmod 600 ~/.ssh/authorized_keys\n"); } public void testAuthorizeRSAPublicKeyUNIXCurrentUserWith2Keys() { assertEquals( new AuthorizeRSAPublicKeys(ImmutableSet.of("ssh-dss AAAAB", "ssh-dss CCCCD")).render(OsFamily.UNIX), - "mkdir -p ~/.ssh\ncat >> ~/.ssh/authorized_keys <<'END_OF_FILE'\nssh-dss AAAAB\n\nssh-dss CCCCD\nEND_OF_FILE\nchmod 600 ~/.ssh/authorized_keys\n"); + "mkdir -p ~/.ssh\n"+ + "cat >> ~/.ssh/authorized_keys <<-'END_OF_JCLOUDS_FILE'\n"+ + "\tssh-dss AAAAB\n"+ + "\t\n"+ + "\tssh-dss CCCCD\n"+ + "END_OF_JCLOUDS_FILE\n"+ + "chmod 600 ~/.ssh/authorized_keys\n"); } public void testAuthorizeRSAPublicKeyUNIXSpecifiedDir() { assertEquals( new AuthorizeRSAPublicKeys("/home/me/.ssh", ImmutableSet.of("ssh-dss AAAAB")).render(OsFamily.UNIX), - "mkdir -p /home/me/.ssh\ncat >> /home/me/.ssh/authorized_keys <<'END_OF_FILE'\nssh-dss AAAAB\nEND_OF_FILE\nchmod 600 /home/me/.ssh/authorized_keys\n"); + "mkdir -p /home/me/.ssh\n"+ + "cat >> /home/me/.ssh/authorized_keys <<-'END_OF_JCLOUDS_FILE'\n"+ + "\tssh-dss AAAAB\n"+ + "END_OF_JCLOUDS_FILE\n"+ + "chmod 600 /home/me/.ssh/authorized_keys\n"); } public void testAuthorizeRSAPublicKeyUNIXSpecifiedDirWith2Keys() { assertEquals( new AuthorizeRSAPublicKeys("/home/me/.ssh", ImmutableSet.of("ssh-dss AAAAB", "ssh-dss CCCCD")) .render(OsFamily.UNIX), - "mkdir -p /home/me/.ssh\ncat >> /home/me/.ssh/authorized_keys <<'END_OF_FILE'\nssh-dss AAAAB\n\nssh-dss CCCCD\nEND_OF_FILE\nchmod 600 /home/me/.ssh/authorized_keys\n"); + "mkdir -p /home/me/.ssh\n"+ + "cat >> /home/me/.ssh/authorized_keys <<-'END_OF_JCLOUDS_FILE'\n"+ + "\tssh-dss AAAAB\n"+ + "\t\n"+ + "\tssh-dss CCCCD\n"+ + "END_OF_JCLOUDS_FILE\n"+ + "chmod 600 /home/me/.ssh/authorized_keys\n"); } @Test(expectedExceptions = UnsupportedOperationException.class) diff --git a/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/statements/ssh/InstallRSAPrivateKeyTest.java b/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/statements/ssh/InstallRSAPrivateKeyTest.java index 2e9f3b2990..3fd7809097 100644 --- a/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/statements/ssh/InstallRSAPrivateKeyTest.java +++ b/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/statements/ssh/InstallRSAPrivateKeyTest.java @@ -33,15 +33,28 @@ public class InstallRSAPrivateKeyTest { assertEquals( new InstallRSAPrivateKey("-----BEGIN RSA PRIVATE KEY-----\n-----END RSA PRIVATE KEY-----\n") .render(OsFamily.UNIX), - "mkdir -p ~/.ssh\nrm ~/.ssh/id_rsa\ncat >> ~/.ssh/id_rsa <<'END_OF_FILE'\n-----BEGIN RSA PRIVATE KEY-----\n-----END RSA PRIVATE KEY-----\n\nEND_OF_FILE\nchmod 600 ~/.ssh/id_rsa\n"); + "mkdir -p ~/.ssh\n"+ + "rm ~/.ssh/id_rsa\n"+ + "cat >> ~/.ssh/id_rsa <<-'END_OF_JCLOUDS_FILE'\n"+ + "\t-----BEGIN RSA PRIVATE KEY-----\n"+ + "\t-----END RSA PRIVATE KEY-----\n"+ + "\t\n"+ + "END_OF_JCLOUDS_FILE\n"+ + "chmod 600 ~/.ssh/id_rsa\n"); } public void testInstallRSAPrivateKeyUNIXSpecifiedHome() { assertEquals( new InstallRSAPrivateKey("/home/me/.ssh", "-----BEGIN RSA PRIVATE KEY-----\n-----END RSA PRIVATE KEY-----\n") .render(OsFamily.UNIX), - "mkdir -p /home/me/.ssh\nrm /home/me/.ssh/id_rsa\ncat >> /home/me/.ssh/id_rsa <<'END_OF_FILE'\n-----BEGIN RSA PRIVATE KEY-----\n-----END RSA PRIVATE KEY-----\n\nEND_OF_FILE\nchmod 600 /home/me/.ssh/id_rsa\n"); - } + "mkdir -p /home/me/.ssh\n"+ + "rm /home/me/.ssh/id_rsa\n"+ + "cat >> /home/me/.ssh/id_rsa <<-'END_OF_JCLOUDS_FILE'\n"+ + "\t-----BEGIN RSA PRIVATE KEY-----\n"+ + "\t-----END RSA PRIVATE KEY-----\n"+ + "\t\n"+ + "END_OF_JCLOUDS_FILE\n"+ + "chmod 600 /home/me/.ssh/id_rsa\n"); } @Test(expectedExceptions = UnsupportedOperationException.class) public void testInstallRSAPrivateKeyWINDOWS() { diff --git a/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/statements/ssh/SshStatementsTest.java b/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/statements/ssh/SshStatementsTest.java index 9459ba51bc..bf9a628518 100644 --- a/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/statements/ssh/SshStatementsTest.java +++ b/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/statements/ssh/SshStatementsTest.java @@ -38,7 +38,7 @@ public class SshStatementsTest { .append("PasswordAuthentication no").append("\n")// .append("PermitRootLogin no").append("\n")// .append("\" 'BEGIN {print TEXT}{print}' /etc/ssh/sshd_config >&3").append("\n")// - .append("/etc/init.d/sshd reload||/etc/init.d/ssh reload").append("\n").toString()); + .append("hash service 2>/dev/null && service ssh reload || /etc/init.d/ssh* reload").append("\n").toString()); } public void testSshdConfigUNIX() { @@ -46,7 +46,7 @@ public class SshStatementsTest { new StringBuilder().append("exec 3<> /etc/ssh/sshd_config && awk -v TEXT=\"")// .append("AddressFamily inet6").append("\n")// .append("\" 'BEGIN {print TEXT}{print}' /etc/ssh/sshd_config >&3").append("\n")// - .append("/etc/init.d/sshd reload||/etc/init.d/ssh reload").append("\n").toString()); + .append("hash service 2>/dev/null && service ssh reload || /etc/init.d/ssh* reload").append("\n").toString()); } } diff --git a/scriptbuilder/src/test/resources/client_rb_append.sh b/scriptbuilder/src/test/resources/client_rb_append.sh index f0522fbfa9..96711ddf63 100644 --- a/scriptbuilder/src/test/resources/client_rb_append.sh +++ b/scriptbuilder/src/test/resources/client_rb_append.sh @@ -1,5 +1,5 @@ -cat >> /etc/chef/client.rb <<'END_OF_FILE' -log_level :info -log_location STDOUT -chef_server_url "http://localhost:4000" -END_OF_FILE +cat >> /etc/chef/client.rb <<-'END_OF_JCLOUDS_FILE' + log_level :info + log_location STDOUT + chef_server_url "http://localhost:4000" +END_OF_JCLOUDS_FILE diff --git a/scriptbuilder/src/test/resources/client_rb_overwrite.sh b/scriptbuilder/src/test/resources/client_rb_overwrite.sh index cca52f5638..7f2b94956a 100644 --- a/scriptbuilder/src/test/resources/client_rb_overwrite.sh +++ b/scriptbuilder/src/test/resources/client_rb_overwrite.sh @@ -1,5 +1,5 @@ -cat > /etc/chef/client.rb <<'END_OF_FILE' -log_level :info -log_location STDOUT -chef_server_url "http://localhost:4000" -END_OF_FILE +cat > /etc/chef/client.rb <<-'END_OF_JCLOUDS_FILE' + log_level :info + log_location STDOUT + chef_server_url "http://localhost:4000" +END_OF_JCLOUDS_FILE diff --git a/scriptbuilder/src/test/resources/functions/test_install_jdk_from_url.sh b/scriptbuilder/src/test/resources/functions/test_install_jdk_from_url.sh new file mode 100644 index 0000000000..a96b138d20 --- /dev/null +++ b/scriptbuilder/src/test/resources/functions/test_install_jdk_from_url.sh @@ -0,0 +1,21 @@ +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_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 diff --git a/scriptbuilder/src/test/resources/test_adminaccess_flipped.sh b/scriptbuilder/src/test/resources/test_adminaccess_flipped.sh index 0c10ee9582..d065eff6a2 100644 --- a/scriptbuilder/src/test/resources/test_adminaccess_flipped.sh +++ b/scriptbuilder/src/test/resources/test_adminaccess_flipped.sh @@ -16,6 +16,6 @@ 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 +hash service 2>/dev/null && service ssh reload || /etc/init.d/ssh* reload awk -v user=^${SUDO_USER:=${USER}}: -v password='crypt(1)' '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 diff --git a/scriptbuilder/src/test/resources/test_adminaccess_params.sh b/scriptbuilder/src/test/resources/test_adminaccess_params.sh index 3908f6299a..6f1e1d0589 100644 --- a/scriptbuilder/src/test/resources/test_adminaccess_params.sh +++ b/scriptbuilder/src/test/resources/test_adminaccess_params.sh @@ -1,21 +1,20 @@ -rm /etc/sudoers -cat >> /etc/sudoers <<'END_OF_FILE' -root ALL = (ALL) ALL -%wheel ALL = (ALL) NOPASSWD:ALL -END_OF_FILE +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(bar)' foo mkdir -p /home/users/foo/.ssh -cat >> /home/users/foo/.ssh/authorized_keys <<'END_OF_FILE' -fooPublicKey -END_OF_FILE +cat >> /home/users/foo/.ssh/authorized_keys <<-'END_OF_JCLOUDS_FILE' + fooPublicKey +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 -/etc/init.d/sshd reload||/etc/init.d/ssh reload +hash service 2>/dev/null && service ssh reload || /etc/init.d/ssh* reload awk -v user=^${SUDO_USER:=${USER}}: -v password='crypt(0)' '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 diff --git a/scriptbuilder/src/test/resources/test_adminaccess_plainuser.sh b/scriptbuilder/src/test/resources/test_adminaccess_plainuser.sh index d91f18e1ef..68325f9e01 100644 --- a/scriptbuilder/src/test/resources/test_adminaccess_plainuser.sh +++ b/scriptbuilder/src/test/resources/test_adminaccess_plainuser.sh @@ -1,14 +1,14 @@ mkdir -p /home/users useradd -s /bin/bash -m -d /home/users/defaultAdminUsername -p 'crypt(0)' defaultAdminUsername mkdir -p /home/users/defaultAdminUsername/.ssh -cat >> /home/users/defaultAdminUsername/.ssh/authorized_keys <<'END_OF_FILE' -publicKey -END_OF_FILE +cat >> /home/users/defaultAdminUsername/.ssh/authorized_keys <<-'END_OF_JCLOUDS_FILE' + publicKey +END_OF_JCLOUDS_FILE chmod 600 /home/users/defaultAdminUsername/.ssh/authorized_keys mkdir -p /home/users/defaultAdminUsername/.ssh rm /home/users/defaultAdminUsername/.ssh/id_rsa -cat >> /home/users/defaultAdminUsername/.ssh/id_rsa <<'END_OF_FILE' -privateKey -END_OF_FILE +cat >> /home/users/defaultAdminUsername/.ssh/id_rsa <<-'END_OF_JCLOUDS_FILE' + privateKey +END_OF_JCLOUDS_FILE chmod 600 /home/users/defaultAdminUsername/.ssh/id_rsa chown -R defaultAdminUsername /home/users/defaultAdminUsername diff --git a/scriptbuilder/src/test/resources/test_adminaccess_standard.sh b/scriptbuilder/src/test/resources/test_adminaccess_standard.sh index 3da6b1c70c..28d184988a 100644 --- a/scriptbuilder/src/test/resources/test_adminaccess_standard.sh +++ b/scriptbuilder/src/test/resources/test_adminaccess_standard.sh @@ -1,21 +1,20 @@ -rm /etc/sudoers -cat >> /etc/sudoers <<'END_OF_FILE' -root ALL = (ALL) ALL -%wheel ALL = (ALL) NOPASSWD:ALL -END_OF_FILE +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(0)' defaultAdminUsername mkdir -p /home/users/defaultAdminUsername/.ssh -cat >> /home/users/defaultAdminUsername/.ssh/authorized_keys <<'END_OF_FILE' -publicKey -END_OF_FILE +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 -/etc/init.d/sshd reload||/etc/init.d/ssh reload +hash service 2>/dev/null && service ssh reload || /etc/init.d/ssh* reload awk -v user=^${SUDO_USER:=${USER}}: -v password='crypt(1)' '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 diff --git a/scriptbuilder/src/test/resources/test_ebs.sh b/scriptbuilder/src/test/resources/test_ebs.sh index d9dd5b7e3e..be055d73c6 100644 --- a/scriptbuilder/src/test/resources/test_ebs.sh +++ b/scriptbuilder/src/test/resources/test_ebs.sh @@ -11,13 +11,13 @@ function default { export INSTANCE_NAME="mkebsboot" export INSTANCE_HOME="/tmp" export LOG_DIR="/tmp/logs" - return 0 + return $? } function mkebsboot { export IMAGE_DIR="/mnt/tmp" export EBS_DEVICE="/dev/sdh" export EBS_MOUNT_POINT="/mnt/ebs" - return 0 + return $? } function findPid { unset FOUND_PID; @@ -65,50 +65,55 @@ init) mkdir -p $INSTANCE_HOME # create runscript header - cat > $INSTANCE_HOME/mkebsboot.sh < $INSTANCE_HOME/mkebsboot.sh <<-'END_OF_JCLOUDS_SCRIPT' + #!/bin/bash + set +u + shopt -s xpg_echo + shopt -s expand_aliases + + PROMPT_COMMAND='echo -ne \"\033]0;mkebsboot\007\"' + export PATH=/usr/ucb/bin:/bin:/sbin:/usr/bin:/usr/sbin + + export INSTANCE_NAME='mkebsboot' +END_OF_JCLOUDS_SCRIPT + cat >> $INSTANCE_HOME/mkebsboot.sh <<-END_OF_JCLOUDS_SCRIPT + export IMAGE_DIR='$IMAGE_DIR' + export EBS_DEVICE='$EBS_DEVICE' + export EBS_MOUNT_POINT='$EBS_MOUNT_POINT' + 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/mkebsboot.sh <<'END_OF_SCRIPT' -cd $INSTANCE_HOME -echo creating a filesystem and mounting the ebs volume -mkdir -p $IMAGE_DIR $EBS_MOUNT_POINT -rm -rf $IMAGE_DIR/* -yes| mkfs -t ext3 $EBS_DEVICE 2>&- -mount $EBS_DEVICE $EBS_MOUNT_POINT -echo making a local working copy of the boot disk -rsync -ax --exclude /ubuntu/.bash_history --exclude /home/*/.bash_history --exclude /etc/ssh/ssh_host_* --exclude /etc/ssh/moduli --exclude /etc/udev/rules.d/*persistent-net.rules --exclude /var/lib/ec2/* --exclude=/mnt/* --exclude=/proc/* --exclude=/tmp/* --exclude=/dev/log / $IMAGE_DIR -echo preparing the local working copy -touch $IMAGE_DIR/etc/init.d/ec2-init-user-data -echo copying the local working copy to the ebs mount -cd $IMAGE_DIR -tar -cSf - * | tar xf - -C $EBS_MOUNT_POINT -echo size of ebs -du -sk $EBS_MOUNT_POINT -echo size of source -du -sk $IMAGE_DIR -rm -rf $IMAGE_DIR/* -umount $EBS_MOUNT_POINT -echo ----COMPLETE---- -END_OF_SCRIPT + cat >> $INSTANCE_HOME/mkebsboot.sh <<-'END_OF_JCLOUDS_SCRIPT' + cd $INSTANCE_HOME + echo creating a filesystem and mounting the ebs volume + mkdir -p $IMAGE_DIR $EBS_MOUNT_POINT + rm -rf $IMAGE_DIR/* + yes| mkfs -t ext3 $EBS_DEVICE 2>&- + mount $EBS_DEVICE $EBS_MOUNT_POINT + echo making a local working copy of the boot disk + rsync -ax --exclude /ubuntu/.bash_history --exclude /home/*/.bash_history --exclude /etc/ssh/ssh_host_* --exclude /etc/ssh/moduli --exclude /etc/udev/rules.d/*persistent-net.rules --exclude /var/lib/ec2/* --exclude=/mnt/* --exclude=/proc/* --exclude=/tmp/* --exclude=/dev/log / $IMAGE_DIR + echo preparing the local working copy + touch $IMAGE_DIR/etc/init.d/ec2-init-user-data + echo copying the local working copy to the ebs mount + cd $IMAGE_DIR + tar -cSf - * | tar xf - -C $EBS_MOUNT_POINT + echo size of ebs + du -sk $EBS_MOUNT_POINT + echo size of source + du -sk $IMAGE_DIR + rm -rf $IMAGE_DIR/* + umount $EBS_MOUNT_POINT + echo ----COMPLETE---- +END_OF_JCLOUDS_SCRIPT # add runscript footer - cat >> $INSTANCE_HOME/mkebsboot.sh <<'END_OF_SCRIPT' -exit 0 -END_OF_SCRIPT + cat >> $INSTANCE_HOME/mkebsboot.sh <<-'END_OF_JCLOUDS_SCRIPT' + exit $? + +END_OF_JCLOUDS_SCRIPT chmod u+x $INSTANCE_HOME/mkebsboot.sh ;; @@ -142,4 +147,4 @@ run) $INSTANCE_HOME/$INSTANCE_NAME.sh ;; esac -exit 0 +exit $? diff --git a/scriptbuilder/src/test/resources/test_find_pid.sh b/scriptbuilder/src/test/resources/test_find_pid.sh index fc29b66050..30206c2cce 100644 --- a/scriptbuilder/src/test/resources/test_find_pid.sh +++ b/scriptbuilder/src/test/resources/test_find_pid.sh @@ -25,4 +25,4 @@ function findPid { export PATH=/usr/ucb/bin:/bin:/sbin:/usr/bin:/usr/sbin findPid $@ || exit 1 echo $FOUND_PID -exit 0 +exit $? diff --git a/scriptbuilder/src/test/resources/test_init.cmd b/scriptbuilder/src/test/resources/test_init.cmd deleted file mode 100644 index f7cc2709c3..0000000000 --- a/scriptbuilder/src/test/resources/test_init.cmd +++ /dev/null @@ -1,134 +0,0 @@ -@echo off -set PATH= -set JAVA_HOME= -set PATH= -GOTO FUNCTION_END -:abort - echo aborting: %EXCEPTION% - exit /b 1 -:default - set INSTANCE_NAME=mkebsboot -set INSTANCE_HOME=/mnt/tmp -set LOG_DIR=/mnt/tmp - exit /b 0 -:mkebsboot - set TMP_DIR=/mnt/tmp - exit /b 0 -:findPid - set FOUND_PID= - set _expression=%1 - shift - set FIND_PROCESS=TASKLIST /FI "WINDOWTITLE eq %_expression%" /NH - FOR /F "usebackq tokens=2 delims= " %%A IN (`cmd /c "%FIND_PROCESS% 2>NUL"`) DO ( - SET FOUND_PID=%%A - ) - if defined FOUND_PID ( - exit /b 0 - ) else ( - set EXCEPTION=%_expression% not found - exit /b 1 - ) -:forget - SETLOCAL - set FOUND_PID= - set NEXT_MINUTE= - set INSTANCE_NAME=%1 - shift - set SCRIPT=%1 - shift - set LOG_DIR=%1 - shift - CALL :findProcess %INSTANCE_NAME% - if defined FOUND_PID ( - echo %INSTANCE_NAME% already running pid [%FOUND_PID%] - ) else ( - CALL :nextMinute - set _DATE=%DATE:~4% - set CMD=schtasks /create /sd %_DATE% /tn %INSTANCE_NAME% /ru System /tr "cmd /c title %INSTANCE_NAME%&%SCRIPT% >%LOG_DIR%\stdout.log 2>%LOG_DIR%\stderr.log" /sc:once /st %NEXT_MINUTE% - echo %INSTANCE_NAME% will start at %NEXT_MINUTE% - set SECONDS=%TIME:~6,2% - set /a SECOND=60-SECONDS - %CMD% >NUL - ping -n %SECONDS% 127.0.0.1 > NUL 2>&1 - CALL :findProcess %INSTANCE_NAME% - if not defined FOUND_PID ( - set EXCEPTION=%INSTANCE_NAME% did not start - abort - ) - ) - exit /b 0 -:FUNCTION_END -set PATH=c:\windows\;C:\windows\system32;c:\windows\system32\wbem -if not "%1" == "init" if not "%1" == "status" if not "%1" == "stop" if not "%1" == "start" if not "%1" == "tail" if not "%1" == "tailerr" if not "%1" == "run" ( - set EXCEPTION=bad argument: %1 not in init status stop start tail tailerr run - goto abort -) -goto CASE_%1 -:CASE_init - call :default - if errorlevel 1 goto abort - call :mkebsboot - if errorlevel 1 goto abort - md %INSTANCE_HOME% - del %INSTANCE_HOME%\mkebsboot.cmd 2>NUL - echo @echo off>>%INSTANCE_HOME%\mkebsboot.cmd - echo title mkebsboot>>%INSTANCE_HOME%\mkebsboot.cmd - echo set PATH=c:\windows\;C:\windows\system32;c:\windows\system32\wbem>>%INSTANCE_HOME%\mkebsboot.cmd - echo set INSTANCE_NAME=mkebsboot>>%INSTANCE_HOME%\mkebsboot.cmd - echo set TMP_DIR=%TMP_DIR%>>%INSTANCE_HOME%\mkebsboot.cmd - echo set INSTANCE_NAME=%INSTANCE_NAME%>>%INSTANCE_HOME%\mkebsboot.cmd - echo set INSTANCE_HOME=%INSTANCE_HOME%>>%INSTANCE_HOME%\mkebsboot.cmd - echo set LOG_DIR=%LOG_DIR%>>%INSTANCE_HOME%\mkebsboot.cmd - echo cd /d %%INSTANCE_HOME%%>>%INSTANCE_HOME%\mkebsboot.cmd - md %INSTANCE_HOME% - del %INSTANCE_HOME%\mkebsboot.cmd 2>NUL - echo @echo off>>%INSTANCE_HOME%\mkebsboot.cmd - echo title mkebsboot>>%INSTANCE_HOME%\mkebsboot.cmd - echo set PATH=c:\windows\;C:\windows\system32;c:\windows\system32\wbem>>%INSTANCE_HOME%\mkebsboot.cmd - echo set INSTANCE_NAME=mkebsboot>>%INSTANCE_HOME%\mkebsboot.cmd - echo set TMP_DIR=%TMP_DIR%>>%INSTANCE_HOME%\mkebsboot.cmd - echo set INSTANCE_NAME=%INSTANCE_NAME%>>%INSTANCE_HOME%\mkebsboot.cmd - echo set INSTANCE_HOME=%INSTANCE_HOME%>>%INSTANCE_HOME%\mkebsboot.cmd - echo set LOG_DIR=%LOG_DIR%>>%INSTANCE_HOME%\mkebsboot.cmd - echo cd /d %%INSTANCE_HOME%%>>%INSTANCE_HOME%\mkebsboot.cmd - echo exit /b 0 >>%INSTANCE_HOME%\mkebsboot.cmd - GOTO END_SWITCH -:CASE_status - call :default - if errorlevel 1 goto abort - call :findPid %INSTANCE_NAME% - if errorlevel 1 goto abort - echo [%FOUND_PID%] - GOTO END_SWITCH -:CASE_stop - call :default - if errorlevel 1 goto abort - call :findPid %INSTANCE_NAME% - if errorlevel 1 goto abort - if defined FOUND_PID ( - TASKKILL /F /T /PID %FOUND_PID% >NUL - ) - GOTO END_SWITCH -:CASE_start - call :default - if errorlevel 1 goto abort - call :forget %INSTANCE_NAME% %INSTANCE_HOME%\%INSTANCE_NAME%.cmd %LOG_DIR% - if errorlevel 1 goto abort - GOTO END_SWITCH -:CASE_tail - call :default - if errorlevel 1 goto abort - tail %LOG_DIR%\stdout.log - GOTO END_SWITCH -:CASE_tailerr - call :default - if errorlevel 1 goto abort - tail %LOG_DIR%\stderr.log - GOTO END_SWITCH -:CASE_run - call :default - if errorlevel 1 goto abort - %INSTANCE_HOME%\%INSTANCE_NAME%.cmd - GOTO END_SWITCH -:END_SWITCH -exit /b 0 diff --git a/scriptbuilder/src/test/resources/test_init.sh b/scriptbuilder/src/test/resources/test_init.sh index e2231a2458..f2bf3e98f2 100644 --- a/scriptbuilder/src/test/resources/test_init.sh +++ b/scriptbuilder/src/test/resources/test_init.sh @@ -11,11 +11,11 @@ function default { export INSTANCE_NAME="mkebsboot" export INSTANCE_HOME="/mnt/tmp" export LOG_DIR="/mnt/tmp" - return 0 + return $? } function mkebsboot { export TMP_DIR="/mnt/tmp" - return 0 + return $? } function findPid { unset FOUND_PID; @@ -63,35 +63,40 @@ init) mkdir -p $INSTANCE_HOME # create runscript header - cat > $INSTANCE_HOME/mkebsboot.sh < $INSTANCE_HOME/mkebsboot.sh <<-'END_OF_JCLOUDS_SCRIPT' + #!/bin/bash + set +u + shopt -s xpg_echo + shopt -s expand_aliases + + PROMPT_COMMAND='echo -ne \"\033]0;mkebsboot\007\"' + export PATH=/usr/ucb/bin:/bin:/sbin:/usr/bin:/usr/sbin + + export INSTANCE_NAME='mkebsboot' +END_OF_JCLOUDS_SCRIPT + cat >> $INSTANCE_HOME/mkebsboot.sh <<-END_OF_JCLOUDS_SCRIPT + export TMP_DIR='$TMP_DIR' + 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/mkebsboot.sh <<'END_OF_SCRIPT' -cd $INSTANCE_HOME -cat >> /tmp/$USER/scripttest/temp.txt <<'END_OF_FILE' -hello world -END_OF_FILE - -find / || exit 1 - -END_OF_SCRIPT + cat >> $INSTANCE_HOME/mkebsboot.sh <<-'END_OF_JCLOUDS_SCRIPT' + cd $INSTANCE_HOME + cat >> /tmp/$USER/scripttest/temp.txt <<-'END_OF_JCLOUDS_FILE' + hello world + END_OF_JCLOUDS_FILE + + find / + +END_OF_JCLOUDS_SCRIPT # add runscript footer - cat >> $INSTANCE_HOME/mkebsboot.sh <<'END_OF_SCRIPT' -exit 0 -END_OF_SCRIPT + cat >> $INSTANCE_HOME/mkebsboot.sh <<-'END_OF_JCLOUDS_SCRIPT' + exit $? + +END_OF_JCLOUDS_SCRIPT chmod u+x $INSTANCE_HOME/mkebsboot.sh ;; @@ -125,4 +130,4 @@ run) $INSTANCE_HOME/$INSTANCE_NAME.sh ;; esac -exit 0 +exit $? diff --git a/scriptbuilder/src/test/resources/test_init_script.sh b/scriptbuilder/src/test/resources/test_init_script.sh new file mode 100644 index 0000000000..a47ed3ec79 --- /dev/null +++ b/scriptbuilder/src/test/resources/test_init_script.sh @@ -0,0 +1,162 @@ +#!/bin/bash +set +u +shopt -s xpg_echo +shopt -s expand_aliases +unset PATH JAVA_HOME LD_LIBRARY_PATH +function abort { + echo "aborting: $@" 1>&2 + exit 1 +} +function default { + export INSTANCE_NAME="testcall" +export INSTANCE_HOME="/tmp/$INSTANCE_NAME" +export LOG_DIR="$INSTANCE_HOME" + return $? +} +function testcall { + return $? +} +function findPid { + unset FOUND_PID; + [ $# -eq 1 ] || { + abort "findPid requires a parameter of pattern to match" + return 1 + } + local PATTERN="$1"; shift + local _FOUND=`ps auxwww|grep "$PATTERN"|grep -v " $0"|grep -v grep|grep -v $$|awk '{print $2}'` + [ -n "$_FOUND" ] && { + export FOUND_PID=$_FOUND + return 0 + } || { + return 1 + } +} +function forget { + unset FOUND_PID; + [ $# -eq 3 ] || { + abort "forget requires parameters INSTANCE_NAME SCRIPT LOG_DIR" + return 1 + } + local INSTANCE_NAME="$1"; shift + local SCRIPT="$1"; shift + local LOG_DIR="$1"; shift + mkdir -p $LOG_DIR + findPid $INSTANCE_NAME + [ -n "$FOUND_PID" -a -f $LOG_DIR/stdout.log ] && { + echo $INSTANCE_NAME already running pid [$FOUND_PID] + return 1; + } || { + nohup $SCRIPT >$LOG_DIR/stdout.log 2>$LOG_DIR/stderr.log & + RETURN=$? + # this is generally followed by findPid, so we shouldn't exit + # immediately as the proc may not have registered in ps, yet + test $RETURN && sleep 1 + return $RETURN; + } +} +export PATH=/usr/ucb/bin:/bin:/sbin:/usr/bin:/usr/sbin +case $1 in +init) + default || exit 1 + testcall || exit 1 + echo hello + mkdir -p $INSTANCE_HOME + + # create runscript header + cat > $INSTANCE_HOME/testcall.sh <<-'END_OF_JCLOUDS_SCRIPT' + #!/bin/bash + set +u + shopt -s xpg_echo + shopt -s expand_aliases + + PROMPT_COMMAND='echo -ne \"\033]0;testcall\007\"' + export PATH=/usr/ucb/bin:/bin:/sbin:/usr/bin:/usr/sbin + + export INSTANCE_NAME='testcall' +END_OF_JCLOUDS_SCRIPT + cat >> $INSTANCE_HOME/testcall.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/testcall.sh <<-'END_OF_JCLOUDS_SCRIPT' + function abort { + echo "aborting: $@" 1>&2 + exit 1 +} +function sourceEnvFile { + [ $# -eq 1 ] || { + abort "sourceEnvFile requires a parameter of the file to source" + return 1 + } + local ENV_FILE="$1"; shift + . "$ENV_FILE" || { + abort "Please append 'return 0' to the end of '$ENV_FILE'" + return 1 + } + return 0 +} + +END_OF_JCLOUDS_SCRIPT + + # add desired commands from the user + cat >> $INSTANCE_HOME/testcall.sh <<-'END_OF_JCLOUDS_SCRIPT' + cd $INSTANCE_HOME + rm -f $INSTANCE_HOME/rc + trap 'echo $?>$INSTANCE_HOME/rc' 0 1 2 3 15 + sourceEnvFile foo || exit 1 + + find / + +END_OF_JCLOUDS_SCRIPT + + # add runscript footer + cat >> $INSTANCE_HOME/testcall.sh <<-'END_OF_JCLOUDS_SCRIPT' + exit $? + +END_OF_JCLOUDS_SCRIPT + + chmod u+x $INSTANCE_HOME/testcall.sh + ;; +status) + default || exit 1 + findPid $INSTANCE_NAME || exit 1 + echo [$FOUND_PID] + ;; +stop) + default || exit 1 + findPid $INSTANCE_NAME || exit 1 + [ -n "$FOUND_PID" ] && { + echo stopping $FOUND_PID + kill -9 $FOUND_PID + } + ;; +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 + ;; +tailerr) + default || exit 1 + tail $LOG_DIR/stderr.log + ;; +run) + default || exit 1 + $INSTANCE_HOME/$INSTANCE_NAME.sh + ;; +esac +exit $? diff --git a/scriptbuilder/src/test/resources/test_install_jdk_from_url.sh b/scriptbuilder/src/test/resources/test_install_jdk_from_url.sh new file mode 100644 index 0000000000..f1638bb15d --- /dev/null +++ b/scriptbuilder/src/test/resources/test_install_jdk_from_url.sh @@ -0,0 +1,21 @@ +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 diff --git a/scriptbuilder/src/test/resources/test_install_jdk_scriptbuilder.sh b/scriptbuilder/src/test/resources/test_install_jdk_scriptbuilder.sh new file mode 100644 index 0000000000..971338e0e8 --- /dev/null +++ b/scriptbuilder/src/test/resources/test_install_jdk_scriptbuilder.sh @@ -0,0 +1,217 @@ +#!/bin/bash +set +u +shopt -s xpg_echo +shopt -s expand_aliases +unset PATH JAVA_HOME LD_LIBRARY_PATH +function abort { + echo "aborting: $@" 1>&2 + exit 1 +} +function default { + export INSTANCE_NAME="install_jdk" +export INSTANCE_HOME="/tmp/$INSTANCE_NAME" +export LOG_DIR="$INSTANCE_HOME" + return $? +} +function install_jdk { + return $? +} +function findPid { + unset FOUND_PID; + [ $# -eq 1 ] || { + abort "findPid requires a parameter of pattern to match" + return 1 + } + local PATTERN="$1"; shift + local _FOUND=`ps auxwww|grep "$PATTERN"|grep -v " $0"|grep -v grep|grep -v $$|awk '{print $2}'` + [ -n "$_FOUND" ] && { + export FOUND_PID=$_FOUND + return 0 + } || { + return 1 + } +} +function forget { + unset FOUND_PID; + [ $# -eq 3 ] || { + abort "forget requires parameters INSTANCE_NAME SCRIPT LOG_DIR" + return 1 + } + local INSTANCE_NAME="$1"; shift + local SCRIPT="$1"; shift + local LOG_DIR="$1"; shift + mkdir -p $LOG_DIR + findPid $INSTANCE_NAME + [ -n "$FOUND_PID" -a -f $LOG_DIR/stdout.log ] && { + echo $INSTANCE_NAME already running pid [$FOUND_PID] + return 1; + } || { + nohup $SCRIPT >$LOG_DIR/stdout.log 2>$LOG_DIR/stderr.log & + RETURN=$? + # this is generally followed by findPid, so we shouldn't exit + # immediately as the proc may not have registered in ps, yet + test $RETURN && sleep 1 + return $RETURN; + } +} +export PATH=/usr/ucb/bin:/bin:/sbin:/usr/bin:/usr/sbin +case $1 in +init) + default || exit 1 + install_jdk || exit 1 + mkdir -p $INSTANCE_HOME + + # create runscript header + cat > $INSTANCE_HOME/install_jdk.sh <<-'END_OF_JCLOUDS_SCRIPT' + #!/bin/bash + set +u + shopt -s xpg_echo + shopt -s expand_aliases + + PROMPT_COMMAND='echo -ne \"\033]0;install_jdk\007\"' + export PATH=/usr/ucb/bin:/bin:/sbin:/usr/bin:/usr/sbin + + export INSTANCE_NAME='install_jdk' +END_OF_JCLOUDS_SCRIPT + cat >> $INSTANCE_HOME/install_jdk.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/install_jdk.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/install_jdk.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_JCLOUDS_SCRIPT + + # add runscript footer + cat >> $INSTANCE_HOME/install_jdk.sh <<-'END_OF_JCLOUDS_SCRIPT' + exit $? + +END_OF_JCLOUDS_SCRIPT + + chmod u+x $INSTANCE_HOME/install_jdk.sh + ;; +status) + default || exit 1 + findPid $INSTANCE_NAME || exit 1 + echo [$FOUND_PID] + ;; +stop) + default || exit 1 + findPid $INSTANCE_NAME || exit 1 + [ -n "$FOUND_PID" ] && { + echo stopping $FOUND_PID + kill -9 $FOUND_PID + } + ;; +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 + ;; +tailerr) + default || exit 1 + tail $LOG_DIR/stderr.log + ;; +run) + default || exit 1 + $INSTANCE_HOME/$INSTANCE_NAME.sh + ;; +esac +exit $? diff --git a/scriptbuilder/src/test/resources/test_runrun.cmd b/scriptbuilder/src/test/resources/test_runrun.cmd deleted file mode 100644 index ab5cf7c7bd..0000000000 --- a/scriptbuilder/src/test/resources/test_runrun.cmd +++ /dev/null @@ -1,17 +0,0 @@ -md %TEMP%\%USERNAME%\scripttest -del %TEMP%\%USERNAME%\scripttest\yahooprod.cmd 2>NUL -echo @echo off>>%TEMP%\%USERNAME%\scripttest\yahooprod.cmd -echo title yahooprod>>%TEMP%\%USERNAME%\scripttest\yahooprod.cmd -echo set PATH=c:\windows\;C:\windows\system32;c:\windows\system32\wbem>>%TEMP%\%USERNAME%\scripttest\yahooprod.cmd -echo set INSTANCE_NAME=yahooprod>>%TEMP%\%USERNAME%\scripttest\yahooprod.cmd -echo set JAVA_HOME=%JAVA_HOME%>>%TEMP%\%USERNAME%\scripttest\yahooprod.cmd -echo cd /d %TEMP%\%USERNAME%\scripttest>>%TEMP%\%USERNAME%\scripttest\yahooprod.cmd -md %TEMP%\%USERNAME%\scripttest -del %TEMP%\%USERNAME%\scripttest\yahooprod.cmd 2>NUL -echo @echo off>>%TEMP%\%USERNAME%\scripttest\yahooprod.cmd -echo title yahooprod>>%TEMP%\%USERNAME%\scripttest\yahooprod.cmd -echo set PATH=c:\windows\;C:\windows\system32;c:\windows\system32\wbem>>%TEMP%\%USERNAME%\scripttest\yahooprod.cmd -echo set INSTANCE_NAME=yahooprod>>%TEMP%\%USERNAME%\scripttest\yahooprod.cmd -echo set JAVA_HOME=%JAVA_HOME%>>%TEMP%\%USERNAME%\scripttest\yahooprod.cmd -echo cd /d %TEMP%\%USERNAME%\scripttest>>%TEMP%\%USERNAME%\scripttest\yahooprod.cmd -echo exit /b 0 >>%TEMP%\%USERNAME%\scripttest\yahooprod.cmd diff --git a/scriptbuilder/src/test/resources/test_runrun.sh b/scriptbuilder/src/test/resources/test_runrun.sh index 54ce111083..fc7935ba48 100644 --- a/scriptbuilder/src/test/resources/test_runrun.sh +++ b/scriptbuilder/src/test/resources/test_runrun.sh @@ -1,33 +1,38 @@ mkdir -p /tmp/$USER/scripttest # create runscript header -cat > /tmp/$USER/scripttest/yahooprod.sh < /tmp/$USER/scripttest/yahooprod.sh <<-'END_OF_JCLOUDS_SCRIPT' + #!/bin/bash + set +u + shopt -s xpg_echo + shopt -s expand_aliases + + PROMPT_COMMAND='echo -ne \"\033]0;yahooprod\007\"' + export PATH=/usr/ucb/bin:/bin:/sbin:/usr/bin:/usr/sbin + + export INSTANCE_NAME='yahooprod' +END_OF_JCLOUDS_SCRIPT +cat >> /tmp/$USER/scripttest/yahooprod.sh <<-END_OF_JCLOUDS_SCRIPT + export JAVA_HOME='$JAVA_HOME' +END_OF_JCLOUDS_SCRIPT # add desired commands from the user -cat >> /tmp/$USER/scripttest/yahooprod.sh <<'END_OF_SCRIPT' -cd /tmp/$USER/scripttest -echo hello || return 1 - -cat >> /tmp/$USER/scripttest/temp.txt <<'END_OF_FILE' -hello world -END_OF_FILE - -echo $JAVA_HOME/bin/java -DinstanceName=$INSTANCE_NAME myServer.Main || return 1 - -END_OF_SCRIPT +cat >> /tmp/$USER/scripttest/yahooprod.sh <<-'END_OF_JCLOUDS_SCRIPT' + cd /tmp/$USER/scripttest + echo hello + + cat >> /tmp/$USER/scripttest/temp.txt <<-'END_OF_JCLOUDS_FILE' + hello world + END_OF_JCLOUDS_FILE + + echo $JAVA_HOME/bin/java -DinstanceName=$INSTANCE_NAME myServer.Main + +END_OF_JCLOUDS_SCRIPT # add runscript footer -cat >> /tmp/$USER/scripttest/yahooprod.sh <<'END_OF_SCRIPT' -exit 0 -END_OF_SCRIPT +cat >> /tmp/$USER/scripttest/yahooprod.sh <<-'END_OF_JCLOUDS_SCRIPT' + exit $? + +END_OF_JCLOUDS_SCRIPT chmod u+x /tmp/$USER/scripttest/yahooprod.sh diff --git a/scriptbuilder/src/test/resources/test_script.sh b/scriptbuilder/src/test/resources/test_script.sh index 5fde6790b1..ea7e1de915 100644 --- a/scriptbuilder/src/test/resources/test_script.sh +++ b/scriptbuilder/src/test/resources/test_script.sh @@ -9,7 +9,7 @@ function abort { } function default { export RUNTIME="Moo" - return 0 + return $? } export PATH=/usr/ucb/bin:/bin:/sbin:/usr/bin:/usr/sbin case $1 in @@ -22,10 +22,10 @@ stop) echo stop $RUNTIME ;; status) - cat >> /tmp/$USER/scripttest/temp.txt <<'END_OF_FILE' -hello world -END_OF_FILE + cat >> /tmp/$USER/scripttest/temp.txt <<-'END_OF_JCLOUDS_FILE' + hello world +END_OF_JCLOUDS_FILE echo "the following should be []: [$RUNTIME]" ;; esac -exit 0 +exit $? diff --git a/scriptbuilder/src/test/resources/test_seek_and_destroy.sh b/scriptbuilder/src/test/resources/test_seek_and_destroy.sh index dad6f6dc5b..3f8d68c701 100644 --- a/scriptbuilder/src/test/resources/test_seek_and_destroy.sh +++ b/scriptbuilder/src/test/resources/test_seek_and_destroy.sh @@ -28,4 +28,4 @@ findPid $@ || exit 1 echo stopping $FOUND_PID kill -9 $FOUND_PID } -exit 0 +exit $? diff --git a/skeletons/standalone-compute/pom.xml b/skeletons/standalone-compute/pom.xml index 85475e4138..6667fb2467 100644 --- a/skeletons/standalone-compute/pom.xml +++ b/skeletons/standalone-compute/pom.xml @@ -121,8 +121,8 @@ ${project.artifactId} - org.jclouds.servermanager.*;version="${project.version}" - org.jclouds.*;version="${project.version}",* + org.jclouds.servermanager*;version="${project.version}" + org.jclouds*;version="${project.version}",*