Move jclouds-chef to the main jclouds repo
Project: http://git-wip-us.apache.org/repos/asf/jclouds/repo Commit: http://git-wip-us.apache.org/repos/asf/jclouds/commit/867c7a40 Tree: http://git-wip-us.apache.org/repos/asf/jclouds/tree/867c7a40 Diff: http://git-wip-us.apache.org/repos/asf/jclouds/diff/867c7a40 Branch: refs/heads/master Commit: 867c7a407c1db8f56ff3211d70481755cf71440f Parents: eba727f Author: Ignasi Barrera <[email protected]> Authored: Mon Jul 28 17:34:30 2014 +0200 Committer: Ignasi Barrera <[email protected]> Committed: Mon Jul 28 21:08:54 2014 +0200 ---------------------------------------------------------------------- apis/chef/pom.xml | 131 +++ apis/chef/src/main/clojure/org/jclouds/chef.clj | 261 ++++++ .../src/main/java/org/jclouds/chef/ChefApi.java | 853 +++++++++++++++++++ .../java/org/jclouds/chef/ChefApiMetadata.java | 110 +++ .../main/java/org/jclouds/chef/ChefContext.java | 37 + .../main/java/org/jclouds/chef/ChefService.java | 263 ++++++ .../binders/BindChecksumsToJsonPayload.java | 54 ++ .../BindCreateClientOptionsToJsonPayload.java | 71 ++ .../BindGenerateKeyForClientToJsonPayload.java | 35 + .../org/jclouds/chef/binders/DatabagItemId.java | 32 + .../jclouds/chef/binders/EnvironmentName.java | 31 + .../java/org/jclouds/chef/binders/NodeName.java | 32 + .../java/org/jclouds/chef/binders/RoleName.java | 32 + .../chef/config/BaseChefHttpApiModule.java | 208 +++++ .../chef/config/ChefBootstrapModule.java | 121 +++ .../jclouds/chef/config/ChefHttpApiModule.java | 28 + .../jclouds/chef/config/ChefParserModule.java | 321 +++++++ .../org/jclouds/chef/config/ChefProperties.java | 110 +++ .../org/jclouds/chef/config/CookbookParser.java | 41 + .../chef/config/CookbookVersionsParser.java | 41 + .../org/jclouds/chef/config/InstallChef.java | 37 + .../java/org/jclouds/chef/config/Validator.java | 40 + .../java/org/jclouds/chef/domain/Attribute.java | 235 +++++ .../jclouds/chef/domain/BootstrapConfig.java | 95 +++ .../org/jclouds/chef/domain/ChecksumStatus.java | 102 +++ .../java/org/jclouds/chef/domain/Client.java | 182 ++++ .../jclouds/chef/domain/CookbookDefinition.java | 217 +++++ .../jclouds/chef/domain/CookbookVersion.java | 369 ++++++++ .../org/jclouds/chef/domain/DatabagItem.java | 63 ++ .../org/jclouds/chef/domain/Environment.java | 178 ++++ .../java/org/jclouds/chef/domain/Metadata.java | 447 ++++++++++ .../main/java/org/jclouds/chef/domain/Node.java | 263 ++++++ .../java/org/jclouds/chef/domain/Resource.java | 169 ++++ .../main/java/org/jclouds/chef/domain/Role.java | 205 +++++ .../java/org/jclouds/chef/domain/Sandbox.java | 195 +++++ .../org/jclouds/chef/domain/SearchResult.java | 46 + .../org/jclouds/chef/domain/UploadSandbox.java | 136 +++ .../jclouds/chef/filters/SignedHeaderAuth.java | 200 +++++ .../chef/functions/BootstrapConfigForGroup.java | 61 ++ .../jclouds/chef/functions/ClientForGroup.java | 69 ++ .../chef/functions/GroupToBootScript.java | 130 +++ ...seCookbookDefinitionCheckingChefVersion.java | 49 ++ .../ParseCookbookDefinitionFromJson.java | 50 ++ .../ParseCookbookDefinitionFromJsonv10.java | 52 ++ .../ParseCookbookDefinitionListFromJsonv10.java | 63 ++ ...arseCookbookVersionsCheckingChefVersion.java | 49 ++ .../ParseCookbookVersionsV09FromJson.java | 49 ++ .../ParseCookbookVersionsV10FromJson.java | 59 ++ .../ParseErrorFromJsonOrReturnBody.java | 55 ++ .../chef/functions/ParseKeySetFromJson.java | 45 + .../functions/ParseSearchClientsFromJson.java | 35 + .../functions/ParseSearchDatabagFromJson.java | 77 ++ .../ParseSearchEnvironmentsFromJson.java | 35 + .../functions/ParseSearchNodesFromJson.java | 35 + .../functions/ParseSearchResultFromJson.java | 50 ++ .../functions/ParseSearchRolesFromJson.java | 35 + .../jclouds/chef/functions/RunListForGroup.java | 61 ++ .../jclouds/chef/functions/UriForResource.java | 42 + .../chef/handlers/ChefApiErrorRetryHandler.java | 67 ++ .../jclouds/chef/handlers/ChefErrorHandler.java | 81 ++ .../jclouds/chef/internal/BaseChefService.java | 299 +++++++ .../jclouds/chef/internal/ChefContextImpl.java | 55 ++ .../chef/options/CreateClientOptions.java | 64 ++ .../org/jclouds/chef/options/SearchOptions.java | 95 +++ .../predicates/CookbookVersionPredicates.java | 93 ++ .../strategy/CleanupStaleNodesAndClients.java | 32 + ...reateNodeAndPopulateAutomaticAttributes.java | 33 + .../chef/strategy/DeleteAllClientsInList.java | 34 + .../chef/strategy/DeleteAllNodesInList.java | 31 + .../org/jclouds/chef/strategy/ListClients.java | 32 + .../chef/strategy/ListCookbookVersions.java | 32 + .../ListCookbookVersionsInEnvironment.java | 37 + .../jclouds/chef/strategy/ListEnvironments.java | 31 + .../org/jclouds/chef/strategy/ListNodes.java | 32 + .../chef/strategy/ListNodesInEnvironment.java | 32 + .../UpdateAutomaticAttributesOnNode.java | 31 + .../internal/BaseListCookbookVersionsImpl.java | 97 +++ .../strategy/internal/BaseListNodesImpl.java | 77 ++ .../CleanupStaleNodesAndClientsImpl.java | 102 +++ ...eNodeAndPopulateAutomaticAttributesImpl.java | 83 ++ .../internal/DeleteAllClientsInListImpl.java | 85 ++ .../internal/DeleteAllNodesInListImpl.java | 81 ++ .../chef/strategy/internal/ListClientsImpl.java | 109 +++ .../internal/ListCookbookVersionsImpl.java | 60 ++ .../ListCookbookVersionsInEnvironmentImpl.java | 117 +++ .../strategy/internal/ListEnvironmentsImpl.java | 96 +++ .../chef/strategy/internal/ListNodesImpl.java | 62 ++ .../internal/ListNodesInEnvironmentImpl.java | 62 ++ .../UpdateAutomaticAttributesOnNodeImpl.java | 75 ++ .../chef/suppliers/ChefVersionSupplier.java | 73 ++ .../org/jclouds/chef/test/TransientChefApi.java | 387 +++++++++ .../chef/test/TransientChefApiMetadata.java | 75 ++ .../test/config/TransientChefApiModule.java | 116 +++ .../java/org/jclouds/chef/util/ChefUtils.java | 71 ++ .../org/jclouds/chef/util/CollectionUtils.java | 69 ++ .../org/jclouds/chef/util/RunListBuilder.java | 83 ++ .../main/java/org/jclouds/ohai/Automatic.java | 33 + .../org/jclouds/ohai/AutomaticSupplier.java | 48 ++ .../org/jclouds/ohai/config/ConfiguresOhai.java | 28 + .../org/jclouds/ohai/config/JMXOhaiModule.java | 48 ++ .../org/jclouds/ohai/config/OhaiModule.java | 183 ++++ .../ohai/functions/ByteArrayToMacAddress.java | 51 ++ .../ohai/functions/MapSetToMultimap.java | 42 + .../jclouds/ohai/functions/NestSlashKeys.java | 156 ++++ .../ohai/suppliers/UptimeSecondsSupplier.java | 44 + .../services/org.jclouds.apis.ApiMetadata | 2 + .../src/test/clojure/org/jclouds/chef_test.clj | 70 ++ .../org/jclouds/chef/BaseChefApiExpectTest.java | 44 + .../org/jclouds/chef/ChefApiExpectTest.java | 279 ++++++ .../java/org/jclouds/chef/ChefApiLiveTest.java | 32 + .../org/jclouds/chef/ChefApiMetadataTest.java | 33 + .../test/java/org/jclouds/chef/ChefApiTest.java | 741 ++++++++++++++++ .../BindHexEncodedMD5sToJsonPayloadTest.java | 70 ++ .../chef/config/ChefParserModuleTest.java | 93 ++ .../chef/filters/SignedHeaderAuthTest.java | 213 +++++ .../functions/BootstrapConfigForGroupTest.java | 74 ++ .../chef/functions/ClientForGroupTest.java | 106 +++ .../chef/functions/GroupToBootScriptTest.java | 230 +++++ .../chef/functions/ParseClientFromJsonTest.java | 98 +++ ...okbookDefinitionCheckingChefVersionTest.java | 62 ++ .../ParseCookbookDefinitionFromJsonTest.java | 72 ++ .../ParseCookbookDefinitionFromJsonv10Test.java | 74 ++ ...seCookbookDefinitionListFromJsonv10Test.java | 92 ++ .../ParseCookbookVersionFromJsonTest.java | 129 +++ ...CookbookVersionsCheckingChefVersionTest.java | 62 ++ .../ParseCookbookVersionsV09FromJsonTest.java | 61 ++ .../ParseCookbookVersionsV10FromJsonTest.java | 68 ++ .../functions/ParseDataBagItemFromJsonTest.java | 65 ++ .../ParseErrorFromJsonOrReturnBodyTest.java | 42 + .../chef/functions/ParseKeySetFromJsonTest.java | 66 ++ .../chef/functions/ParseNodeFromJsonTest.java | 73 ++ .../functions/ParseSandboxFromJsonTest.java | 71 ++ .../ParseSearchDataBagItemFromJsonTest.java | 62 ++ .../ParseUploadSandboxFromJsonTest.java | 87 ++ .../chef/functions/RunListForGroupTest.java | 92 ++ .../chef/functions/UriForResourceTest.java | 54 ++ .../handlers/ChefApiErrorRetryHandlerTest.java | 115 +++ .../chef/internal/BaseChefApiLiveTest.java | 542 ++++++++++++ .../jclouds/chef/internal/BaseChefLiveTest.java | 96 +++ .../chef/internal/BaseChefServiceTest.java | 99 +++ .../chef/internal/BaseStubbedOhaiLiveTest.java | 60 ++ ...CleanupStaleNodesAndClientsImplLiveTest.java | 61 ++ ...PopulateAutomaticAttributesImplLiveTest.java | 62 ++ ...eAndPopulateAutomaticAttributesImplTest.java | 61 ++ ...DeleteAllApisAndNodesInListImplLiveTest.java | 64 ++ ...okbookVersionsInEnvironmentImplLiveTest.java | 217 +++++ .../internal/ListNodesImplLiveTest.java | 82 ++ .../ListNodesInEnvironmentImplLiveTest.java | 86 ++ ...teAutomaticAttributesOnNodeImplLiveTest.java | 61 ++ ...UpdateAutomaticAttributesOnNodeImplTest.java | 63 ++ .../chef/suppliers/ChefVersionSupplierTest.java | 47 + .../test/TransientChefApiIntegrationTest.java | 69 ++ .../chef/test/TransientChefApiMetadataTest.java | 33 + .../org/jclouds/chef/util/ChefUtilsTest.java | 57 ++ .../jclouds/chef/util/RunListBuilderTest.java | 71 ++ .../java/org/jclouds/ohai/config/JMXTest.java | 82 ++ .../org/jclouds/ohai/config/OhaiModuleTest.java | 147 ++++ .../functions/ByteArrayToMacAddressTest.java | 33 + .../ohai/functions/NestSlashKeysTest.java | 117 +++ .../resources/apache-chef-demo-cookbook.json | 46 + apis/chef/src/test/resources/bootstrap-env.sh | 56 ++ apis/chef/src/test/resources/bootstrap.sh | 56 ++ apis/chef/src/test/resources/brew-cookbook.json | 48 ++ apis/chef/src/test/resources/client.json | 8 + apis/chef/src/test/resources/clients_list.json | 5 + apis/chef/src/test/resources/data_list.json | 4 + apis/chef/src/test/resources/env_cookbooks.json | 20 + .../src/test/resources/environment_recipes.json | 6 + .../chef/src/test/resources/mysql-cookbook.json | 268 ++++++ apis/chef/src/test/resources/node.json | 10 + apis/chef/src/test/resources/nodes_list.json | 5 + apis/chef/src/test/resources/privkey.txt | 27 + apis/chef/src/test/resources/pubkey.txt | 9 + apis/chef/src/test/resources/roles_list.json | 4 + apis/chef/src/test/resources/sandbox.json | 12 + apis/chef/src/test/resources/search_role.json | 34 + .../src/test/resources/search_role_empty.json | 5 + .../src/test/resources/tomcat-cookbook.json | 121 +++ apis/chef/src/test/resources/upload-site.json | 13 + apis/pom.xml | 1 + project/pom.xml | 2 + providers/enterprise-chef/pom.xml | 110 +++ .../enterprisechef/EnterpriseChefApi.java | 124 +++ .../EnterpriseChefApiMetadata.java | 82 ++ .../EnterpriseChefProviderMetadata.java | 86 ++ .../BindGroupToUpdateRequestJsonPayload.java | 79 ++ .../enterprisechef/binders/GroupName.java | 38 + .../config/EnterpriseChefHttpApiModule.java | 36 + .../jclouds/enterprisechef/domain/Group.java | 211 +++++ .../org/jclouds/enterprisechef/domain/User.java | 220 +++++ .../org.jclouds.providers.ProviderMetadata | 1 + .../EnterpriseChefApiExpectTest.java | 209 +++++ .../EnterpriseChefApiLiveTest.java | 122 +++ .../EnterpriseChefProviderMetadataTest.java | 31 + ...BindGroupToUpdateRequestJsonPayloadTest.java | 82 ++ .../enterprisechef/binders/GroupNameTest.java | 40 + .../src/test/resources/group-update.json | 1 + .../src/test/resources/group.json | 14 + .../src/test/resources/groups.json | 7 + .../src/test/resources/user.json | 9 + providers/pom.xml | 1 + 201 files changed, 18721 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/jclouds/blob/867c7a40/apis/chef/pom.xml ---------------------------------------------------------------------- diff --git a/apis/chef/pom.xml b/apis/chef/pom.xml new file mode 100644 index 0000000..6d0d889 --- /dev/null +++ b/apis/chef/pom.xml @@ -0,0 +1,131 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + + 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. + +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>org.apache.jclouds</groupId> + <artifactId>jclouds-project</artifactId> + <version>1.8.0-SNAPSHOT</version> + <relativePath>../../project/pom.xml</relativePath> + </parent> + <groupId>org.apache.jclouds.api</groupId> + <artifactId>chef</artifactId> + <packaging>bundle</packaging> + <name>jclouds Chef api</name> + <description>jclouds components to access Chef</description> + + <properties> + <test.chef.endpoint>http://localhost:4000</test.chef.endpoint> + <test.chef.api-version /> + <test.chef.build-version /> + <test.chef.identity>chef-webui</test.chef.identity> + <test.chef.credential>${user.home}/.chef/webui.pem</test.chef.credential> + <jclouds.osgi.import>org.jclouds*;version=${project.version},*</jclouds.osgi.import> + <jclouds.osgi.export> + org.jclouds.chef*;version=${project.version};-noimport:=true, + org.jclouds.ohai*;version=${project.version};-noimport:=true, + </jclouds.osgi.export> + </properties> + + <dependencies> + <dependency> + <groupId>org.apache.jclouds</groupId> + <artifactId>jclouds-core</artifactId> + <version>${project.version}</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>org.apache.jclouds</groupId> + <artifactId>jclouds-core</artifactId> + <version>${project.version}</version> + <type>test-jar</type> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.apache.jclouds</groupId> + <artifactId>jclouds-scriptbuilder</artifactId> + <version>${project.version}</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>org.apache.jclouds</groupId> + <artifactId>jclouds-scriptbuilder</artifactId> + <version>${project.version}</version> + <type>test-jar</type> + <scope>test</scope> + </dependency> + <!-- for ohai --> + <dependency> + <groupId>com.google.inject.extensions</groupId> + <artifactId>guice-multibindings</artifactId> + <version>3.0</version> + </dependency> + <!-- for transient chef provider --> + <dependency> + <groupId>org.apache.jclouds</groupId> + <artifactId>jclouds-blobstore</artifactId> + <version>${project.version}</version> + <optional>true</optional> + </dependency> + <dependency> + <groupId>org.apache.jclouds.driver</groupId> + <artifactId>jclouds-slf4j</artifactId> + <version>${project.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>ch.qos.logback</groupId> + <artifactId>logback-classic</artifactId> + <scope>test</scope> + </dependency> + </dependencies> + + <profiles> + <profile> + <id>live</id> + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-surefire-plugin</artifactId> + <executions> + <execution> + <id>integration</id> + <phase>integration-test</phase> + <goals> + <goal>test</goal> + </goals> + <configuration> + <systemPropertyVariables> + <test.chef.endpoint>${test.chef.endpoint}</test.chef.endpoint> + <test.chef.api-version>${test.chef.api-version}</test.chef.api-version> + <test.chef.build-version>${test.chef.build-version}</test.chef.build-version> + <test.chef.identity>${test.chef.identity}</test.chef.identity> + <test.chef.credential>${test.chef.credential}</test.chef.credential> + </systemPropertyVariables> + </configuration> + </execution> + </executions> + </plugin> + </plugins> + </build> + </profile> + </profiles> +</project> http://git-wip-us.apache.org/repos/asf/jclouds/blob/867c7a40/apis/chef/src/main/clojure/org/jclouds/chef.clj ---------------------------------------------------------------------- diff --git a/apis/chef/src/main/clojure/org/jclouds/chef.clj b/apis/chef/src/main/clojure/org/jclouds/chef.clj new file mode 100644 index 0000000..ad0f200 --- /dev/null +++ b/apis/chef/src/main/clojure/org/jclouds/chef.clj @@ -0,0 +1,261 @@ +; +; 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 Opscode 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 opscode 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)))))) http://git-wip-us.apache.org/repos/asf/jclouds/blob/867c7a40/apis/chef/src/main/java/org/jclouds/chef/ChefApi.java ---------------------------------------------------------------------- diff --git a/apis/chef/src/main/java/org/jclouds/chef/ChefApi.java b/apis/chef/src/main/java/org/jclouds/chef/ChefApi.java new file mode 100644 index 0000000..13f4971 --- /dev/null +++ b/apis/chef/src/main/java/org/jclouds/chef/ChefApi.java @@ -0,0 +1,853 @@ +/* + * 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. + */ +package org.jclouds.chef; + +import java.io.Closeable; +import java.io.InputStream; +import java.net.URI; +import java.util.List; +import java.util.Set; + +import javax.inject.Named; +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; + +import org.jclouds.Constants; +import org.jclouds.Fallbacks.EmptySetOnNotFoundOr404; +import org.jclouds.Fallbacks.NullOnNotFoundOr404; +import org.jclouds.Fallbacks.VoidOnNotFoundOr404; +import org.jclouds.chef.binders.BindChecksumsToJsonPayload; +import org.jclouds.chef.binders.BindCreateClientOptionsToJsonPayload; +import org.jclouds.chef.binders.BindGenerateKeyForClientToJsonPayload; +import org.jclouds.chef.binders.DatabagItemId; +import org.jclouds.chef.binders.EnvironmentName; +import org.jclouds.chef.binders.NodeName; +import org.jclouds.chef.binders.RoleName; +import org.jclouds.chef.domain.Client; +import org.jclouds.chef.domain.CookbookDefinition; +import org.jclouds.chef.domain.CookbookVersion; +import org.jclouds.chef.domain.DatabagItem; +import org.jclouds.chef.domain.Environment; +import org.jclouds.chef.domain.Node; +import org.jclouds.chef.domain.Resource; +import org.jclouds.chef.domain.Role; +import org.jclouds.chef.domain.Sandbox; +import org.jclouds.chef.domain.SearchResult; +import org.jclouds.chef.domain.UploadSandbox; +import org.jclouds.chef.filters.SignedHeaderAuth; +import org.jclouds.chef.functions.ParseCookbookDefinitionCheckingChefVersion; +import org.jclouds.chef.functions.ParseCookbookDefinitionFromJsonv10; +import org.jclouds.chef.functions.ParseCookbookDefinitionListFromJsonv10; +import org.jclouds.chef.functions.ParseCookbookVersionsCheckingChefVersion; +import org.jclouds.chef.functions.ParseKeySetFromJson; +import org.jclouds.chef.functions.ParseSearchClientsFromJson; +import org.jclouds.chef.functions.ParseSearchDatabagFromJson; +import org.jclouds.chef.functions.ParseSearchEnvironmentsFromJson; +import org.jclouds.chef.functions.ParseSearchNodesFromJson; +import org.jclouds.chef.functions.ParseSearchRolesFromJson; +import org.jclouds.chef.functions.UriForResource; +import org.jclouds.chef.options.CreateClientOptions; +import org.jclouds.chef.options.SearchOptions; +import org.jclouds.io.Payload; +import org.jclouds.rest.annotations.BinderParam; +import org.jclouds.rest.annotations.EndpointParam; +import org.jclouds.rest.annotations.Fallback; +import org.jclouds.rest.annotations.Headers; +import org.jclouds.rest.annotations.MapBinder; +import org.jclouds.rest.annotations.ParamParser; +import org.jclouds.rest.annotations.PayloadParam; +import org.jclouds.rest.annotations.RequestFilters; +import org.jclouds.rest.annotations.ResponseParser; +import org.jclouds.rest.annotations.SelectJson; +import org.jclouds.rest.annotations.SinceApiVersion; +import org.jclouds.rest.annotations.SkipEncoding; +import org.jclouds.rest.annotations.WrapWith; +import org.jclouds.rest.binders.BindToJsonPayload; + +/** + * Provides synchronous access to Chef. + */ +@RequestFilters(SignedHeaderAuth.class) +@Headers(keys = "X-Chef-Version", values = "{" + Constants.PROPERTY_API_VERSION + "}") +@Consumes(MediaType.APPLICATION_JSON) +public interface ChefApi extends Closeable { + + // Clients + + /** + * Lists the names of the existing clients. + * + * @return The names of the existing clients. + */ + @Named("client:list") + @GET + @Path("/clients") + @ResponseParser(ParseKeySetFromJson.class) + @Fallback(EmptySetOnNotFoundOr404.class) + Set<String> listClients(); + + /** + * Gets the details of existing client. + * + * @param clientname The name of the client to get. + * @return The details of the given client. + */ + @Named("client:get") + @GET + @Path("/clients/{clientname}") + @Fallback(NullOnNotFoundOr404.class) + Client getClient(@PathParam("clientname") String clientName); + + /** + * Creates a new client. + * + * @param clientname The name of the new client + * @return The client with the generated private key. This key should be + * stored so client can be properly authenticated . + */ + @Named("client:create") + @POST + @Path("/clients") + @MapBinder(BindToJsonPayload.class) + Client createClient(@PayloadParam("name") String clientName); + + /** + * Creates a new client with custom options. + * + * @param clientname The name of the new client + * @param options The options to customize the client creation. + * @return The client with the generated private key. This key should be + * stored so client can be properly authenticated . + */ + @Named("client:create") + @POST + @Path("/clients") + @MapBinder(BindCreateClientOptionsToJsonPayload.class) + Client createClient(@PayloadParam("name") String clientName, CreateClientOptions options); + + /** + * Generates a new key-pair for this client, and return the new private key in + * the response body. + * + * @param clientname The name of the client. + * @return The details of the client with the new private key. + */ + @Named("client:generatekey") + @PUT + @Path("/clients/{clientname}") + Client generateKeyForClient( + @PathParam("clientname") @BinderParam(BindGenerateKeyForClientToJsonPayload.class) String clientName); + + /** + * Deletes the given client. + * + * @param clientname The name of the client to delete. + * @return The deleted client. + */ + @Named("client:delete") + @DELETE + @Path("/clients/{clientname}") + @Fallback(NullOnNotFoundOr404.class) + Client deleteClient(@PathParam("clientname") String clientName); + + // Cookbooks + + /** + * Lists the names of the existing cookbooks. + * + * @return The names of the exsisting cookbooks. + */ + @Named("cookbook:list") + @GET + @Path("/cookbooks") + @ResponseParser(ParseCookbookDefinitionCheckingChefVersion.class) + @Fallback(EmptySetOnNotFoundOr404.class) + Set<String> listCookbooks(); + + /** + * Lists the cookbooks that are available in the given environment. + * + * @param environmentname The name of the environment to get the cookbooks + * from. + * @return The definitions of the cookbooks (name, URL and versions) available in + * the given environment. + */ + @SinceApiVersion("0.10.0") + @Named("cookbook:list") + @GET + @ResponseParser(ParseCookbookDefinitionListFromJsonv10.class) + @Path("/environments/{environmentname}/cookbooks") + @Fallback(EmptySetOnNotFoundOr404.class) + Set<CookbookDefinition> listCookbooksInEnvironment(@PathParam("environmentname") String environmentName); + + /** + * Lists the cookbooks that are available in the given environment, limiting + * the number of versions returned for each cookbook. + * + * @param environmentname The name of the environment to get the cookbooks + * from. + * @param numversions The number of cookbook versions to include in the + * response, where n is the number of cookbook versions. + * @return The definitions of the cookbooks (name, URL and versions) available in + * the given environment. + */ + @SinceApiVersion("0.10.0") + @Named("cookbook:list") + @GET + @ResponseParser(ParseCookbookDefinitionListFromJsonv10.class) + @Path("/environments/{environmentname}/cookbooks?num_versions={numversions}") + @Fallback(EmptySetOnNotFoundOr404.class) + Set<CookbookDefinition> listCookbooksInEnvironment(@PathParam("environmentname") String environmentName, + @PathParam("numversions") String numVersions); + + /** + * Lists the available versions of the given cookbook. + * + * @param cookbookName The name of the cookbook. + * @return The available versions of the given cookbook. + */ + @Named("cookbook:versions") + @GET + @Path("/cookbooks/{cookbookname}") + @ResponseParser(ParseCookbookVersionsCheckingChefVersion.class) + @Fallback(EmptySetOnNotFoundOr404.class) + Set<String> listVersionsOfCookbook(@PathParam("cookbookname") String cookbookName); + + /** + * Gets the details of the given cookbook, with the links to each resource + * such as recipe files, attributes, etc. + * + * @param cookbookName The name of the cookbook. + * @param version The version of the cookbook to get. + * @return The details of the given cookbook. + */ + @Named("cookbook:get") + @GET + @Path("/cookbooks/{cookbookname}/{version}") + @Fallback(NullOnNotFoundOr404.class) + CookbookVersion getCookbook(@PathParam("cookbookname") String cookbookName, @PathParam("version") String version); + + /** + * Gets the definition of the cookbook in the given environment. + * + * @param environmentname The name of the environment. + * @param cookbookname The name of the cookbook. + * @return The definition of the cookbook (URL and versions) of the cookbook + * in the given environment. + */ + @SinceApiVersion("0.10.0") + @Named("environment:cookbook") + @GET + @ResponseParser(ParseCookbookDefinitionFromJsonv10.class) + @Path("/environments/{environmentname}/cookbooks/{cookbookname}") + CookbookDefinition getCookbookInEnvironment(@PathParam("environmentname") String environmentName, + @PathParam("cookbookname") String cookbookName); + + /** + * Gets the definition of the cookbook in the given environment. + * + * @param environmentname The name of the environment. + * @param cookbookname The name of the cookbook. + * @param numversions The number of cookbook versions to include in the + * response, where n is the number of cookbook versions. + * @return The definition of the cookbook (URL and versions) of the cookbook + * in the given environment. + */ + @SinceApiVersion("0.10.0") + @Named("environment:cookbook") + @GET + @ResponseParser(ParseCookbookDefinitionFromJsonv10.class) + @Path("/environments/{environmentname}/cookbooks/{cookbookname}?num_versions={numversions}") + CookbookDefinition getCookbookInEnvironment(@PathParam("environmentname") String environmentName, + @PathParam("cookbookname") String cookbookName, @PathParam("numversions") String numVersions); + + /** + * Lists the names of the recipes in the given environment. + * + * @param environmentname The name of the environment. + * @return The names of the recipes in the given environment. + */ + @SinceApiVersion("0.10.0") + @Named("environment:recipelist") + @GET + @Path("/environments/{environmentname}/recipes") + @Fallback(EmptySetOnNotFoundOr404.class) + Set<String> listRecipesInEnvironment(@PathParam("environmentname") String environmentName); + + /** + * Creates or updates the given cookbook. + * + * @param cookbookName The name of the cookbook to create or update. + * @param version The version of the cookbook to create or update. + * @param cookbook The contents of the cookbook to create or update. + * @return The details of the created or updated cookbook. + */ + @Named("cookbook:update") + @PUT + @Path("/cookbooks/{cookbookname}/{version}") + CookbookVersion updateCookbook(@PathParam("cookbookname") String cookbookName, @PathParam("version") String version, + @BinderParam(BindToJsonPayload.class) CookbookVersion cookbook); + + /** + * Deletes the given cookbook. + * + * @param cookbookName The name of the cookbook to delete. + * @param version The version of the cookbook to delete. + * @return The details of the deleted cookbook. + */ + @Named("cookbook:delete") + @DELETE + @Path("/cookbooks/{cookbookname}/{version}") + @Fallback(NullOnNotFoundOr404.class) + CookbookVersion deleteCookbook(@PathParam("cookbookname") String cookbookName, @PathParam("version") String version); + + // Data bags + + /** + * Lists the names of the existing data bags. + * + * @return The names of the existing data bags. + */ + @Named("databag:list") + @GET + @Path("/data") + @ResponseParser(ParseKeySetFromJson.class) + @Fallback(EmptySetOnNotFoundOr404.class) + Set<String> listDatabags(); + + /** + * Creates a new data bag. + * + * @param databagName The name for the new data bag. + */ + @Named("databag:create") + @POST + @Path("/data") + void createDatabag(@WrapWith("name") String databagName); + + /** + * Deletes a data bag, including its items. + * + * @param databagName The name of the data bag to delete. + */ + @Named("databag:delete") + @DELETE + @Path("/data/{name}") + @Fallback(VoidOnNotFoundOr404.class) + void deleteDatabag(@PathParam("name") String databagName); + + /** + * Lists the names of the items in a data bag. + * + * @param databagName The name of the data bag. + * @return The names of the items in the given data bag. + */ + @Named("databag:listitems") + @GET + @Path("/data/{name}") + @ResponseParser(ParseKeySetFromJson.class) + @Fallback(EmptySetOnNotFoundOr404.class) + Set<String> listDatabagItems(@PathParam("name") String databagName); + + /** + * Gets an item in a data bag. + * + * @param databagName The name of the data bag. + * @param databagItemId The identifier of the item to get. + * @return The details of the item in the given data bag. + */ + @Named("databag:getitem") + @GET + @Path("/data/{databagName}/{databagItemId}") + @Fallback(NullOnNotFoundOr404.class) + DatabagItem getDatabagItem(@PathParam("databagName") String databagName, + @PathParam("databagItemId") String databagItemId); + + /** + * Adds an item in a data bag. + * + * @param databagName The name of the data bag. + * @param The item to add to the data bag. + * @param The item just added to the data bag. + */ + @Named("databag:createitem") + @POST + @Path("/data/{databagName}") + DatabagItem createDatabagItem(@PathParam("databagName") String databagName, + @BinderParam(BindToJsonPayload.class) DatabagItem databagItem); + + /** + * Updates an item in a data bag. + * + * @param databagName The name of the data bag. + * @param item The new contents for the item in the data bag. + * @return The details for the updated item in the data bag. + */ + @Named("databag:updateitem") + @PUT + @Path("/data/{databagName}/{databagItemId}") + DatabagItem updateDatabagItem( + @PathParam("databagName") String databagName, + @PathParam("databagItemId") @ParamParser(DatabagItemId.class) @BinderParam(BindToJsonPayload.class) DatabagItem item); + + /** + * Deletes an item from a data bag. + * + * @param databagName The name of the data bag. + * @param databagItemId The identifier of the item to delete. + * @return The item deleted from the data bag. + */ + @Named("databag:deleteitem") + @DELETE + @Path("/data/{databagName}/{databagItemId}") + @Fallback(NullOnNotFoundOr404.class) + @SelectJson("raw_data") + DatabagItem deleteDatabagItem(@PathParam("databagName") String databagName, + @PathParam("databagItemId") String databagItemId); + + // Environments + + /** + * Lists the names of the existing environments. + * + * @return The names of the existing environments. + */ + @SinceApiVersion("0.10.0") + @Named("environment:list") + @GET + @Path("/environments") + @ResponseParser(ParseKeySetFromJson.class) + @Fallback(EmptySetOnNotFoundOr404.class) + Set<String> listEnvironments(); + + /** + * Gets the details of an existing environment. + * + * @param environmentname The name of the environment to get. + * @return The details of the given environment. + */ + @SinceApiVersion("0.10.0") + @Named("environment:get") + @GET + @Path("/environments/{environmentname}") + @Fallback(NullOnNotFoundOr404.class) + Environment getEnvironment(@PathParam("environmentname") String environmentName); + + /** + * Creates a new environment. + * + * @param environment The environment to create. + */ + @SinceApiVersion("0.10.0") + @Named("environment:create") + @POST + @Path("/environments") + void createEnvironment(@BinderParam(BindToJsonPayload.class) Environment environment); + + /** + * Updates the given environment. + * + * @param environment The new details for the environment. + * @return The details of the updated environment. + */ + @SinceApiVersion("0.10.0") + @Named("environment:update") + @PUT + @Path("/environments/{environmentname}") + Environment updateEnvironment( + @PathParam("environmentname") @ParamParser(EnvironmentName.class) @BinderParam(BindToJsonPayload.class) Environment environment); + + /** + * Deletes the given environment. + * + * @param environmentname The name of the environment to delete. + * @return The details of the deleted environment. + */ + @SinceApiVersion("0.10.0") + @Named("environment:delete") + @DELETE + @Path("/environments/{environmentname}") + @Fallback(NullOnNotFoundOr404.class) + Environment deleteEnvironment(@PathParam("environmentname") String environmentName); + + // Nodes + + /** + * Lists the names of the existing nodes. + * + * @return The names of the existing nodes. + */ + @Named("node:list") + @GET + @Path("/nodes") + @ResponseParser(ParseKeySetFromJson.class) + @Fallback(EmptySetOnNotFoundOr404.class) + Set<String> listNodes(); + + /** + * Lists the names of the nodes in the given environment. + * + * @param environmentname The name of the environment. + * @return The names of the existing nodes in the given environment. + */ + @SinceApiVersion("0.10.0") + @Named("environment:nodelist") + @GET + @Path("/environments/{environmentname}/nodes") + @ResponseParser(ParseKeySetFromJson.class) + @Fallback(EmptySetOnNotFoundOr404.class) + Set<String> listNodesInEnvironment(@PathParam("environmentname") String environmentName); + + /** + * Gets the details of the given node. + * + * @param nodename The name of the node to get. + * @return The details of the given node. + */ + @Named("node:get") + @GET + @Path("/nodes/{nodename}") + @Fallback(NullOnNotFoundOr404.class) + Node getNode(@PathParam("nodename") String nodeName); + + /** + * Creates a new node. + * + * @param node The details of the node to create. + */ + @Named("node:create") + @POST + @Path("/nodes") + void createNode(@BinderParam(BindToJsonPayload.class) Node node); + + /** + * Updates an existing node. + * + * @param node The new details for the node. + * @return The details of the updated node. + */ + @Named("node:update") + @PUT + @Path("/nodes/{nodename}") + Node updateNode(@PathParam("nodename") @ParamParser(NodeName.class) @BinderParam(BindToJsonPayload.class) Node node); + + /** + * Deletes the given node. + * + * @param nodename The name of the node to delete. + * @return The details of the deleted node. + */ + @Named("node:delete") + @DELETE + @Path("/nodes/{nodename}") + @Fallback(NullOnNotFoundOr404.class) + Node deleteNode(@PathParam("nodename") String nodeName); + + // Roles + + /** + * Lists the names of the existing roles. + * + * @return The names of the existing roles. + */ + @Named("role:list") + @GET + @Path("/roles") + @ResponseParser(ParseKeySetFromJson.class) + @Fallback(EmptySetOnNotFoundOr404.class) + Set<String> listRoles(); + + /** + * Gets the details of the given role. + * + * @param rolename The name of the role to get. + * @return The details of the given role. + */ + @Named("role:get") + @GET + @Path("/roles/{rolename}") + @Fallback(NullOnNotFoundOr404.class) + Role getRole(@PathParam("rolename") String roleName); + + /** + * Creates a new role. + * + * @param role The details for the new role. + */ + @Named("role:create") + @POST + @Path("/roles") + void createRole(@BinderParam(BindToJsonPayload.class) Role role); + + /** + * Updates the given role. + * + * @param role The new details for the role. + * @return The details of the updated role. + */ + @Named("role:update") + @PUT + @Path("/roles/{rolename}") + Role updateRole(@PathParam("rolename") @ParamParser(RoleName.class) @BinderParam(BindToJsonPayload.class) Role role); + + /** + * Deletes the given role. + * + * @param rolename The name of the role to delete. + * @return The details of the deleted role. + */ + @Named("role:delete") + @DELETE + @Path("/roles/{rolename}") + @Fallback(NullOnNotFoundOr404.class) + Role deleteRole(@PathParam("rolename") String roleName); + + // Sandboxes + + /** + * Creates a new sandbox. + * <p> + * It accepts a list of checksums as input and returns the URLs against which + * to PUT files that need to be uploaded. + * + * @param md5s The raw md5 sums. Uses {@code Bytes.asList()} and + * {@code Bytes.toByteArray()} as necessary + * @return The upload sandbox with the URLs against which to PUT files that + * need to be uploaded. + */ + @Named("sandbox:upload") + @POST + @Path("/sandboxes") + UploadSandbox createUploadSandboxForChecksums(@BinderParam(BindChecksumsToJsonPayload.class) Set<List<Byte>> md5s); + + /** + * Uploads the given content to the sandbox at the given URI. + * <p> + * The URI must be obtained, after uploading a sandbox, from the + * {@link UploadSandbox#getUri()}. + * + * @param location The URI where the upload must be performed. + * @param content The contents to upload. + */ + @Named("content:upload") + @PUT + @Produces("application/x-binary") + void uploadContent(@EndpointParam URI location, Payload content); + + /** + * Gets the contents of the given resource. + * + * @param resource The resource to get. + * @return An input stream for the content of the requested resource. + */ + @Named("content:get") + @GET + @Fallback(NullOnNotFoundOr404.class) + @SkipEncoding({ '+', ' ', '/', '=', ':', ';' }) + InputStream getResourceContents(@EndpointParam(parser = UriForResource.class) Resource resource); + + /** + * Confirms if the sandbox is completed or not. + * <p> + * This method should be used after uploading contents to the sandbox. + * + * @param id The id of the sandbox to commit. + * @param isCompleted Flag to set if the sandbox is completed or not. + * @return The details of the sandbox. + */ + @Named("sandbox:commit") + @PUT + @Path("/sandboxes/{id}") + Sandbox commitSandbox(@PathParam("id") String id, @WrapWith("is_completed") boolean isCompleted); + + // Search + + /** + * Lists the names of the available search indexes. + * <p> + * By default, the "role", "node" and "api" indexes will always be available. + * <p> + * Note that the search indexes may lag behind the most current data by at + * least 10 seconds at any given time - so if you need to write data and + * immediately query it, you likely need to produce an artificial delay (or + * simply retry until the data is available). + * + * @return The names of the available search indexes. + */ + @Named("search:indexes") + @GET + @Path("/search") + @ResponseParser(ParseKeySetFromJson.class) + @Fallback(EmptySetOnNotFoundOr404.class) + Set<String> listSearchIndexes(); + + /** + * Searches all clients. + * <p> + * Note that without any request parameters this will return all of the data + * within the index. + * + * @return The response contains the total number of rows that matched the + * request, the position this result set returns (useful for paging) + * and the rows themselves. + */ + @Named("search:clients") + @GET + @Path("/search/client") + @ResponseParser(ParseSearchClientsFromJson.class) + SearchResult<? extends Client> searchClients(); + + /** + * Searches all clients that match the given options. + * + * @return The response contains the total number of rows that matched the + * request, the position this result set returns (useful for paging) + * and the rows themselves. + */ + @Named("search:clients") + @GET + @Path("/search/client") + @ResponseParser(ParseSearchClientsFromJson.class) + SearchResult<? extends Client> searchClients(SearchOptions options); + + /** + * Searches all items in a data bag. + * <p> + * Note that without any request parameters this will return all of the data + * within the index. + * + * @return The response contains the total number of rows that matched the + * request, the position this result set returns (useful for paging) + * and the rows themselves. + */ + @Named("search:databag") + @GET + @Path("/search/{databagName}") + @ResponseParser(ParseSearchDatabagFromJson.class) + SearchResult<? extends DatabagItem> searchDatabagItems(@PathParam("databagName") String databagName); + + /** + * Searches all items in a data bag that match the given options. + * + * @return The response contains the total number of rows that matched the + * request, the position this result set returns (useful for paging) + * and the rows themselves. + */ + @Named("search:databag") + @GET + @Path("/search/{databagName}") + @ResponseParser(ParseSearchDatabagFromJson.class) + SearchResult<? extends DatabagItem> searchDatabagItems(@PathParam("databagName") String databagName, + SearchOptions options); + + /** + * Searches all environments. + * <p> + * Note that without any request parameters this will return all of the data + * within the index. + * + * @return The response contains the total number of rows that matched the + * request, the position this result set returns (useful for paging) + * and the rows themselves. + */ + @SinceApiVersion("0.10.0") + @Named("search:environments") + @GET + @Path("/search/environment") + @ResponseParser(ParseSearchEnvironmentsFromJson.class) + SearchResult<? extends Environment> searchEnvironments(); + + /** + * Searches all environments that match the given options. + * + * @return The response contains the total number of rows that matched the + * request, the position this result set returns (useful for paging) + * and the rows themselves. + */ + @SinceApiVersion("0.10.0") + @Named("search:environments") + @GET + @Path("/search/environment") + @ResponseParser(ParseSearchEnvironmentsFromJson.class) + SearchResult<? extends Environment> searchEnvironments(SearchOptions options); + + /** + * Searches all nodes. + * <p> + * Note that without any request parameters this will return all of the data + * within the index. + * + * @return The response contains the total number of rows that matched the + * request, the position this result set returns (useful for paging) + * and the rows themselves. + */ + @Named("search:nodes") + @GET + @Path("/search/node") + @ResponseParser(ParseSearchNodesFromJson.class) + SearchResult<? extends Node> searchNodes(); + + /** + * Searches all nodes that match the given options. + * + * @return The response contains the total number of rows that matched the + * request, the position this result set returns (useful for paging) + * and the rows themselves. + */ + @Named("search:nodes") + @GET + @Path("/search/node") + @ResponseParser(ParseSearchNodesFromJson.class) + SearchResult<? extends Node> searchNodes(SearchOptions options); + + /** + * Searches all roles. + * <p> + * Note that without any request parameters this will return all of the data + * within the index. + * + * @return The response contains the total number of rows that matched the + * request, the position this result set returns (useful for paging) + * and the rows themselves. + */ + @Named("search:roles") + @GET + @Path("/search/role") + @ResponseParser(ParseSearchRolesFromJson.class) + SearchResult<? extends Role> searchRoles(); + + /** + * Searches all roles that match the given options. + * + * @return The response contains the total number of rows that matched the + * request, the position this result set returns (useful for paging) + * and the rows themselves. + */ + @Named("search:roles") + @GET + @Path("/search/role") + @ResponseParser(ParseSearchRolesFromJson.class) + SearchResult<? extends Role> searchRoles(SearchOptions options); + +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/867c7a40/apis/chef/src/main/java/org/jclouds/chef/ChefApiMetadata.java ---------------------------------------------------------------------- diff --git a/apis/chef/src/main/java/org/jclouds/chef/ChefApiMetadata.java b/apis/chef/src/main/java/org/jclouds/chef/ChefApiMetadata.java new file mode 100644 index 0000000..ede03e9 --- /dev/null +++ b/apis/chef/src/main/java/org/jclouds/chef/ChefApiMetadata.java @@ -0,0 +1,110 @@ +/* + * 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. + */ +package org.jclouds.chef; + +import static java.util.concurrent.TimeUnit.MINUTES; +import static java.util.concurrent.TimeUnit.SECONDS; +import static org.jclouds.Constants.PROPERTY_SESSION_INTERVAL; +import static org.jclouds.Constants.PROPERTY_TIMEOUTS_PREFIX; +import static org.jclouds.chef.config.ChefProperties.CHEF_BOOTSTRAP_DATABAG; +import static org.jclouds.chef.config.ChefProperties.CHEF_UPDATE_GEMS; +import static org.jclouds.chef.config.ChefProperties.CHEF_UPDATE_GEM_SYSTEM; +import static org.jclouds.chef.config.ChefProperties.CHEF_USE_OMNIBUS; + +import java.net.URI; +import java.util.Properties; + +import org.jclouds.chef.config.ChefBootstrapModule; +import org.jclouds.chef.config.ChefHttpApiModule; +import org.jclouds.chef.config.ChefParserModule; +import org.jclouds.ohai.config.JMXOhaiModule; +import org.jclouds.rest.internal.BaseHttpApiMetadata; + +import com.google.common.collect.ImmutableSet; +import com.google.inject.Module; + +/** + * Implementation of {@link ApiMetadata} for OpsCode's Chef api. + */ +public class ChefApiMetadata extends BaseHttpApiMetadata<ChefApi> { + + /** + * The default Chef Server API version to use. + */ + public static final String DEFAULT_API_VERSION = "0.10.8"; + + @Override + public Builder toBuilder() { + return new Builder().fromApiMetadata(this); + } + + public ChefApiMetadata() { + this(new Builder()); + } + + protected ChefApiMetadata(Builder builder) { + super(builder); + } + + public static Properties defaultProperties() { + Properties properties = BaseHttpApiMetadata.defaultProperties(); + properties.setProperty(PROPERTY_TIMEOUTS_PREFIX + "default", SECONDS.toMillis(30) + ""); + properties.setProperty(PROPERTY_TIMEOUTS_PREFIX + "ChefApi.updateCookbook", MINUTES.toMillis(10) + ""); + properties.setProperty(PROPERTY_TIMEOUTS_PREFIX + "ChefApi.createClient", MINUTES.toMillis(2) + ""); + properties.setProperty(PROPERTY_TIMEOUTS_PREFIX + "ChefApi.generateKeyForClient", MINUTES.toMillis(2) + ""); + properties.setProperty(PROPERTY_TIMEOUTS_PREFIX + "ChefApi.createNode", MINUTES.toMillis(2) + ""); + properties.setProperty(PROPERTY_TIMEOUTS_PREFIX + "ChefApi.updateNode", MINUTES.toMillis(10) + ""); + properties.setProperty(PROPERTY_TIMEOUTS_PREFIX + "ChefApi.createRole", MINUTES.toMillis(2) + ""); + properties.setProperty(PROPERTY_TIMEOUTS_PREFIX + "ChefApi.updateRole", MINUTES.toMillis(10) + ""); + properties.setProperty(PROPERTY_TIMEOUTS_PREFIX + "ChefApi.createEnvironment", MINUTES.toMillis(2) + ""); + properties.setProperty(PROPERTY_SESSION_INTERVAL, "1"); + properties.setProperty(CHEF_BOOTSTRAP_DATABAG, "bootstrap"); + properties.setProperty(CHEF_UPDATE_GEM_SYSTEM, "false"); + properties.setProperty(CHEF_UPDATE_GEMS, "false"); + properties.setProperty(CHEF_USE_OMNIBUS, "true"); + return properties; + } + + public static class Builder extends BaseHttpApiMetadata.Builder<ChefApi, Builder> { + + protected Builder() { + id("chef") + .name("OpsCode Chef Api") + .identityName("User") + .credentialName("Certificate") + .version(DEFAULT_API_VERSION) + .documentation(URI.create("http://wiki.opscode.com/display/chef/Server+API")) + .defaultEndpoint("http://localhost:4000") + .defaultProperties(ChefApiMetadata.defaultProperties()) + .view(ChefContext.class) + .defaultModules( + ImmutableSet.<Class<? extends Module>> of(ChefHttpApiModule.class, ChefParserModule.class, + ChefBootstrapModule.class, JMXOhaiModule.class)); + } + + @Override + public ChefApiMetadata build() { + return new ChefApiMetadata(this); + } + + @Override + protected Builder self() { + return this; + } + } + +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/867c7a40/apis/chef/src/main/java/org/jclouds/chef/ChefContext.java ---------------------------------------------------------------------- diff --git a/apis/chef/src/main/java/org/jclouds/chef/ChefContext.java b/apis/chef/src/main/java/org/jclouds/chef/ChefContext.java new file mode 100644 index 0000000..7809634 --- /dev/null +++ b/apis/chef/src/main/java/org/jclouds/chef/ChefContext.java @@ -0,0 +1,37 @@ +/* + * 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. + */ +package org.jclouds.chef; + +import java.io.Closeable; + +import org.jclouds.View; +import org.jclouds.chef.internal.ChefContextImpl; + +import com.google.inject.ImplementedBy; + +/** + * Provides an entry point to Chef features. + */ +@ImplementedBy(ChefContextImpl.class) +public interface ChefContext extends View, Closeable { + + /** + * Provides access to high level Chef features. + */ + ChefService getChefService(); + +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/867c7a40/apis/chef/src/main/java/org/jclouds/chef/ChefService.java ---------------------------------------------------------------------- diff --git a/apis/chef/src/main/java/org/jclouds/chef/ChefService.java b/apis/chef/src/main/java/org/jclouds/chef/ChefService.java new file mode 100644 index 0000000..040107a --- /dev/null +++ b/apis/chef/src/main/java/org/jclouds/chef/ChefService.java @@ -0,0 +1,263 @@ +/* + * 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. + */ +package org.jclouds.chef; + +import com.google.common.io.InputSupplier; +import com.google.inject.ImplementedBy; +import org.jclouds.chef.domain.BootstrapConfig; +import org.jclouds.chef.domain.Client; +import org.jclouds.chef.domain.CookbookVersion; +import org.jclouds.chef.domain.Environment; +import org.jclouds.chef.domain.Node; +import org.jclouds.chef.internal.BaseChefService; +import org.jclouds.domain.JsonBall; +import org.jclouds.rest.annotations.SinceApiVersion; +import org.jclouds.scriptbuilder.domain.Statement; + +import java.io.IOException; +import java.io.InputStream; +import java.util.List; +import java.util.concurrent.ExecutorService; + +/** + * Provides high level Chef operations. + */ +@ImplementedBy(BaseChefService.class) +public interface ChefService { + + /** + * Gets the context that created this service. + * + * @return The context that created the service. + */ + ChefContext getContext(); + + // Crypto + + /** + * Encrypts the given input stream. + * + * @param supplier The input stream to encrypt. + * @return The encrypted bytes for the given input stream. + * @throws IOException If there is an error reading from the input stream. + */ + byte[] encrypt(InputSupplier<? extends InputStream> supplier) throws IOException; + + /** + * Decrypts the given input stream. + * + * @param supplier The input stream to decrypt. + * @return The decrypted bytes for the given input stream. + * @throws IOException If there is an error reading from the input stream. + */ + byte[] decrypt(InputSupplier<? extends InputStream> supplier) throws IOException; + + // Bootstrap + + /** + * Creates all steps necessary to bootstrap the node. + * + * @param group corresponds to a configured + * {@link ChefProperties#CHEF_BOOTSTRAP_DATABAG} data bag where + * run_list and other information are stored. + * @return The script used to bootstrap the node. + */ + Statement createBootstrapScriptForGroup(String group); + + /** + * Configures how the nodes of a certain group will be bootstrapped + * + * @param group The group where the given bootstrap configuration will be + * applied. + * @param bootstrapConfig The configuration to be applied to the nodes in the + * group. + */ + void updateBootstrapConfigForGroup(String group, BootstrapConfig bootstrapConfig); + + /** + * Gets the run list for the given group. + * + * @param The group to get the configured run list for. + * @return run list for all nodes bootstrapped with a certain group + */ + List<String> getRunListForGroup(String group); + + /** + * Gets the bootstrap configuration for a given group. + * <p/> + * The bootstrap configuration is a Json object containing the run list and + * the configured attributes. + * + * @param group The name of the group. + * @return The bootstrap configuration for the given group. + */ + JsonBall getBootstrapConfigForGroup(String group); + + // Nodes / Clients + + /** + * Creates a new node and populates the automatic attributes. + * + * @param nodeName The name of the node to create. + * @param runList The run list for the created node. + * @return The created node with the automatic attributes populated. + * @see OhaiModule + * @see ChefUtils#ohaiAutomaticAttributeBinder(com.google.inject.Binder) + */ + Node createNodeAndPopulateAutomaticAttributes(String nodeName, Iterable<String> runList); + + /** + * Updates and populate the automatic attributes of the given node. + * + * @param nodeName The node to update. + */ + void updateAutomaticAttributesOnNode(String nodeName); + + /** + * Removes the nodes and clients that have been inactive for a given amount of + * time. + * + * @param prefix The prefix for the nodes and clients to delete. + * @param secondsStale The seconds of inactivity to consider a node and + * client obsolete. + */ + void cleanupStaleNodesAndClients(String prefix, int secondsStale); + + /** + * Deletes the given nodes. + * + * @param names The names of the nodes to delete. + */ + void deleteAllNodesInList(Iterable<String> names); + + /** + * Deletes the given clients. + * + * @param names The names of the client to delete. + */ + void deleteAllClientsInList(Iterable<String> names); + + /** + * Lists the details of all existing nodes. + * + * @return The details of all existing nodes. + */ + Iterable<? extends Node> listNodes(); + + /** + * Lists the details of all existing nodes, executing concurrently using the executorService. + * + * @return The details of all existing nodes. + */ + Iterable<? extends Node> listNodes(ExecutorService executorService); + + /** + * Lists the details of all existing nodes in the given environment. + * + * @param environmentName The name fo the environment. + * @return The details of all existing nodes in the given environment. + */ + @SinceApiVersion("0.10.0") + Iterable<? extends Node> listNodesInEnvironment(String environmentName); + + /** + * Lists the details of all existing nodes in the given environment, using the ExecutorService to paralleling the execution. + * + * @param executorService The thread pool used in this operation + * @param environmentName The name fo the environment. + * @return The details of all existing nodes in the given environment. + */ + @SinceApiVersion("0.10.0") + Iterable<? extends Node> listNodesInEnvironment(String environmentName, ExecutorService executorService); + + /** + * Lists the details of all existing clients. + * + * @return The details of all existing clients. + */ + Iterable<? extends Client> listClients(); + + /** + * Lists the details of all existing clients, but executing concurrently using the threads available in the ExecutorService. + * + * @return The details of all existing clients. + */ + Iterable<? extends Client> listClients(ExecutorService executorService); + + /** + * Lists the details of all existing cookbooks. + * + * @return The details of all existing cookbooks. + */ + Iterable<? extends CookbookVersion> listCookbookVersions(); + + /** + * Lists the details of all existing cookbooks. This method is executed concurrently, using the threads available in the ExecutorService. + * + * @return The details of all existing cookbooks. + */ + Iterable<? extends CookbookVersion> listCookbookVersions(ExecutorService executorService); + + /** + * Lists the details of all existing cookbooks in an environment. + * + * @param environmentName The environment name. + * @return The details of all existing cookbooks in an environment. + */ + Iterable<? extends CookbookVersion> listCookbookVersionsInEnvironment(String environmentName); + + /** + * Lists the details of all existing cookbooks in an environment. + + * @param executorService The thread pool to do the concurrent execution. + * @param environmentName The environment name. + * @return The details of all existing cookbooks in an environment. + */ + Iterable<? extends CookbookVersion> listCookbookVersionsInEnvironment(String environmentName, ExecutorService executorService); + + /** + * Lists the details of all existing cookbooks in an environment + * limiting number of versions. + * + * @param environmentName The environment name. + * @param numVersions The number of cookbook versions to include. + * Use 'all' to return all cookbook versions. + * @return The details of all existing cookbooks in environment. + */ + Iterable<? extends CookbookVersion> listCookbookVersionsInEnvironment(String environmentName, String numVersions); + + /** + * Lists the details of all existing cookbooks in an environment + * limiting number of versions. + * + * @param executorService The executorService used to do this operation concurrently. + * @param environmentName The environment name. + * @param numVersions The number of cookbook versions to include. + * Use 'all' to return all cookbook versions. + * @return The details of all existing cookbooks in environment. + */ + Iterable<? extends CookbookVersion> listCookbookVersionsInEnvironment(String environmentName, String numVersions, ExecutorService executorService); + + /** + * Lists the details of all existing environments. + * + * @return The details of all existing environments. + */ + @SinceApiVersion("0.10.0") + Iterable<? extends Environment> listEnvironments(); + +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/867c7a40/apis/chef/src/main/java/org/jclouds/chef/binders/BindChecksumsToJsonPayload.java ---------------------------------------------------------------------- diff --git a/apis/chef/src/main/java/org/jclouds/chef/binders/BindChecksumsToJsonPayload.java b/apis/chef/src/main/java/org/jclouds/chef/binders/BindChecksumsToJsonPayload.java new file mode 100644 index 0000000..9a744a3 --- /dev/null +++ b/apis/chef/src/main/java/org/jclouds/chef/binders/BindChecksumsToJsonPayload.java @@ -0,0 +1,54 @@ +/* + * 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. + */ +package org.jclouds.chef.binders; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.io.BaseEncoding.base16; +import static com.google.common.primitives.Bytes.toArray; + +import java.util.List; +import java.util.Set; + +import javax.inject.Singleton; +import javax.ws.rs.core.MediaType; + +import org.jclouds.http.HttpRequest; +import org.jclouds.rest.binders.BindToStringPayload; + +@Singleton +public class BindChecksumsToJsonPayload extends BindToStringPayload { + + @SuppressWarnings("unchecked") + public HttpRequest bindToRequest(HttpRequest request, Object input) { + checkArgument(checkNotNull(input, "input") instanceof Set, "this binder is only valid for Set!"); + + Set<List<Byte>> md5s = (Set<List<Byte>>) input; + + StringBuilder builder = new StringBuilder(); + builder.append("{\"checksums\":{"); + + for (List<Byte> md5 : md5s) + builder.append(String.format("\"%s\":null,", base16().lowerCase().encode(toArray(md5)))); + builder.deleteCharAt(builder.length() - 1); + builder.append("}}"); + super.bindToRequest(request, builder.toString()); + request.getPayload().getContentMetadata().setContentType(MediaType.APPLICATION_JSON); + return request; + } + +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/867c7a40/apis/chef/src/main/java/org/jclouds/chef/binders/BindCreateClientOptionsToJsonPayload.java ---------------------------------------------------------------------- diff --git a/apis/chef/src/main/java/org/jclouds/chef/binders/BindCreateClientOptionsToJsonPayload.java b/apis/chef/src/main/java/org/jclouds/chef/binders/BindCreateClientOptionsToJsonPayload.java new file mode 100644 index 0000000..b719c66 --- /dev/null +++ b/apis/chef/src/main/java/org/jclouds/chef/binders/BindCreateClientOptionsToJsonPayload.java @@ -0,0 +1,71 @@ +/* + * 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. + */ +package org.jclouds.chef.binders; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; + +import java.util.Map; + +import javax.inject.Inject; + +import org.jclouds.chef.options.CreateClientOptions; +import org.jclouds.http.HttpRequest; +import org.jclouds.json.Json; +import org.jclouds.rest.binders.BindToJsonPayload; +import org.jclouds.rest.internal.GeneratedHttpRequest; + +import com.google.common.base.Predicates; +import com.google.common.collect.Iterables; + +/** + * Bind the parameters of a {@link CreateClientOptions} to the payload. + */ +public class BindCreateClientOptionsToJsonPayload extends BindToJsonPayload { + @Inject + public BindCreateClientOptionsToJsonPayload(Json jsonBinder) { + super(jsonBinder); + } + + @Override + public <R extends HttpRequest> R bindToRequest(R request, Map<String, Object> postParams) { + checkArgument(checkNotNull(request, "request") instanceof GeneratedHttpRequest, + "this binder is only valid for GeneratedHttpRequests"); + GeneratedHttpRequest gRequest = (GeneratedHttpRequest) request; + checkState(gRequest.getInvocation().getArgs() != null, "args should be initialized at this point"); + + String name = checkNotNull(postParams.remove("name"), "name").toString(); + CreateClientOptions options = (CreateClientOptions) Iterables.find(gRequest.getInvocation().getArgs(), + Predicates.instanceOf(CreateClientOptions.class)); + + return bindToRequest(request, new CreateClientParams(name, options)); + } + + @SuppressWarnings("unused") + private static class CreateClientParams { + private String name; + + private boolean admin; + + public CreateClientParams(String name, CreateClientOptions options) { + this.name = name; + this.admin = options.isAdmin(); + } + } + +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/867c7a40/apis/chef/src/main/java/org/jclouds/chef/binders/BindGenerateKeyForClientToJsonPayload.java ---------------------------------------------------------------------- diff --git a/apis/chef/src/main/java/org/jclouds/chef/binders/BindGenerateKeyForClientToJsonPayload.java b/apis/chef/src/main/java/org/jclouds/chef/binders/BindGenerateKeyForClientToJsonPayload.java new file mode 100644 index 0000000..4bd5821 --- /dev/null +++ b/apis/chef/src/main/java/org/jclouds/chef/binders/BindGenerateKeyForClientToJsonPayload.java @@ -0,0 +1,35 @@ +/* + * 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. + */ +package org.jclouds.chef.binders; + +import javax.inject.Singleton; +import javax.ws.rs.core.MediaType; + +import org.jclouds.http.HttpRequest; +import org.jclouds.rest.binders.BindToStringPayload; + +@Singleton +public class BindGenerateKeyForClientToJsonPayload extends BindToStringPayload { + + @Override + public <R extends HttpRequest> R bindToRequest(R request, Object payload) { + super.bindToRequest(request, String.format("{\"name\":\"%s\", \"private_key\": true}", payload)); + request.getPayload().getContentMetadata().setContentType(MediaType.APPLICATION_JSON); + return request; + } + +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/867c7a40/apis/chef/src/main/java/org/jclouds/chef/binders/DatabagItemId.java ---------------------------------------------------------------------- diff --git a/apis/chef/src/main/java/org/jclouds/chef/binders/DatabagItemId.java b/apis/chef/src/main/java/org/jclouds/chef/binders/DatabagItemId.java new file mode 100644 index 0000000..5dd5a62 --- /dev/null +++ b/apis/chef/src/main/java/org/jclouds/chef/binders/DatabagItemId.java @@ -0,0 +1,32 @@ +/* + * 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. + */ +package org.jclouds.chef.binders; + +import javax.inject.Singleton; + +import org.jclouds.chef.domain.DatabagItem; + +import com.google.common.base.Function; + +@Singleton +public class DatabagItemId implements Function<Object, String> { + + public String apply(Object from) { + return ((DatabagItem) from).getId(); + } + +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/867c7a40/apis/chef/src/main/java/org/jclouds/chef/binders/EnvironmentName.java ---------------------------------------------------------------------- diff --git a/apis/chef/src/main/java/org/jclouds/chef/binders/EnvironmentName.java b/apis/chef/src/main/java/org/jclouds/chef/binders/EnvironmentName.java new file mode 100644 index 0000000..1650521 --- /dev/null +++ b/apis/chef/src/main/java/org/jclouds/chef/binders/EnvironmentName.java @@ -0,0 +1,31 @@ +/* + * 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. + */ +package org.jclouds.chef.binders; + +import com.google.common.base.Function; +import org.jclouds.chef.domain.Environment; + +import javax.inject.Singleton; + +@Singleton +public class EnvironmentName implements Function<Object, String> { + + @Override + public String apply(Object input) { + return ((Environment) input).getName(); + } +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/867c7a40/apis/chef/src/main/java/org/jclouds/chef/binders/NodeName.java ---------------------------------------------------------------------- diff --git a/apis/chef/src/main/java/org/jclouds/chef/binders/NodeName.java b/apis/chef/src/main/java/org/jclouds/chef/binders/NodeName.java new file mode 100644 index 0000000..5277895 --- /dev/null +++ b/apis/chef/src/main/java/org/jclouds/chef/binders/NodeName.java @@ -0,0 +1,32 @@ +/* + * 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. + */ +package org.jclouds.chef.binders; + +import javax.inject.Singleton; + +import org.jclouds.chef.domain.Node; + +import com.google.common.base.Function; + +@Singleton +public class NodeName implements Function<Object, String> { + + public String apply(Object from) { + return ((Node) from).getName(); + } + +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/867c7a40/apis/chef/src/main/java/org/jclouds/chef/binders/RoleName.java ---------------------------------------------------------------------- diff --git a/apis/chef/src/main/java/org/jclouds/chef/binders/RoleName.java b/apis/chef/src/main/java/org/jclouds/chef/binders/RoleName.java new file mode 100644 index 0000000..aa78a06 --- /dev/null +++ b/apis/chef/src/main/java/org/jclouds/chef/binders/RoleName.java @@ -0,0 +1,32 @@ +/* + * 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. + */ +package org.jclouds.chef.binders; + +import javax.inject.Singleton; + +import org.jclouds.chef.domain.Role; + +import com.google.common.base.Function; + +@Singleton +public class RoleName implements Function<Object, String> { + + public String apply(Object from) { + return ((Role) from).getName(); + } + +}
