Remove clojure bindings

These have not seen any development in many years.
This commit is contained in:
Andrew Gaul 2016-10-23 05:21:40 -07:00
parent e446b5b8b4
commit 0bc935dd57
23 changed files with 0 additions and 2728 deletions

View File

@ -1,261 +0,0 @@
;
; Licensed to the Apache Software Foundation (ASF) under one or more
; contributor license agreements. See the NOTICE file distributed with
; this work for additional information regarding copyright ownership.
; The ASF 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 "Adrian Cole"
:doc "A clojure binding to the jclouds chef interface.
Here's a quick example of how to manipulate a databag on the Chef Platform,
which is basically Chef Server as a Service.
(use 'org.jclouds.chef)
(def client \"YOUR_CLIENT\")
;; load the rsa key from ~/.chef/CLIENT_NAME.pem
(def credential (load-pem client))
;; create a connection to the chef platform
(def chef (chef-service \"chef\" client credential :chef.endpoint \"https://api.opscode.com/organizations/YOUR_ORG\"))
(with-chef-service [chef]
(create-databag \"cluster-config\")
(update-databag-item \"cluster-config\" {:id \"master\" :name \"myhost.com\"}))
;; note that you can create your chef connection like this to do in-memory testing
(def chef (chef-service \"transientchef\" \"\" \"\"))
See http://code.google.com/p/jclouds for details."}
org.jclouds.chef
(:use [org.jclouds.core])
(:require (org.danlarkin [json :as json]))
(:import
java.util.Properties
[org.jclouds ContextBuilder]
[org.jclouds.chef ChefClient
ChefService ChefContext]
[org.jclouds.chef.domain DatabagItem]))
(try
(use '[clojure.contrib.reflect :only [get-field]])
(catch Exception e
(use '[clojure.contrib.java-utils
:only [wall-hack-field]
:rename {wall-hack-field get-field}])))
(defn load-pem
"get the pem associated with the supplied identity"
([#^String identity]
(slurp (str (. System getProperty "user.home") "/.chef/" identity ".pem"))))
;; TODO find a way to pass the chef provider by default
(defn chef-service
"Create a logged in context to a chef server.
provider \"chef\" is a remote connection, and you can pass the option
:chef.endpoint \"https://url\" to override the endpoint
provider \"transientchef\" is for in-memory when you are looking to do
unit testing"
([#^String provider #^String identity #^String credential & options]
(let [module-keys (set (keys module-lookup))
ext-modules (filter #(module-keys %) options)
opts (apply hash-map (filter #(not (module-keys %)) options))]
(.. (ContextBuilder/newBuilder provider)
(credentials provider-identity provider-credential)
(modules (apply modules (concat ext-modules (opts :extensions))))
(overrides (reduce #(do (.put %1 (name (first %2)) (second %2)) %1)
(Properties.) (dissoc opts :extensions)))
(build ChefContext)
(getChefService)))))
(defn chef-context
"Returns a chef context from a chef service."
[#^ChefService chef]
(.getContext chef))
(defn chef-service?
[object]
(instance? ChefService object))
(defn chef-context?
[object]
(instance? ChefContext object))
(defn as-chef-service
"Tries hard to produce a chef service from its input arguments"
[& args]
(cond
(chef-service? (first args)) (first args)
(chef-context? (first args)) (.getChefService (first args))
:else (apply chef-service args)))
(defn as-chef-api
"Tries hard to produce a chef client from its input arguments"
[& args]
(cond
(chef-service? (first args)) (.getApi (.getContext (first args)))
(chef-context? (first args)) (.getApi (first args))
:else (.getApi (.getContext (apply chef-service args)))))
(def *chef*)
(defmacro with-chef-service
"Specify the default chef service"
[[& chef-or-args] & body]
`(binding [*chef* (as-chef-service ~@chef-or-args)]
~@body))
(defn nodes
"Retrieve the names of the existing nodes in your chef server."
([] (nodes *chef*))
([#^ChefService chef]
(seq (.listNodes (as-chef-api chef)))))
(defn nodes-with-details
"Retrieve the existing nodes in your chef server including all details."
([] (nodes *chef*))
([#^ChefService chef]
(seq (.listNodes chef))))
(defn clients
"Retrieve the names of the existing clients in your chef server."
([] (clients *chef*))
([#^ChefService chef]
(seq (.listClients (as-chef-api chef)))))
(defn clients-with-details
"Retrieve the existing clients in your chef server including all details."
([] (clients *chef*))
([#^ChefService chef]
(seq (.listClients chef))))
(defn cookbooks
"Retrieve the names of the existing cookbooks in your chef server."
([] (cookbooks *chef*))
([#^ChefService chef]
(seq (.listCookbooks (as-chef-api chef)))))
(defn cookbook-versions
"Retrieve the versions of an existing cookbook in your chef server."
([name] (cookbook-versions *chef*))
([#^ChefService name chef]
(seq (.getVersionsOfCookbook (as-chef-api chef) name))))
(defn cookbook-versions-with-details
"Retrieve the existing cookbook versions in your chef server including all details."
([] (cookbook-versions *chef*))
([#^ChefService chef]
(seq (.listCookbookVersions chef))))
(defn update-run-list
"Updates the run-list associated with a tag"
([run-list tag] (update-run-list run-list tag *chef*))
([run-list tag #^ChefService chef]
(.updateRunListForTag chef run-list tag)))
(defn run-list
"Retrieves the run-list associated with a tag"
([tag] (run-list tag *chef*))
([tag #^ChefService chef]
(seq (.getRunListForTag chef tag))))
(defn create-bootstrap
"creates a client and bootstrap script associated with a tag"
([tag] (create-bootstrap tag *chef*))
([tag #^ChefService chef]
(.createClientAndBootstrapScriptForTag chef tag)))
(defn databags
"Retrieve the names of the existing data bags in your chef server."
([] (databags *chef*))
([#^ChefService chef]
(seq (.listDatabags (as-chef-api chef)))))
(defn databag-exists?
"Predicate to check presence of a databag"
([databag-name]
(databag-exists? databag-name *chef*))
([databag-name #^ChefService chef]
(.databagExists (as-chef-api chef) databag-name)))
(defn delete-databag
"Delete a data bag, including its items"
([databag]
(delete-databag databag *chef*))
([databag chef]
(.deleteDatabag (as-chef-api chef) databag)))
(defn create-databag
"create a data bag"
([databag]
(create-databag databag *chef*))
([databag chef]
(.createDatabag (as-chef-api chef) databag)))
(defn databag-items
"Retrieve the names of the existing items in a data bag in your chef server."
([databag]
(databag-items databag *chef*))
([databag chef]
(seq (.listDatabagItems (as-chef-api chef) databag))))
(defn databag-item-exists?
"Predicate to check presence of a databag item"
([databag-name item-id]
(databag-item-exists? databag-name item-id *chef*))
([databag-name item-id #^ChefService chef]
(.databagExists (as-chef-api chef) databag-name item-id)))
(defn databag-item
"Get an item from the data bag"
([databag item-id]
(databag-item databag item-id *chef*))
([databag item-id chef]
(json/decode-from-str (str (.getDatabagItem (as-chef-api chef) databag item-id)))))
(defn delete-databag-item
"delete an item from the data bag"
([databag item-id]
(delete-databag-item databag item-id *chef*))
([databag item-id chef]
(.deleteDatabagItem (as-chef-api chef) databag item-id)))
(defn create-databag-item
"put a new item in the data bag. Note the Map you pass must have an :id key:
ex.
(create-databag-item \"cluster-config\" {:id \"master\" :name \"myhost.com\"}))"
([databag value]
(create-databag-item databag value *chef*))
([databag value chef]
(let [value-str (json/encode-to-str value)]
(let [value-json (json/decode-from-str value-str)]
(.createDatabagItem (as-chef-api chef) databag
(DatabagItem. (get value-json :id) value-str))))))
(defn update-databag-item
"updates an existing item in the data bag. Note the Map you pass must have an :id key:
ex.
(update-databag-item \"cluster-config\" {:id \"master\" :name \"myhost.com\"}))"
([databag value]
(update-databag-item databag value *chef*))
([databag value chef]
(let [value-str (json/encode-to-str value)]
(let [value-json (json/decode-from-str value-str)]
(.updateDatabagItem (as-chef-api chef) databag
(DatabagItem. (get value-json :id) value-str))))))

View File

@ -1,70 +0,0 @@
;
; Licensed to the Apache Software Foundation (ASF) under one or more
; contributor license agreements. See the NOTICE file distributed with
; this work for additional information regarding copyright ownership.
; The ASF 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.chef-test
(:use [org.jclouds.chef] :reload-all)
(:use [clojure.test]))
(defn clean-stub-fixture
"This should allow basic tests to easily be run with another service."
[service account key & options]
(fn [f]
(with-chef-service [(apply chef-service service account key options)]
(doseq [databag (databags)]
(delete-databag databag))
(f))))
(use-fixtures :each (clean-stub-fixture "transientchef" "" ""))
(deftest chef-service?-test
(is (chef-service? *chef*)))
(deftest as-chef-service-test
(is (chef-service? (chef-service "transientchef" "" "")))
(is (chef-service? (as-chef-service *chef*)))
(is (chef-service? (as-chef-service (chef-context *chef*)))))
(deftest create-existing-databag-test
(is (not (databag-exists? "")))
(create-databag "fred")
(is (databag-exists? "fred")))
(deftest create-databag-test
(create-databag "fred")
(is (databag-exists? "fred")))
(deftest databags-test
(is (empty? (databags)))
(create-databag "fred")
(is (= 1 (count (databags)))))
(deftest databag-items-test
(create-databag "databag")
(is (empty? (databag-items "databag")))
(is (create-databag-item "databag" {:id "databag-item1" :value "databag-value1"}))
(is (create-databag-item "databag" {:id "databag-item2" :value "databag-value2"}))
(is (= 2 (count (databag-items "databag")))))
(deftest databag-item-test
(create-databag "databag")
(is (create-databag-item "databag" {:id "databag-item1" :value "databag-value1"}))
(is (create-databag-item "databag" {:id "databag-item2" :value "databag-value2"}))
(is (= {:id "databag-item2" :value "databag-value2"} (databag-item "databag" "databag-item2"))))
(deftest run-list-test
(update-run-list #{"recipe[foo]"} "tag")
(is (= ["recipe[foo]"] (run-list "tag"))))

View File

@ -105,15 +105,6 @@
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>com.theoryinpractise</groupId>
<artifactId>clojure-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>live</id>

View File

@ -1,84 +0,0 @@
;
; Licensed to the Apache Software Foundation (ASF) under one or more
; contributor license agreements. See the NOTICE file distributed with
; this work for additional information regarding copyright ownership.
; The ASF 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 "Hunter Hutchinson, hunter.hutchinson@gmail.com"
:doc "A clojure binding to the jclouds AMI service interface."}
org.jclouds.ec2.ami2
(:use org.jclouds.compute2)
(:import org.jclouds.aws.domain.Region
org.jclouds.ec2.features.AMIApi
org.jclouds.ec2.options.CreateImageOptions
org.jclouds.compute.domain.NodeMetadata
(org.jclouds.ec2.domain Volume Volume$Status Snapshot Snapshot$Status AvailabilityZoneInfo)))
(defn ^org.jclouds.ec2.features.AMIApi
ami-service
""
[compute]
(-> compute
.getContext
.getProviderSpecificContext
.getApi
.getAMIApi().get))
(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 (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- 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 create-image-in-region
([compute region name node-id description]
(.createImageInRegion (ami-service compute)
(get-region region)
(as-string name)
(as-string node-id)
(into-array CreateImageOptions
(when description
[(.withDescription (CreateImageOptions.) description)])))))

View File

@ -1,286 +0,0 @@
;
; Licensed to the Apache Software Foundation (ASF) under one or more
; contributor license agreements. See the NOTICE file distributed with
; this work for additional information regarding copyright ownership.
; The ASF 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.ebs2
(:use org.jclouds.compute2 [clojure.core.incubator :only (-?>)])
(: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
""
[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 (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)."
[compute & [region & volume-ids]]
(set
(.describeVolumesInRegion (ebs-service compute)
(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."
[compute & options]
(let [options (apply hash-map options)
region (:region options)
options (snapshot-options (dissoc options :region))]
(set
(.describeSnapshotsInRegion (ebs-service compute)
(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."
([compute ^Volume volume] (create-snapshot compute volume nil))
([compute ^Volume volume description] (create-snapshot compute (.getRegion volume) (.getId volume) description))
([compute region volume-id description]
(.createSnapshotInRegion (ebs-service compute)
(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."
([compute ^Snapshot snapshot] (delete-snapshot compute (.getRegion snapshot) (.getId snapshot)))
([compute region snapshot-id]
(.deleteSnapshotInRegion (ebs-service compute)
(get-region region)
(as-string snapshot-id))))
(defn get-zone
[v]
(cond
(instance? AvailabilityZoneInfo v) (.getZone v)
(instance? NodeMetadata v) (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."
([compute ^NodeMetadata node volume device]
(attach-volume compute node (.getProviderId node) (get-volume-id volume) device))
([compute region instance-id volume-id device]
(apply #(.attachVolumeInRegion (ebs-service compute)
(get-region region) % %2 %3)
(map as-string [volume-id instance-id device]))))
(defn detach-volume
"Detaches 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."
[compute 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 compute)
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)."
[compute & 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 compute)]
(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 compute node new-volume (as-string (:device options))))])))
(defn delete-volume
"Deletes a volume in the specified region."
([compute ^Volume volume]
(delete-volume (.getRegion volume) (.getId volume)))
([compute region volume-id]
(.deleteVolumeInRegion (ebs-service compute)
(get-region region)
(as-string volume-id))))
(defn status
"Returns the status of the given entity; works for Volumes and Snapshots."
[k]
(.getStatus k))
(defn status-available?
[^Volume v]
(= Volume$Status/AVAILABLE (status v)))
(defn status-creating?
[^Volume v]
(= Volume$Status/CREATING (status v)))
(defn status-deleting?
[^Volume v]
(= Volume$Status/DELETING (status v)))
(defn status-in-use?
[^Volume v]
(= Volume$Status/IN_USE (status v)))
(defn status-completed?
[^Snapshot s]
(= Snapshot$Status/COMPLETED (status s)))
(defn status-error?
[^Snapshot s]
(= Snapshot$Status/ERROR (status s)))
(defn status-pending?
[^Snapshot s]
(= Snapshot$Status/PENDING (status s)))

View File

@ -1,80 +0,0 @@
;
; Licensed to the Apache Software Foundation (ASF) under one or more
; contributor license agreements. See the NOTICE file distributed with
; this work for additional information regarding copyright ownership.
; The ASF 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-ip2
(:require (org.jclouds [compute2 :as compute])
[org.jclouds.ec2.ebs2 :as ebs])
(:import org.jclouds.compute.domain.NodeMetadata
(org.jclouds.ec2.domain PublicIpInstanceIdPair)))
(defn ^org.jclouds.ec2.features.ElasticIPAddressApi
eip-service
"Returns an ElasticIPAddressApi for the given ComputeService"
[compute]
(-> compute
.getContext .getProviderSpecificContext .getApi .getElasticIPAddressApi().get))
(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."
([compute] (allocate compute nil))
([compute region]
(.allocateAddressInRegion (eip-service compute) (ebs/get-region region))))
(defn associate
"Associates an elastic IP address with a node."
([compute ^NodeMetadata node public-ip]
(associate node public-ip (.getProviderId node)))
([compute region public-ip instance-id]
(.associateAddressInRegion (eip-service compute)
(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."
([compute] (addresses compute nil))
([compute region & public-ips]
(into {} (for [^PublicIpInstanceIdPair pair (.describeAddressesInRegion (eip-service compute)
(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."
[compute region public-ip]
(.disassociateAddressInRegion (eip-service compute)
(ebs/get-region region)
public-ip))
(defn release
"Disclaims an elastic IP address from your account."
([compute public-ip] (release compute public-ip nil))
([compute public-ip region]
(.releaseAddressInRegion (eip-service compute)
(ebs/get-region region)
public-ip)))

View File

@ -1,99 +0,0 @@
;
; Licensed to the Apache Software Foundation (ASF) under one or more
; contributor license agreements. See the NOTICE file distributed with
; this work for additional information regarding copyright ownership.
; The ASF 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 "Juegen Hoetzel, juergen@archlinux.org"
:doc "A clojure binding for the jclouds AWS security group interface."}
org.jclouds.ec2.security-group2
(:require (org.jclouds [compute2 :as compute])
[org.jclouds.ec2.ebs2 :as ebs])
(:import org.jclouds.ec2.domain.SecurityGroup
org.jclouds.ec2.features.SecurityGroupApi
org.jclouds.net.domain.IpProtocol))
(defn #^SecurityGroupApi
sg-service
"Returns the SecurityGroup Api associated with the specified compute service."
[compute]
(-> compute .getContext .getProviderSpecificContext .getApi .getSecurityGroupApi().get))
(defn create-group
"Creates a new security group.
e.g. (create-group compute \"Database Server\" \"Description for group\" :region :us-west-1)"
[compute name & {:keys [description region]}]
(.createSecurityGroupInRegion (sg-service compute) (ebs/get-region region) name (or description name)))
(defn delete-group
"Deletes a security group.
e.g. (delete-group compute \"Database Server\" :region :us-west-1)"
[compute name & {:keys [region]}]
(.deleteSecurityGroupInRegion (sg-service compute) (ebs/get-region region) name))
(defn groups
"Returns a map of GroupName -> org.jclouds.ec2.domain.SecurityGroup instances.
e.g. (groups compute :region :us-east-1)"
[compute & {:keys [region]}]
(into {} (for [#^SecurityGroup group (.describeSecurityGroupsInRegion (sg-service compute)
(ebs/get-region region)
(into-array String '()))]
[(.getName group) group])))
(defn get-protocol [v]
"Coerce argument to a IP Protocol."
(cond
(instance? IpProtocol v) v
(keyword? v) (if-let [p (get {:tcp IpProtocol/TCP
:udp IpProtocol/UDP
:icmp IpProtocol/ICMP}
v)]
p
(throw (IllegalArgumentException.
(str "Can't obtain IP protocol from " v " (valid :tcp, :udp and :icmp)"))))
(nil? v) IpProtocol/TCP
:else (throw (IllegalArgumentException.
(str "Can't obtain IP protocol from argument of type " (type v))))))
(defn authorize
"Adds permissions to a security group.
e.g. (authorize compute \"jclouds#webserver#us-east-1\" 80 :ip-range \"0.0.0.0/0\")
(authorize compute \"jclouds#webserver#us-east-1\" [1000,2000] :protocol :udp)"
[compute group-name port & {:keys [protocol ip-range region]}]
(let [group ((groups compute :region region) group-name)
[from-port to-port] (if (number? port) [port port] port)]
(if group
(.authorizeSecurityGroupIngressInRegion
(sg-service compute) (ebs/get-region region) (.getName group) (get-protocol protocol) from-port to-port (or ip-range "0.0.0.0/0"))
(throw (IllegalArgumentException.
(str "Can't find security group for name " group-name))))))
(defn revoke
"Revokes permissions from a security group.
e.g. (revoke compute 80 \"jclouds#webserver#us-east-1\" :protocol :tcp 80 80 :ip-range \"0.0.0.0/0\")"
[compute group-name port & {:keys [protocol ip-range region]}]
(let [group ((groups compute :region region) group-name)
[from-port to-port] (if (number? port) [port port] port)]
(if group
(.revokeSecurityGroupIngressInRegion
(sg-service compute) (ebs/get-region region) (.getName group) (get-protocol protocol) from-port to-port (or ip-range "0.0.0.0/0"))
(throw (IllegalArgumentException.
(str "Can't find security group for name " group-name))))))

View File

@ -72,10 +72,6 @@
<build>
<plugins>
<plugin>
<groupId>com.theoryinpractise</groupId>
<artifactId>clojure-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>

View File

@ -1,327 +0,0 @@
;
; Licensed to the Apache Software Foundation (ASF) under one or more
; contributor license agreements. See the NOTICE file distributed with
; this work for additional information regarding copyright ownership.
; The ASF 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.blobstore2
"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 view resources in rackspace
(use 'org.jclouds.blobstore2)
(def user \"rackspace_username\")
(def password \"rackspace_password\")
(def blobstore-name \"cloudfiles\")
(def the-blobstore (blobstore blobstore-name user password))
(pprint (locations the-blobstore))
(pprint (containers the-blobstore))
(pprint (blobs the-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 ContextBuilder]
[org.jclouds.blobstore
domain.BlobBuilder BlobStore BlobStoreContext
domain.BlobMetadata domain.StorageMetadata domain.PageSet
domain.Blob domain.internal.BlobBuilderImpl options.PutOptions
options.PutOptions$Builder
options.CreateContainerOptions options.ListContainerOptions]
[org.jclouds.io Payload Payloads]
java.util.Arrays
[java.security DigestOutputStream MessageDigest]
com.google.common.collect.ImmutableSet
com.google.common.net.MediaType
com.google.common.io.ByteSource))
;;
;; Payload support for creating Blobs.
;;
(defprotocol PayloadSource
"Various types can have PayloadSource extended onto them so that they are
easily coerced into a Payload."
(^Payload payload [arg] "Coerce arg into a Payload."))
(extend-protocol PayloadSource
Payload
(payload [p] p)
java.io.InputStream
(payload [is] (Payloads/newInputStreamPayload is))
String
(payload [s] (Payloads/newStringPayload s))
java.io.File
(payload [f] (Payloads/newFilePayload f))
ByteSource
(payload [bs] (Payloads/newByteSourcePayload bs)))
;; something in clojure 1.3 (namespaces?) does not like a private type called byte-array-type,
;; so we refer to (class (make-array ...)) directly; and it only parses if it is its own block,
;; hence separating it from the above
(extend-protocol PayloadSource
(class (make-array Byte/TYPE 0))
(payload [ba] (Payloads/newByteArrayPayload ba)))
(defn blobstore
"Create a logged in context.
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 [^BlobStoreContext
context (.. (ContextBuilder/newBuilder provider)
(credentials provider-identity provider-credential)
(modules (apply modules (concat ext-modules (opts :extensions))))
(overrides (reduce #(do (.put ^Properties %1 (name (first %2)) (second %2)) %1)
(Properties.) (dissoc opts :extensions)))
(buildView BlobStoreContext))]
(.getBlobStore context))))
(defn blobstore-context
"Returns a blobstore context from a blobstore."
[^BlobStore blobstore]
(.getContext ^BlobStore blobstore))
(defn blob?
[object]
(instance? Blob))
(defn blobstore?
[object]
(instance? BlobStore object))
(defn blobstore-context?
[object]
(instance? BlobStoreContext object))
(defn containers
"List all containers in a blobstore."
[^BlobStore blobstore] (.list ^BlobStore blobstore))
(def ^{:private true} list-option-map
{:after-marker #(.afterMarker ^ListContainerOptions %1 ^String %2)
:in-directory #(.inDirectory ^ListContainerOptions %1 %2)
:max-results #(.maxResults ^ListContainerOptions %1 ^Integer %2)
:with-details #(when %2 (.withDetails ^ListContainerOptions %1))
:recursive #(when %2 (.recursive ^ListContainerOptions %1))})
(defn blobs
"Returns a set of blobs in the given container, as directed by the
query options below.
Options are:
:after-marker string
:in-directory path
:max-results n
:with-details true
:recursive true"
[^BlobStore blobstore container-name & args]
(let [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)))
(defn- container-seq-chunk
[^BlobStore blobstore container prefix marker]
(apply blobs blobstore container
(concat (when prefix
[:in-directory prefix])
(when (string? marker)
[:after-marker marker]))))
(defn- container-seq-chunks [^BlobStore blobstore container prefix marker]
(when marker ;; When getNextMarker returns null, there's no more.
(let [chunk (container-seq-chunk blobstore container prefix marker)]
(lazy-seq (cons chunk
(container-seq-chunks blobstore container prefix
(.getNextMarker ^PageSet 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 container-seq
"Returns a lazy seq of all blobs in the given container."
([^BlobStore blobstore container]
(container-seq blobstore container nil))
([^BlobStore blobstore container prefix]
;; :start has no special meaning, it is just a non-null (null indicates
;; end), non-string (markers are strings).
(concat-elements (container-seq-chunks blobstore container prefix
:start))))
(defn locations
"Retrieve the available container locations for the blobstore context."
[^BlobStore blobstore]
(seq (.listAssignableLocations blobstore)))
(defn create-container
"Create a container."
[^BlobStore blobstore container-name & {:keys [location public-read?]}]
(let [cco (CreateContainerOptions.)
cco (if public-read? (.publicRead cco) cco)]
(.createContainerInLocation blobstore location container-name cco)))
(defn clear-container
"Clear a container."
[^BlobStore blobstore container-name]
(.clearContainer blobstore container-name))
(defn delete-container
"Delete a container."
[^BlobStore blobstore container-name]
(.deleteContainer blobstore container-name))
(defn delete-container-if-empty
"Delete a container if empty."
[^BlobStore blobstore container-name]
(.deleteContainerIfEmpty blobstore container-name))
(defn container-exists?
"Predicate to check presence of a container"
[^BlobStore blobstore container-name]
(.containerExists blobstore container-name))
(defn directory-exists?
"Predicate to check presence of a directory"
[^BlobStore blobstore container-name path]
(.directoryExists blobstore container-name path))
(defn create-directory
"Create a directory path."
[^BlobStore blobstore container-name path]
(.createDirectory blobstore container-name path))
(defn delete-directory
"Delete a directory path."
[^BlobStore blobstore container-name path]
(.deleteDirectory blobstore container-name path))
(defn blob-exists?
"Predicate to check presence of a blob"
[^BlobStore blobstore container-name path]
(.blobExists blobstore container-name path))
(defn put-blob
"Put a blob. Metadata in the blob determines location."
[^BlobStore blobstore container-name blob & {:keys [multipart?]}]
(let [options (if multipart?
(PutOptions$Builder/multipart)
(PutOptions.))]
(.putBlob blobstore container-name blob options)))
(defn blob-metadata
"Get metadata from given path"
[^BlobStore blobstore container-name path]
(.blobMetadata blobstore container-name path))
(defn ^Blob get-blob
"Get blob from given path"
[^BlobStore blobstore container-name path]
(.getBlob blobstore container-name path))
(defn sign-get
"Get a signed http GET request for manipulating a blob in another
application, Ex. curl."
[^BlobStore blobstore container-name name]
(.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."
[^BlobStore blobstore container-name ^Blob blob]
(.signPutBlob (.. blobstore getContext getSigner)
container-name
blob))
(defn sign-delete
"Get a signed http DELETE request for manipulating a blob in another
application, Ex. curl."
[^BlobStore blobstore container-name name]
(.signRemoveBlob (.. blobstore getContext getSigner) container-name name))
(defn get-blob-stream
"Get an inputstream from the blob at a given path"
[^BlobStore blobstore container-name path]
(.getInput ^Payload (.getPayload (get-blob blobstore container-name path))))
(defn remove-blob
"Remove blob from given path"
[^BlobStore blobstore container-name path]
(.removeBlob blobstore container-name path))
(defn count-blobs
"Count blobs"
[^BlobStore blobstore container-name]
(.countBlobs blobstore container-name))
(defn blob
"Create a new blob with the specified payload and options.
The payload argument can be anything accepted by the PayloadSource protocol."
([^String name &
{:keys [payload content-type content-length content-md5
content-disposition content-encoding content-language metadata]}]
(let [blob-builder (.name (BlobBuilderImpl.) name)
blob-builder (if payload
(.payload blob-builder
(org.jclouds.blobstore2/payload payload))
(.forSigning blob-builder))
blob-builder (if content-length ;; Special case, arg is prim.
(.contentLength blob-builder content-length)
blob-builder)
blob-builder (if content-type
(.contentType blob-builder content-type)
blob-builder)
blob-builder (if content-md5
(.contentMD5 blob-builder content-md5)
blob-builder)]
(doto blob-builder
(.contentDisposition content-disposition)
(.contentEncoding content-encoding)
(.contentLanguage content-language)
(.userMetadata metadata))
(.build blob-builder))))
(define-accessors StorageMetadata "blob" type id name
location-id uri last-modified)
(define-accessors BlobMetadata "blob" content-type)
(defn blob-etag [^Blob blob]
(.getETag blob))
(defn blob-md5 [^Blob blob]
(.getContentMD5 blob))

View File

@ -1,205 +0,0 @@
;
; Licensed to the Apache Software Foundation (ASF) under one or more
; contributor license agreements. See the NOTICE file distributed with
; this work for additional information regarding copyright ownership.
; The ASF 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.blobstore2-test
(:use [org.jclouds.blobstore2] :reload-all)
(:use [clojure.test])
(:import [java.io ByteArrayInputStream ByteArrayOutputStream
StringBufferInputStream]
[org.jclouds.util Strings2]
com.google.common.hash.Hashing
com.google.common.io.ByteSource))
(defn clean-stub-fixture
"This should allow basic tests to easily be run with another service."
[blobstore]
(fn [f]
(doseq [container (containers blobstore)]
(delete-container blobstore (.getName container)))
(f)))
(def blobstore-stub (blobstore "transient" "" ""))
(use-fixtures :each (clean-stub-fixture blobstore-stub))
(deftest blobstore?-test
(is (blobstore? blobstore-stub)))
(deftest as-blobstore-test
(is (blobstore? (blobstore "transient" "user" "password"))))
(deftest create-existing-container-test
(is (not (container-exists? blobstore-stub "")))
(is (create-container blobstore-stub "fred"))
(is (container-exists? blobstore-stub "fred")))
(deftest create-container-test
(is (create-container blobstore-stub "fred"))
(is (container-exists? blobstore-stub "fred")))
(deftest locations-test
(is (not (empty? (locations blobstore-stub))))
(is (create-container blobstore-stub "fred"
:location (first (locations blobstore-stub)))))
(deftest containers-test
(is (empty? (containers blobstore-stub)))
(is (create-container blobstore-stub "fred"))
(is (= 1 (count (containers blobstore-stub)))))
(deftest blobs-test
(is (create-container blobstore-stub "container"))
(is (empty? (blobs blobstore-stub "container")))
(is (put-blob blobstore-stub "container"
(blob "blob1" :payload "blob1")))
(is (put-blob blobstore-stub "container"
(blob "blob2" :payload "blob2")))
(is (= 2 (count (blobs blobstore-stub "container"))))
(is (= 1 (count (blobs blobstore-stub "container" :max-results 1))))
(create-directory blobstore-stub "container" "dir")
(is (put-blob blobstore-stub "container"
(blob "dir/blob2" :payload "blob2")))
(is (put-blob blobstore-stub "container"
(blob "dir/blob3" :payload "blob3")))
(is (= 4 (count-blobs blobstore-stub "container")))
(is (= 4 (count (blobs blobstore-stub "container"))))
(is (= 5 (count (blobs blobstore-stub "container" :recursive true))))
(is (= 4 (count (blobs blobstore-stub "container" :with-details true))))
;; jclouds will list dir and dir/
(is (= 2 (count (blobs blobstore-stub "container" :in-directory "dir")))))
(deftest large-container-list-test
(let [container-name "test"
total-blobs 5000]
;; create a container full of blobs
(create-container blobstore-stub container-name)
(dotimes [i total-blobs] (put-blob blobstore-stub container-name
(blob (str i)
:payload (str i))))
;; verify
(is (= total-blobs (count-blobs blobstore-stub container-name)))))
(deftest container-seq-test
(is (create-container blobstore-stub "container"))
(is (empty? (container-seq blobstore-stub "container")))
(is (empty? (container-seq blobstore-stub "container" "/a"))))
(deftest get-blob-test
(is (create-container blobstore-stub "blob"))
(is (put-blob blobstore-stub "blob"
(blob "blob1" :payload "blob1")))
(is (put-blob blobstore-stub "blob"
(blob "blob2" :payload "blob2")))
(is (= "blob2" (Strings2/toStringAndClose (get-blob-stream blobstore-stub
"blob" "blob2")))))
(deftest put-blob-test
;; Check multipart works
(is (create-container blobstore-stub "blobs"))
(is (put-blob blobstore-stub "blobs"
(blob "blob1" :payload "blob1")
:multipart? true))
(is (= 1 (count (blobs blobstore-stub "blobs")))))
(deftest sign-get-test
(let [request (sign-get blobstore-stub "container" "path")]
(is (= "http://localhost/container/path" (str (.getEndpoint request))))
(is (= "GET" (.getMethod request)))))
(deftest sign-put-test
(let [request (sign-put blobstore-stub "container"
(blob "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 (= "application/unknown"
(first (.get (.getHeaders request) "Content-Type"))))))
(deftest sign-put-with-headers-test
(let [request (sign-put blobstore-stub
"container"
(blob "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 blobstore-stub "container" "path")]
(is (= "http://localhost/container/path" (str (.getEndpoint request))))
(is (= "DELETE" (.getMethod request)))))
(deftest blob-test
(let [byte-source (ByteSource/wrap (.getBytes "test-payload"))
a-blob (blob "test-name"
:payload byte-source
:content-md5 (.asBytes (.hash byte-source (Hashing/md5))))]
(is (= (seq (.. a-blob (getPayload) (getContentMetadata) (getContentMD5)))
(seq (.digest (doto (java.security.MessageDigest/getInstance "MD5")
(.reset)
(.update (.getBytes "test-payload")))))))))
(deftest payload-protocol-test
(is (instance? org.jclouds.io.Payload (payload "test")))
(is (blob "blob1" :payload (payload "blob1")))
(is (create-container blobstore-stub "container"))
(is (= "blob1"
(do
(put-blob blobstore-stub "container"
(blob "blob1"
:payload "blob1"))
(Strings2/toStringAndClose (get-blob-stream blobstore-stub
"container" "blob1")))))
(is (= "blob2"
(do
(put-blob blobstore-stub "container"
(blob "blob2"
:payload (StringBufferInputStream. "blob2")))
(Strings2/toStringAndClose (get-blob-stream blobstore-stub
"container" "blob2")))))
(is (= "blob3"
(do
(put-blob blobstore-stub "container"
(blob "blob3"
:payload (.getBytes "blob3")))
(Strings2/toStringAndClose (get-blob-stream blobstore-stub
"container" "blob3")))))
(is (= "blob4"
(do
(put-blob blobstore-stub "container"
(blob "blob4"
:payload (ByteArrayInputStream. (.getBytes "blob4"))))
(Strings2/toStringAndClose (get-blob-stream blobstore-stub
"container" "blob4")))))
(is (= "blob5"
(do
(put-blob blobstore-stub "container"
(blob "blob5"
:payload (ByteSource/wrap (.getBytes "blob5"))))
(Strings2/toStringAndClose (get-blob-stream blobstore-stub
"container" "blob5"))))))
;; TODO: more tests involving blob-specific functions

View File

@ -71,13 +71,4 @@
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>com.theoryinpractise</groupId>
<artifactId>clojure-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

View File

@ -1,450 +0,0 @@
;
; Licensed to the Apache Software Foundation (ASF) under one or more
; contributor license agreements. See the NOTICE file distributed with
; this work for additional information regarding copyright ownership.
; The ASF 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.compute2
"A clojure binding to the jclouds ComputeService.
jclouds supports many compute providers including Amazon EC2 (aws-ec2),
Rackspace Cloud Servers (cloudservers-us), GoGrid (gogrid),
There are over a dozen to choose from.
Current supported providers are available via the following dependency:
org.jclouds/jclouds-allcompute
You can inquire about which providers are loaded via the following:
(seq (org.jclouds.providers.Providers/allCompute))
(seq (org.jclouds.apis.Apis/allCompute))
Here's an example of getting some compute configuration from rackspace:
(use 'org.jclouds.compute2)
(use 'clojure.pprint)
(def provider \"cloudservers-us\")
(def provider-identity \"username\")
(def provider-credential \"password\")
;; create a compute service
(def compute
(compute-service provider provider-identity provider-credential))
(pprint (locations compute))
(pprint (images compute))
(pprint (nodes compute))
(pprint (hardware-profiles compute)))
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 ContextBuilder]
[org.jclouds.domain Location]
[org.jclouds.compute
ComputeService ComputeServiceContext]
[org.jclouds.compute.domain
Template TemplateBuilder ComputeMetadata NodeMetadata Hardware
OsFamily Image]
[org.jclouds.compute.options TemplateOptions RunScriptOptions
RunScriptOptions$Builder]
[org.jclouds.compute.predicates
NodePredicates]
[com.google.common.collect ImmutableSet])
)
(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))]
(.. (ContextBuilder/newBuilder provider)
(credentials provider-identity provider-credential)
(modules (apply modules (concat ext-modules (opts :extensions))))
(overrides (reduce #(do (.put %1 (name (first %2)) (second %2)) %1)
(Properties.) (dissoc opts :extensions)))
(buildView ComputeServiceContext)
(getComputeService))))
([#^ComputeServiceContext compute-context]
(.getComputeService compute-context)))
(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 locations
"Retrieve the available compute locations for the compute context."
([#^ComputeService compute]
(seq (.listAssignableLocations compute))))
(defn nodes
"Retrieve the existing nodes for the compute context."
([#^ComputeService compute]
(seq (.listNodes compute))))
(defn nodes-with-details
"Retrieve the existing nodes for the compute context."
([#^ComputeService compute]
(seq (.listNodesDetailsMatching compute (NodePredicates/all)))))
(defn nodes-with-details-matching
"List details for all nodes matching fn pred.
pred should be a fn of one argument that takes a ComputeMetadata and returns true or false.
"
([#^ComputeService compute pred]
(seq (.listNodesDetailsMatching compute (to-predicate pred)))))
(defn nodes-in-group
"list details of all the nodes in the given group."
([#^ComputeService compute #^String group]
(filter #(= (.getGroup %) group) (nodes-with-details compute))))
(defn images
"Retrieve the available images for the compute context."
([#^ComputeService compute]
(seq (.listImages compute))))
(defn hardware-profiles
"Retrieve the available node hardware profiles for the compute context."
([#^ComputeService compute]
(seq (.listHardwareProfiles compute))))
(defn default-template
([#^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)
;; Note that this will actually add another 2 nodes to the set called
;; \"webserver\""
([group count compute]
(create-nodes
group count (default-template compute) compute))
([#^ComputeService compute group count template]
(seq
(.createNodesInGroup compute group count template))))
(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)
;; Note that this will actually add another node to the set called
;; \"webserver\""
([compute group]
(create-node compute group (default-template compute)))
([compute group template]
(first (create-nodes compute group 1 template))))
(defn #^NodeMetadata node-details
"Retrieve the node metadata, given its id."
([#^ComputeService compute id]
(.getNodeMetadata compute id)))
(defn suspend-nodes-matching
"Suspend all nodes matching the fn pred.
pred should be a fn of one argument that takes a ComputeMetadata and returns true or false."
([#^ComputeService compute pred]
(.suspendNodesMatching compute (to-predicate pred))))
(defn suspend-node
"Suspend a node, given its id."
([#^ComputeService compute id]
(.suspendNode compute id)))
(defn resume-nodes-matching
"Suspend all the nodes in the fn pred.
pred should be a fn of one argument that takes a ComputeMetadata and returns true or false."
([#^ComputeService compute pred]
(.resumeNodesMatching compute (to-predicate pred))))
(defn resume-node
"Resume a node, given its id."
([#^ComputeService compute id]
(.resumeNode compute id)))
(defn reboot-nodes-matching
"Reboot all the nodes in the fn pred.
pred should be a fn of one argument that takes a ComputeMetadata and returns true or false."
([#^ComputeService compute pred]
(.rebootNodesMatching compute (to-predicate pred))))
(defn reboot-node
"Reboot a node, given its id."
([#^ComputeService compute id]
(.rebootNode compute id)))
(defn destroy-nodes-matching
"Destroy all the nodes in the fn pred.
pred should be a fn of one argument that takes a ComputeMetadata and returns true or false.
;; destroy all nodes
(destroy-nodes-matching compute (constantly true))
"
([#^ComputeService compute pred]
(.destroyNodesMatching compute (to-predicate pred))))
(defn destroy-node
"Destroy a node, given its id."
([#^ComputeService compute id]
(.destroyNode compute id)))
(defn run-script-on-node
"Run a script on a node"
([#^ComputeService compute id command #^RunScriptOptions options]
(.runScriptOnNode compute id command options)))
(defn run-script-on-nodes-matching
"Run a script on the nodes matching the given predicate"
([#^ComputeService compute pred command #^RunScriptOptions options]
(.runScriptOnNodesMatching compute (to-predicate pred) command options)))
(defmacro status-predicate [node status]
`(= (.getStatus ~node)
(. org.jclouds.compute.domain.NodeMetadata$Status ~status)))
(defn pending?
"Predicate for the node being in transition"
[#^NodeMetadata node]
(status-predicate node PENDING))
(defn running?
"Predicate for the node being available for requests."
[#^NodeMetadata node]
(status-predicate node RUNNING))
(defn terminated?
"Predicate for the node being halted."
[#^NodeMetadata node]
(or
(= node nil)
(status-predicate node TERMINATED)))
(defn suspended?
"Predicate for the node being suspended."
[#^NodeMetadata node]
(status-predicate node SUSPENDED))
(defn error-status?
"Predicate for the node being in an error status."
[#^NodeMetadata node]
(status-predicate node ERROR))
(defn unrecognized-status?
"Predicate for the node being in an unrecognized status."
[#^NodeMetadata node]
(status-predicate node UNRECOGNIZED))
(defn in-group?
"Returns a predicate fn which returns true if the node is in the given group, false otherwise"
[group]
#(= (.getGroup %) group))
(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 status 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
[:from-hardware :from-image :from-template
: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
:min-cores :min-ram :min-disk])))
(def
^{:doc "TemplateOptions functions" :private true}
options-map
(merge
(make-option-map
kw-memfn-0arg
[;; ec2
:no-key-pair
;; aws-ec2
:enable-monitoring :no-placement-group])
(make-option-map
kw-memfn-1arg
[;; RunScriptOptions
:override-login-credentials
:override-login-user
:override-login-password :override-login-private-key
:override-authenticate-sudo
:name-task :run-as-root :wrap-in-init-script :block-on-complete
:block-on-port
;; TemplateOptions
:run-script :install-private-key :authorize-public-key :tags
;; cloudstack
:security-group-id :network-id :network-ids :setup-static-nat
:ip-on-default-network :ips-to-networks
;; ec2
:security-groups :user-data :block-device-mappings
:unmap-device-named
;; cloudstack ec2
:key-pair
;; aws-ec2
:placement-group :subnet-id :spot-price :spot-options
:iam-instance-profile-name :iam-instance-profile-arn
;; cloudstack aws-ec2
:security-group-ids
;; softlayer
:domain-name])
(make-option-map
kw-memfn-varargs
[;; from TemplateOptions
:inbound-ports])
(make-option-map
kw-memfn-2arg
[;; from TemplateOptions
:block-on-port
;; ec2 options
:map-ephemeral-device-to-device-name])
{:map-ebs-snapshot-to-device-name
(kw-memfn-apply :map-ebs-snapshot-to-device-name
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))))
(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, and :any keys expect a
boolean value.
Options correspond to TemplateBuilder methods."
[#^ComputeService compute
{:keys [from-hardware from-image from-template
os-family location-id image-id hardware-id
os-name-matches os-description-matches os-version-matches
os-arch-matches os-64-bit mage-name-matches
image-version-matches image-description-matches image-matches
min-cores min-ram min-disk smallest fastest biggest any]
:as options}]
(let [builder (.. compute (templateBuilder))]
(doseq [[option value] options]
(when-not (known-template-options option)
(throw (Exception. (format "Invalid template builder option : %s" option))))
;; apply template builder options
(try
(apply-option builder template-map option value)
(catch Exception e
(throw (Exception.
(format
"Problem applying template builder %s with value %s: %s"
option (pr-str value) (.getMessage e))
e)))))
(let [template (.build builder)
template-options (.getOptions template)]
(doseq [[option value] options]
;; apply template option options
(try
(apply-option template-options options-map option value)
(catch Exception e
(throw (Exception.
(format
"Problem applying template option %s with value %s: %s"
option (pr-str value) (.getMessage e))
e)))))
template)))

View File

@ -1,88 +0,0 @@
;
; Licensed to the Apache Software Foundation (ASF) under one or more
; contributor license agreements. See the NOTICE file distributed with
; this work for additional information regarding copyright ownership.
; The ASF 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.
;
(defn compute-module
[]
(org.jclouds.compute.config.JCloudsNativeComputeServiceAdapterContextModule
(class ComputeService)
(class ComputeService)
(defrecord ClojureComputeServiceAdapter []
org.jclouds.compute.JCloudsNativeComputeServiceAdapter
(^NodeMetadata createNodeWithGroupEncodedIntoNameThenStoreCredentials [this ^String group ^String name ^Template template ^Map credentialStore]
())
(^Iterable listNodes [this ]
())
(^Iterable listImages [this ]
())
(^Iterable listHardwareProfiles [this ]
())
(^Iterable listLocations [this ]
())
(^NodeMetadata getNode [this ^String id]
())
(^void destroyNode [this ^String id]
())
(^void rebootNode [this ^String id]
())
(^void suspendNode [this ^String id]
())
(^void resumeNode [this ^String id]
()))))
(defn compute-context [^RestContextSpec spec]
(.createContext (ComputeServiceContextFactory.) spec))
(^RestContextSpec defn context-spec [^StandaloneComputeServiceContextModule module]
(StandaloneComputeServiceContextSpec. "servermanager", "http://host", "1", "", "identity", "credential", module, (ImmutableSet/of)))
(defrecord NodeListComputeService
[node-list]
org.jclouds.compute.ComputeService
(listNodes [_] node-list)
(getNodeMetadata
[_ id]
(some #(= (.getId %) id) node-list))
(listNodesDetailsMatching
[_ predicate]
(filter #(.apply predicate %) node-list)))
(defn ssh-client-factory
"Pass in a function that reifies org.jclouds.ssh.SshClient"
[ctor]
(reify
org.jclouds.ssh.SshClient$Factory
(^org.jclouds.ssh.SshClient create
[_ ^IPSocket socket ^Credentials credentials]
(ctor socket credentials))
(^org.jclouds.ssh.SshClient create
[_ ^IPSocket socket ^String username ^String password-or-key]
(ctor socket username password-or-key))
(^org.jclouds.ssh.SshClient create
[_ ^IPSocket socket ^String username ^bytes password-or-key]
(ctor socket username password-or-key))))
(defn ssh-module
"Create a module that specifies the factory for creating an ssh service"
[^org.jclouds.ssh.SshClient$Factory factory]
(let [binder (atom nil)]
(reify
com.google.inject.Module
(configure
[this abinder]
(reset! binder abinder)
(.. @binder (bind org.jclouds.ssh.SshClient$Factory)
(toInstance factory))))))

View File

@ -1,32 +0,0 @@
;
; Licensed to the Apache Software Foundation (ASF) under one or more
; contributor license agreements. See the NOTICE file distributed with
; this work for additional information regarding copyright ownership.
; The ASF 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.predicate)
(defprotocol Coercions
"Protocol for coercing between predicate-like things, like
Clojure fns and com.google.common.base.Predicate."
(to-predicate [p]))
(extend-protocol Coercions
clojure.lang.IFn
(to-predicate [p]
(reify com.google.common.base.Predicate
(apply [this input] (p input))))
com.google.common.base.Predicate
(to-predicate [p] p))

View File

@ -1,158 +0,0 @@
;
; Licensed to the Apache Software Foundation (ASF) under one or more
; contributor license agreements. See the NOTICE file distributed with
; this work for additional information regarding copyright ownership.
; The ASF 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.compute2-test
(:use [org.jclouds.compute2] :reload-all)
(:use clojure.test)
(:require [org.jclouds.ssh-test :as ssh-test])
(:import
org.jclouds.compute.domain.OsFamily
java.net.InetAddress
org.jclouds.scriptbuilder.domain.Statements
org.jclouds.compute.options.TemplateOptions
org.jclouds.compute.options.TemplateOptions$Builder
org.jclouds.compute.options.RunScriptOptions
org.jclouds.compute.options.RunScriptOptions$Builder
org.jclouds.domain.LoginCredentials
java.util.NoSuchElementException
))
(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)))))
(def compute-stub (compute-service "stub" "compute2.clj" "" :extensions [(ssh-test/ssh-test-client ssh-test/no-op-ssh-client)]))
(defn clean-stub-fixture
"This should allow basic tests to easily be run with another service."
[compute-service]
(fn [f]
(doseq [node (nodes compute-service)]
(destroy-node compute-service (.getId node)))
(f)))
(use-fixtures :each (clean-stub-fixture compute-stub))
(deftest compute-service?-test
(is (compute-service? compute-stub)))
(deftest as-compute-service-test
(is (compute-service? (compute-service "stub" "compute2.clj" "")))
(is (compute-service? compute-stub))
(is (compute-service? (compute-service (compute-context compute-stub)))))
(deftest nodes-test
(is (create-node compute-stub "fred" (build-template compute-stub {} )))
(is (= 1 (count (nodes-in-group compute-stub "fred"))))
;; pass in a function that selects node metadata based on NodeMetadata field
(is (= 1 (count (nodes-with-details-matching compute-stub (in-group? "fred")))))
;; or make your query inline
(is (= 1 (count (nodes-with-details-matching compute-stub #(= (.getGroup %) "fred")))))
;; or get real fancy, and use the underlying Predicate object jclouds uses
(is (= 1 (count (nodes-with-details-matching compute-stub
(reify com.google.common.base.Predicate
(apply [this input] (= (.getGroup input) "fred")))))))
(is (= 0 (count (nodes-with-details-matching compute-stub (in-group? "othergroup")))))
(suspend-nodes-matching compute-stub (in-group? "fred"))
(is (suspended? (first (nodes-with-details-matching compute-stub (in-group? "fred")))))
(resume-nodes-matching compute-stub (in-group? "fred"))
(is (running? (first (nodes-in-group compute-stub "fred"))))
(reboot-nodes-matching compute-stub (in-group? "fred"))
(is (running? (first (nodes-in-group compute-stub "fred"))))
(is (create-nodes compute-stub "fred" 2 (build-template compute-stub {} )))
(is (= 3 (count (nodes-in-group compute-stub "fred"))))
(is (= "fred" (group (first (nodes compute-stub)))))
(destroy-nodes-matching compute-stub (in-group? "fred"))
(is (terminated? (first (nodes-in-group compute-stub "fred")))))
(defn localhost? [node]
"Returns true if the localhost address is in the node's private ips"
(seq? (some #(= "localhost" %) (private-ips node))))
(deftest compound-predicate-test
(is (create-node compute-stub "my-group" (build-template compute-stub {})))
(is (= 0 (count (nodes-with-details-matching compute-stub #(and (suspended? %) (not (localhost? %)))))))
(is (= 0 (count (nodes-with-details-matching compute-stub #(and (suspended? %) (localhost? %))))))
(is (= 0 (count (nodes-with-details-matching compute-stub #(and (running? %) (localhost? %))))))
(is (= 1 (count (nodes-with-details-matching compute-stub #(and (running? %) (not (localhost? %))))))))
(deftest run-script-on-nodes-matching-with-options-test
(let [echo (Statements/exec "echo hello")
script-options (.. (RunScriptOptions$Builder/overrideLoginCredentials (.build (.password (.user (org.jclouds.domain.LoginCredentials/builder) "user") "pwd")))
(runAsRoot false)
(wrapInInitScript false))
pred #(= (.getGroup %) "scriptednode")]
(is (create-node compute-stub "scriptednode" (build-template compute-stub {})))
(is (run-script-on-nodes-matching compute-stub pred echo script-options))
(is (thrown? NoSuchElementException
(run-script-on-nodes-matching compute-stub #(= (.getGroup %) "nonexistingnode") echo script-options)))))
(deftest run-script-on-node-with-options-test
(let [echo (Statements/exec "echo hello")
script-options (.. (RunScriptOptions$Builder/overrideLoginCredentials (.build (.password (.user (org.jclouds.domain.LoginCredentials/builder) "user") "pwd")))
(runAsRoot false)
(wrapInInitScript false))
test_node (create-node compute-stub "scriptednode" (build-template compute-stub {}))]
(is (run-script-on-node compute-stub (id test_node) echo script-options))
(is (thrown? NoSuchElementException
(run-script-on-node compute-stub "nonexistingnode" echo script-options)))))
(deftest build-template-test
(let [service (compute-service "stub" "compute2.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 (.build (.password (.user (org.jclouds.domain.LoginCredentials/builder) "user") "pwd"))
f (juxt #(.identity %) #(.credential %))
template (build-template
service
{:override-login-credentials credentials})
node (create-node service "something" template)]
(is (= (-> node bean :credentials f)
(f credentials)))
(let [identity "fred"
f #(.identity %)
template (build-template service {:override-login-user identity})
node (create-node service "something" template)]
(is (= (-> node bean :credentials f) identity)))
(let [credential "fred"
f #(.credential %)
template (build-template
service {:override-login-password credential})
node (create-node service "something" template)]
(is (= (-> node bean :credentials f) credential)))))
(testing "enumerated"
(is (= OsFamily/CENTOS
(-> (build-template service {:os-family :centos})
bean :image bean :operatingSystem bean :family))))
(testing "varags"
(is (java.util.Arrays/equals
(int-array [22 8080])
(-> (build-template service {:inbound-ports [22 8080]})
bean :options bean :inboundPorts))))
(testing "invalid"
(is (thrown? Exception (build-template service {:xx :yy}))))))

View File

@ -1,105 +0,0 @@
;
; Licensed to the Apache Software Foundation (ASF) under one or more
; contributor license agreements. See the NOTICE file distributed with
; this work for additional information regarding copyright ownership.
; The ASF 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.ssh-test
(:require
[clojure.tools.logging :as logging])
(:import
org.jclouds.ssh.SshClient
org.jclouds.domain.Credentials
org.jclouds.domain.LoginCredentials
org.jclouds.io.Payload
com.google.common.net.HostAndPort
org.jclouds.compute.domain.ExecResponse))
(defn instantiate [impl-class & args]
(let [constructor (first
(filter
(fn [c] (= (count args) (count (.getParameterTypes c))))
(.getDeclaredConstructors impl-class)))]
(.newInstance impl-class (object-array args))))
;; define an instance or implementation of the following interfaces:
(defn maybe-invoke [f & args]
(when f
(apply f args)))
(defn default-exec
"Default exec function - replies to ./runscript status by returning 1"
[cmd]
(merge
{:exit (Integer. 0) :err "stderr" :out "stdout"}
(condp = cmd
"/tmp/init-bootstrap status" {:exit (Integer. 1) :out "[]"}
{})))
(deftype NoOpClient
[socket username password]
SshClient
(connect [this])
(disconnect [this])
(exec [this cmd]
(logging/info (format "ssh cmd: %s" cmd))
(let [response (default-exec cmd)]
(ExecResponse. (:out response) (:err response) (:exit response))))
(get [this path] )
(^void put [this ^String path ^String content])
(^void put [this ^String path ^org.jclouds.io.Payload content])
(getUsername [this] username)
(getHostAddress [this] (.getHostText socket)) )
(defn no-op-ssh-client
[socket username password]
(NoOpClient. socket username password))
(deftype SshClientFactory
[factory-fn]
org.jclouds.ssh.SshClient$Factory
(^org.jclouds.ssh.SshClient
create
[_ ^HostAndPort socket ^LoginCredentials credentials]
(factory-fn socket (.identity credentials) (.credential credentials)))
)
(deftype Module
[factory binder]
com.google.inject.Module
(configure
[this abinder]
(reset! binder abinder)
(.. @binder (bind org.jclouds.ssh.SshClient$Factory)
(toInstance factory))))
(defn ssh-test-module
"Create a module that specifies the factory for creating a test service"
[factory]
(let [binder (atom nil)]
(Module. factory binder)))
(defn ssh-test-client
"Create a module that can be passed to a compute-context, and which implements
an ssh client with the provided map of function implementations. Keys are
clojurefied versions of org.jclouds.ssh.SshClient's methods"
[factory-fn]
(ssh-test-module (SshClientFactory. factory-fn)))

View File

@ -110,10 +110,6 @@
<build>
<plugins>
<plugin>
<groupId>com.theoryinpractise</groupId>
<artifactId>clojure-maven-plugin</artifactId>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<executions>

View File

@ -1,213 +0,0 @@
;
; Licensed to the Apache Software Foundation (ASF) under one or more
; contributor license agreements. See the NOTICE file distributed with
; this work for additional information regarding copyright ownership.
; The ASF 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.core
"Core functionality used across blobstore and compute."
(:use clojure.tools.logging)
(:import java.io.File
(com.google.common.collect ImmutableSet))
(:require [clojure.string :as string]))
(def ^{:dynamic :true} module-lookup
{:log4j 'org.jclouds.logging.log4j.config.Log4JLoggingModule
:slf4j 'org.jclouds.logging.slf4j.config.SLF4JLoggingModule
:lognull 'org.jclouds.logging.config.NullLoggingModule
:ssh 'org.jclouds.ssh.jsch.config.JschSshClientModule
:jsch 'org.jclouds.ssh.jsch.config.JschSshClientModule
:sshj 'org.jclouds.sshj.config.SshjSshClientModule
:enterprise 'org.jclouds.enterprise.config.EnterpriseConfigurationModule
:apachehc 'org.jclouds.http.apachehc.config.ApacheHCHttpCommandExecutorServiceModule
:okhttp 'org.jclouds.http.okhttp.config.OkHttpCommandExecutorServiceModule
:bouncycastle 'org.jclouds.encryption.bouncycastle.config.BouncyCastleCryptoModule
:joda 'org.jclouds.date.joda.config.JodaDateServiceModule
:gae 'org.jclouds.gae.config.GoogleAppEngineConfigurationModule})
(defn- instantiate [sym]
(let [loader (.getContextClassLoader (Thread/currentThread))]
(try
(.newInstance #^Class (.loadClass loader (name sym)))
(catch java.lang.ClassNotFoundException e
(warn (str "Could not find " (name sym) " module.
Ensure the module is on the classpath. You are maybe missing a dependency on
org.jclouds/jclouds-jsch
org.jclouds/jclouds-log4j
org.jclouds/jclouds-ning
or org.jclouds/jclouds-enterprise."))))))
(defn modules
"Build a list of modules suitable for passing to compute or blobstore context"
[& modules]
(.build #^com.google.common.collect.ImmutableSet$Builder
(reduce #(.add #^com.google.common.collect.ImmutableSet$Builder %1 %2)
(com.google.common.collect.ImmutableSet/builder)
(filter (complement nil?)
(map #(cond
(keyword? %) (-> % module-lookup instantiate)
(symbol? %) (instantiate %)
:else %)
modules)))))
;;; Functions and macros to map keywords to java member functions
(defn dashed [a]
(apply
str (interpose "-" (map string/lower-case (re-seq #"[A-Z][^A-Z]*" a)))))
(defn ^String map-str
"Apply f to each element of coll, concatenate all results into a
String."
[f coll]
(apply str (map f coll)))
(defn camelize
"Takes a string, or anything named, and converts it to camel case
(capitalised initial component"
[a]
(map-str string/capitalize (.split (name a) "-")))
(defn camelize-mixed
"Takes a string, or anything named, and converts it to mixed camel case
(lower case initial component)"
[a]
(let [c (.split (name a) "-")]
(apply str (string/lower-case (first c)) (map string/capitalize (rest c)))))
(defn kw-fn-symbol
"Converts a keyword into a camel cased symbol corresponding to a function
name"
[kw]
(symbol (camelize-mixed kw)))
(defmacro memfn-apply
"Expands into a function that takes one argument,"
[fn-name & args]
`(fn [target# [~@args]]
((memfn ~fn-name ~@args) target# ~@args)))
(defmacro kw-memfn
"Expands into code that creates a function that expects to be passed an
object and any args, and calls the instance method corresponding to
the camel cased version of the passed keyword, passing the arguments."
[kw & args]
`(memfn ~(kw-fn-symbol kw) ~@args))
(defmacro kw-memfn-apply
"Expands into code that creates a function that expects to be passed an object
and an arg vector containing the args, and calls the instance method
corresponding to the camel cased version of the passed keyword, passing the
arguments."
[kw & args]
`(fn [target# [~@args]]
((memfn ~(kw-fn-symbol kw) ~@args) target# ~@args)))
(defmacro kw-memfn-0arg
"Expands into code that creates a function that expects to be passed an
object, and calls the instance method corresponding to the camel cased
version of the passed keyword if the argument is non-nil."
[kw]
`(fn [target# arg#]
(if arg#
((kw-memfn ~kw) target#)
target#)))
(defmacro kw-memfn-1arg
"Expands into code that creates a function that expects to be passed an object
and an arg, and calls the instance method corresponding to the camel cased
version of the passed keyword, passing the argument."
[kw]
`(kw-memfn ~kw a#))
(defmacro kw-memfn-2arg
"Expands into code that creates a function that expects to be passed an object
and an arg vector containing 2 args, and calls the instance method
corresponding to the camel cased version of the passed keyword, passing the
arguments."
[kw]
`(kw-memfn-apply ~kw a# b#))
;; (defmacro memfn-overloads
;; "Construct a function that applies arguments to the given member function."
;; [name]
;; `(fn [target# args#]
;; (condp = (count args#)
;; 0 (. target# (~name))
;; 1 (. target# (~name (first args#)))
;; 2 (. target# (~name (first args#) (second args#)))
;; 3 (. target# (~name (first args#) (second args#) (nth args# 2)))
;; 4 (. target#
;; (~name (first args#) (second args#) (nth args# 2) (nth args# 3)))
;; 5 (. target#
;; (~name (first args#) (second args#) (nth args# 2) (nth args# 3)
;; (nth args# 4)))
;; (throw
;; (java.lang.IllegalArgumentException.
;; (str
;; "too many arguments passed. Limit 5, passed " (count args#)))))))
;; (defmacro kw-memfn-overloads
;; "Expands into code that creates a function that expects to be passed an
;; object and an arg vector, and calls the instance method corresponding to
;; the camel cased version of the passed keyword, passing the arguments.
;; The function accepts different arities at runtime."
;; [kw]
;; `(memfn-overloads ~(kw-fn-symbol kw)))
(defmacro memfn-varargs
"Construct a function that applies an argument sequence to the given member
function, which accepts varargs. array-fn should accept a sequence and
return a suitable array for passing as varargs."
[name array-fn]
`(fn [target# args#]
(. target#
(~name
(if (or (seq? args#) (vector? args#)) (~array-fn args#) args#)))))
(defmacro kw-memfn-varargs
"Expands into code that creates a function that expects to be passed an
object and an arg vector, and calls the instance method corresponding to
the camel cased version of the passed keyword, passing the arguments.
The function accepts different arities at runtime."
([kw] `(kw-memfn-varargs ~kw int-array))
([kw array-fn] `(memfn-varargs ~(kw-fn-symbol kw) ~array-fn)))
(defmacro make-option-map
"Builds a literal map from keyword, to a call on macro f with the keyword
as an argument."
[f keywords]
`(hash-map
~@(reduce (fn [v# k#] (conj (conj v# k#) `(~f ~k#))) [] keywords)))
(defmacro define-accessor
[class property obj-name]
(list 'defn (symbol (str obj-name "-" (name property)))
(vector (with-meta (symbol obj-name) {:tag (.getName class)}))
(list
(symbol (str ".get" (camelize (name property))))
(symbol obj-name))))
(defmacro define-accessors
"Defines read accessors, modelled on class-name-property-name. If the second
argument is a string, it is used instead of the class-name prefix."
[class & properties]
(let [obj-name (if (string? (first properties))
(first properties)
(dashed (.getName class)))
properties (if (string? (first properties))
(rest properties)
properties)]
`(do
~@(for [property properties]
`(define-accessor ~class ~property ~obj-name)))))

View File

@ -1,78 +0,0 @@
;
; Licensed to the Apache Software Foundation (ASF) under one or more
; contributor license agreements. See the NOTICE file distributed with
; this work for additional information regarding copyright ownership.
; The ASF 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.core-test
(:use
org.jclouds.core
clojure.test))
(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))
(with-private-vars [org.jclouds.core [instantiate]]
(deftest instantiate-test
(is (instance? String (instantiate 'java.lang.String)))))
(deftest modules-empty-test
(is (.isEmpty (modules))))
(deftest modules-instantiate-test
(binding [module-lookup
(assoc module-lookup
:string 'java.lang.String)]
(is (instance? String (first (modules :string))))
(is (= 1 (count (modules :string)))))
(testing "pre-instantiated"
(is (instance? String (first (modules "string")))))
(testing "symbol"
(is (instance? String (first (modules 'java.lang.String))))))
(deftest modules-instantiate-fail-test
(binding [module-lookup
(assoc module-lookup
:non-existing 'this.doesnt.Exist)]
(is (.isEmpty (modules :non-existing)))))
(deftest kw-fn-symbol-test
(is (= 'aB (kw-fn-symbol :a-b))))
(deftest memfn-apply-test
(is (= "Ab" ((memfn-apply concat s) "A" ["b"])))
(is (= "Ac" ((memfn-apply replace a b) "Ab" ["b" "c"]))))
(deftest kw-memfn-test
(is (= "a" ((kw-memfn :to-lower-case) "A")))
(is (= "Ab" ((kw-memfn :concat s) "A" "b")))
(is (= "Ab" ((kw-memfn-apply :concat s) "A" ["b"])))
(is (= "Ac" ((kw-memfn-apply :replace a b) "Ab" ["b" "c"]))))
(deftest kw-memfn-0arg-test
(is (= "a" ((kw-memfn-0arg :to-lower-case) "A" true)))
(is (= "A" ((kw-memfn-0arg :to-lower-case) "A" nil))))
(deftest kw-memfn-1arg-test
(is (= "Ab" ((kw-memfn-1arg :concat) "A" "b"))))
(deftest kw-memfn-2arg-test
(is (= "Ac" ((kw-memfn-2arg :replace) "Ab" ["b" "c"]))))
(deftest kw-memfn-varargs-test
(is (fn? (kw-memfn-varargs :replace))))

View File

@ -221,7 +221,6 @@
<maven.compile.target>1.6</maven.compile.target>
<maven.compile.deprecation>true</maven.compile.deprecation>
<maven.site.url.base>gitsite:git@github.com/jclouds/jclouds-maven-site.git</maven.site.url.base>
<clojure.version>1.3.0</clojure.version>
<guava.version>16.0.1</guava.version>
<guava.osgi.import>com.google.common.*;version="[16.0.1,20.0.0)"</guava.osgi.import>
<guice.version>3.0</guice.version>
@ -249,21 +248,6 @@
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.clojure</groupId>
<artifactId>clojure</artifactId>
<version>${clojure.version}</version>
</dependency>
<dependency>
<groupId>org.clojure</groupId>
<artifactId>tools.logging</artifactId>
<version>0.2.3</version>
</dependency>
<dependency>
<groupId>org.clojure</groupId>
<artifactId>core.incubator</artifactId>
<version>0.1.0</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
@ -393,21 +377,6 @@
<artifactId>xmlunit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.clojure</groupId>
<artifactId>clojure</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.clojure</groupId>
<artifactId>tools.logging</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.clojure</groupId>
<artifactId>core.incubator</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
@ -422,9 +391,6 @@
<build>
<resources>
<resource>
<directory>src/main/clojure</directory>
</resource>
<resource>
<directory>src/main/resources</directory>
</resource>
@ -437,9 +403,6 @@
</resource>
</resources>
<testResources>
<testResource>
<directory>src/test/clojure</directory>
</testResource>
<testResource>
<directory>src/test/resources</directory>
</testResource>
@ -1128,32 +1091,6 @@
<artifactId>emma-maven-plugin</artifactId>
<version>1.2</version>
</plugin>
<plugin>
<groupId>com.theoryinpractise</groupId>
<artifactId>clojure-maven-plugin</artifactId>
<version>1.3.10</version>
<configuration>
<sourceDirectories>
<sourceDirectory>src/main/clojure</sourceDirectory>
</sourceDirectories>
<testSourceDirectories>
<testSourceDirectory>src/test/clojure</testSourceDirectory>
</testSourceDirectories>
<clojureOptions>-Xms128m -Xmx512m -Djava.awt.headless=true -XX:MaxPermSize=256m -Xss256k</clojureOptions>
<warnOnReflection>true</warnOnReflection>
<compileDeclaredNamespaceOnly>true</compileDeclaredNamespaceOnly>
<testDeclaredNamespaceOnly>false</testDeclaredNamespaceOnly>
</configuration>
<executions>
<execution>
<id>test-clojure</id>
<phase>test</phase>
<goals>
<goal>test</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>

View File

@ -125,15 +125,6 @@
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>com.theoryinpractise</groupId>
<artifactId>clojure-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>live</id>

View File

@ -1,62 +0,0 @@
;
; Licensed to the Apache Software Foundation (ASF) under one or more
; contributor license agreements. See the NOTICE file distributed with
; this work for additional information regarding copyright ownership.
; The ASF 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.aws.ec2
"AWS EC2 specific functionality"
(:require
[org.jclouds.core :as core])
(:import
org.jclouds.aws.ec2.domain.SpotInstanceRequest
org.jclouds.aws.ec2.options.RequestSpotInstancesOptions))
(def
^{:doc "TemplateBuilder functions" :private true}
spot-option-map
(core/make-option-map
core/kw-memfn-1arg
[:valid-from :valid-until :type :launch-group :availability-zone-group]))
(defn spot-types []
(. org.jclouds.aws.ec2.domain.SpotInstanceRequest$Type values))
(def enum-map {:type (spot-types)})
(defn translate-enum-value [kword value]
(or (-> (filter #(= (name value) (str %)) (kword enum-map)) first)
value))
(defn apply-option
[options [option value]]
(when-let [f (spot-option-map option)]
(f options (translate-enum-value option value)))
options)
(defn spot-options
"Build a spot request options object, for passing to the :spot-options
key of the template builder options.
Takes a hash-map of keys and values that correspond to the methods of
RequestSpotInstancesOptions.
Options are:
:valid-from :valid-until :type :launch-group :availability-zone-group
:type takes either :one-time or :persistent"
[request-map]
(reduce
apply-option
(RequestSpotInstancesOptions.) request-map))

View File

@ -1,32 +0,0 @@
;
; Licensed to the Apache Software Foundation (ASF) under one or more
; contributor license agreements. See the NOTICE file distributed with
; this work for additional information regarding copyright ownership.
; The ASF 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.aws.ec2-test
(:use
org.jclouds.aws.ec2
clojure.test))
(deftest translate-enum-value-test
(is (= org.jclouds.aws.ec2.domain.SpotInstanceRequest$Type/ONE_TIME
(org.jclouds.aws.ec2/translate-enum-value :type :one-time))))
(deftest spot-options-est
(is (spot-options {:type :one-time
:valid-from (java.util.Date.)
:valid-until (java.util.Date.)
:launch-group "lg"
:availability-zone-group "ag"})))