mirror of https://github.com/apache/jclouds.git
Remove clojure bindings
These have not seen any development in many years.
This commit is contained in:
parent
e446b5b8b4
commit
0bc935dd57
|
@ -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))))))
|
|
@ -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"))))
|
|
@ -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>
|
||||
|
|
|
@ -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)])))))
|
||||
|
|
@ -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)))
|
|
@ -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)))
|
|
@ -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))))))
|
|
@ -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>
|
||||
|
|
|
@ -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))
|
|
@ -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
|
|
@ -71,13 +71,4 @@
|
|||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>com.theoryinpractise</groupId>
|
||||
<artifactId>clojure-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
|
|
|
@ -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)))
|
|
@ -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))))))
|
|
@ -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))
|
|
@ -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}))))))
|
|
@ -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)))
|
||||
|
|
@ -110,10 +110,6 @@
|
|||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>com.theoryinpractise</groupId>
|
||||
<artifactId>clojure-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<executions>
|
||||
|
|
|
@ -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)))))
|
|
@ -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))))
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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))
|
|
@ -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"})))
|
Loading…
Reference in New Issue