Promoted jclouds-chef/core to apis/chef

This commit is contained in:
Ignasi Barrera 2014-10-10 15:10:44 +02:00
commit aa17a4f9f9
180 changed files with 17251 additions and 0 deletions

134
apis/chef/pom.xml Normal file
View File

@ -0,0 +1,134 @@
<?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.chef</groupId>
<artifactId>chef-project</artifactId>
<version>2.0.0-SNAPSHOT</version>
<relativePath>../project/pom.xml</relativePath>
</parent>
<groupId>org.apache.jclouds.api</groupId>
<artifactId>chef</artifactId>
<packaging>bundle</packaging>
<name>Apache jclouds Chef :: Core</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=${jclouds.version},
org.jclouds*;version=${jclouds.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>${jclouds.version}</version>
</dependency>
<dependency>
<groupId>org.apache.jclouds</groupId>
<artifactId>jclouds-core</artifactId>
<version>${jclouds.version}</version>
<type>test-jar</type>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.jclouds</groupId>
<artifactId>jclouds-scriptbuilder</artifactId>
<version>${jclouds.version}</version>
</dependency>
<dependency>
<groupId>org.apache.jclouds</groupId>
<artifactId>jclouds-scriptbuilder</artifactId>
<version>${jclouds.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>${jclouds.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.apache.jclouds.driver</groupId>
<artifactId>jclouds-slf4j</artifactId>
<version>${jclouds.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.0.9</version>
<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>

View File

@ -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))))))

View File

@ -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);
}

View File

@ -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;
}
}
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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;
}
}

View File

@ -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();
}
}
}

View File

@ -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;
}
}

View File

@ -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();
}
}

View File

@ -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();
}
}

View File

@ -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();
}
}

View File

@ -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();
}
}

View File

@ -0,0 +1,208 @@
/*
* 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.config;
import static com.google.common.base.Suppliers.compose;
import static com.google.common.base.Suppliers.memoizeWithExpiration;
import static com.google.common.base.Throwables.propagate;
import static org.jclouds.Constants.PROPERTY_SESSION_INTERVAL;
import static org.jclouds.chef.config.ChefProperties.CHEF_VALIDATOR_CREDENTIAL;
import static org.jclouds.chef.config.ChefProperties.CHEF_VALIDATOR_NAME;
import static org.jclouds.crypto.Pems.privateKeySpec;
import java.io.IOException;
import java.security.PrivateKey;
import java.security.spec.InvalidKeySpecException;
import java.util.List;
import java.util.concurrent.TimeUnit;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import org.jclouds.chef.domain.Client;
import org.jclouds.chef.functions.BootstrapConfigForGroup;
import org.jclouds.chef.functions.ClientForGroup;
import org.jclouds.chef.functions.RunListForGroup;
import org.jclouds.chef.handlers.ChefApiErrorRetryHandler;
import org.jclouds.chef.handlers.ChefErrorHandler;
import org.jclouds.crypto.Crypto;
import org.jclouds.crypto.Pems;
import org.jclouds.date.DateService;
import org.jclouds.date.TimeStamp;
import org.jclouds.domain.Credentials;
import org.jclouds.domain.JsonBall;
import org.jclouds.http.HttpErrorHandler;
import org.jclouds.http.HttpRetryHandler;
import org.jclouds.http.annotation.ClientError;
import org.jclouds.http.annotation.Redirection;
import org.jclouds.http.annotation.ServerError;
import org.jclouds.rest.ConfiguresHttpApi;
import org.jclouds.rest.config.HttpApiModule;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Charsets;
import com.google.common.base.Function;
import com.google.common.base.Optional;
import com.google.common.base.Supplier;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.io.ByteSource;
import com.google.inject.ConfigurationException;
import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.Provides;
import com.google.inject.name.Names;
/**
* Configures the Chef connection.
*/
@ConfiguresHttpApi
public abstract class BaseChefHttpApiModule<S> extends HttpApiModule<S> {
@Provides
@TimeStamp
protected String provideTimeStamp(@TimeStamp Supplier<String> cache) {
return cache.get();
}
/**
* borrowing concurrency code to ensure that caching takes place properly
*/
@Provides
@TimeStamp
Supplier<String> provideTimeStampCache(@Named(PROPERTY_SESSION_INTERVAL) long seconds, final DateService dateService) {
return memoizeWithExpiration(new Supplier<String>() {
@Override
public String get() {
return dateService.iso8601SecondsDateFormat();
}
}, seconds, TimeUnit.SECONDS);
}
// TODO: potentially change this
@Provides
@Singleton
public Supplier<PrivateKey> supplyKey(final LoadingCache<Credentials, PrivateKey> keyCache,
@org.jclouds.location.Provider final Supplier<Credentials> creds) {
return compose(new Function<Credentials, PrivateKey>() {
@Override
public PrivateKey apply(Credentials in) {
return keyCache.getUnchecked(in);
}
}, creds);
}
@Provides
@Singleton
LoadingCache<Credentials, PrivateKey> privateKeyCache(PrivateKeyForCredentials loader) {
// throw out the private key related to old credentials
return CacheBuilder.newBuilder().maximumSize(2).build(loader);
}
/**
* it is relatively expensive to extract a private key from a PEM. cache the
* relationship between current credentials so that the private key is only
* recalculated once.
*/
@VisibleForTesting
@Singleton
private static class PrivateKeyForCredentials extends CacheLoader<Credentials, PrivateKey> {
private final Crypto crypto;
@Inject
private PrivateKeyForCredentials(Crypto crypto) {
this.crypto = crypto;
}
@Override
public PrivateKey load(Credentials in) {
try {
return crypto.rsaKeyFactory().generatePrivate(
privateKeySpec(ByteSource.wrap(in.credential.getBytes(Charsets.UTF_8))));
} catch (InvalidKeySpecException e) {
throw propagate(e);
} catch (IOException e) {
throw propagate(e);
}
}
}
@Provides
@Singleton
@Validator
public Optional<String> provideValidatorName(Injector injector) {
// Named properties can not be injected as optional here, so let's use the
// injector to bypass it
Key<String> key = Key.get(String.class, Names.named(CHEF_VALIDATOR_NAME));
try {
return Optional.<String> of(injector.getInstance(key));
} catch (ConfigurationException ex) {
return Optional.<String> absent();
}
}
@Provides
@Singleton
@Validator
public Optional<PrivateKey> provideValidatorCredential(Crypto crypto, Injector injector)
throws InvalidKeySpecException, IOException {
// Named properties can not be injected as optional here, so let's use the
// injector to bypass it
Key<String> key = Key.get(String.class, Names.named(CHEF_VALIDATOR_CREDENTIAL));
try {
String validatorCredential = injector.getInstance(key);
PrivateKey validatorKey = crypto.rsaKeyFactory().generatePrivate(
Pems.privateKeySpec(ByteSource.wrap(validatorCredential.getBytes(Charsets.UTF_8))));
return Optional.<PrivateKey> of(validatorKey);
} catch (ConfigurationException ex) {
return Optional.<PrivateKey> absent();
}
}
@Provides
@Singleton
CacheLoader<String, List<String>> runListForGroup(RunListForGroup runListForGroup) {
return CacheLoader.from(runListForGroup);
}
@Provides
@Singleton
CacheLoader<String, ? extends JsonBall> bootstrapConfigForGroup(BootstrapConfigForGroup bootstrapConfigForGroup) {
return CacheLoader.from(bootstrapConfigForGroup);
}
@Provides
@Singleton
CacheLoader<String, Client> groupToClient(ClientForGroup clientForGroup) {
return CacheLoader.from(clientForGroup);
}
@Override
protected void bindErrorHandlers() {
bind(HttpErrorHandler.class).annotatedWith(Redirection.class).to(ChefErrorHandler.class);
bind(HttpErrorHandler.class).annotatedWith(ClientError.class).to(ChefErrorHandler.class);
bind(HttpErrorHandler.class).annotatedWith(ServerError.class).to(ChefErrorHandler.class);
}
@Override
protected void bindRetryHandlers() {
bind(HttpRetryHandler.class).annotatedWith(ClientError.class).to(ChefApiErrorRetryHandler.class);
}
}

View File

@ -0,0 +1,121 @@
/*
* 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.config;
import static org.jclouds.chef.config.ChefProperties.CHEF_GEM_SYSTEM_VERSION;
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 static org.jclouds.chef.config.ChefProperties.CHEF_VERSION;
import javax.inject.Named;
import javax.inject.Singleton;
import org.jclouds.scriptbuilder.domain.Statement;
import org.jclouds.scriptbuilder.domain.StatementList;
import org.jclouds.scriptbuilder.statements.chef.InstallChefGems;
import org.jclouds.scriptbuilder.statements.chef.InstallChefUsingOmnibus;
import org.jclouds.scriptbuilder.statements.ruby.InstallRuby;
import org.jclouds.scriptbuilder.statements.ruby.InstallRubyGems;
import com.google.common.base.Optional;
import com.google.inject.AbstractModule;
import com.google.inject.Inject;
import com.google.inject.Provides;
/**
* Provides bootstrap configuration for nodes.
*/
public class ChefBootstrapModule extends AbstractModule {
@Provides
@Named("installChefGems")
@Singleton
Statement installChefGems(BootstrapProperties bootstrapProperties) {
InstallRubyGems installRubyGems = InstallRubyGems.builder()
.version(bootstrapProperties.gemSystemVersion().orNull())
.updateSystem(bootstrapProperties.updateGemSystem(), bootstrapProperties.gemSystemVersion().orNull())
.updateExistingGems(bootstrapProperties.updateGems()) //
.build();
Statement installChef = InstallChefGems.builder().version(bootstrapProperties.chefVersion().orNull()).build();
return new StatementList(InstallRuby.builder().build(), installRubyGems, installChef);
}
@Provides
@Named("installChefOmnibus")
@Singleton
Statement installChefUsingOmnibus() {
return new InstallChefUsingOmnibus();
}
@Provides
@InstallChef
@Singleton
Statement installChef(BootstrapProperties bootstrapProperties, @Named("installChefGems") Statement installChefGems,
@Named("installChefOmnibus") Statement installChefOmnibus) {
return bootstrapProperties.useOmnibus() ? installChefOmnibus : installChefGems;
}
@Singleton
private static class BootstrapProperties {
@Named(CHEF_VERSION)
@Inject(optional = true)
private String chefVersionProperty;
@Named(CHEF_GEM_SYSTEM_VERSION)
@Inject(optional = true)
private String gemSystemVersionProperty;
@Named(CHEF_UPDATE_GEM_SYSTEM)
@Inject
private String updateGemSystemProeprty;
@Named(CHEF_UPDATE_GEMS)
@Inject
private String updateGemsProperty;
@Named(CHEF_USE_OMNIBUS)
@Inject
private String useOmnibus;
public Optional<String> chefVersion() {
return Optional.fromNullable(chefVersionProperty);
}
public Optional<String> gemSystemVersion() {
return Optional.fromNullable(gemSystemVersionProperty);
}
public boolean updateGemSystem() {
return Boolean.parseBoolean(updateGemSystemProeprty);
}
public boolean updateGems() {
return Boolean.parseBoolean(updateGemsProperty);
}
public boolean useOmnibus() {
return Boolean.parseBoolean(useOmnibus);
}
}
@Override
protected void configure() {
}
}

View File

@ -0,0 +1,28 @@
/*
* 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.config;
import org.jclouds.chef.ChefApi;
import org.jclouds.rest.ConfiguresHttpApi;
/**
* Configures the Chef connection.
*/
@ConfiguresHttpApi
public class ChefHttpApiModule extends BaseChefHttpApiModule<ChefApi> {
}

View File

@ -0,0 +1,321 @@
/*
* 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.config;
import static com.google.common.base.Objects.equal;
import static com.google.common.base.Objects.toStringHelper;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkState;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Type;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.security.spec.InvalidKeySpecException;
import java.util.Map;
import java.util.Set;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.chef.domain.DatabagItem;
import org.jclouds.chef.functions.ParseCookbookDefinitionFromJson;
import org.jclouds.chef.functions.ParseCookbookVersionsV09FromJson;
import org.jclouds.chef.functions.ParseCookbookVersionsV10FromJson;
import org.jclouds.chef.functions.ParseKeySetFromJson;
import org.jclouds.chef.suppliers.ChefVersionSupplier;
import org.jclouds.crypto.Crypto;
import org.jclouds.crypto.Pems;
import org.jclouds.http.HttpResponse;
import org.jclouds.json.config.GsonModule.DateAdapter;
import org.jclouds.json.config.GsonModule.Iso8601DateAdapter;
import org.jclouds.json.internal.NullFilteringTypeAdapterFactories.MapTypeAdapterFactory;
import org.jclouds.json.internal.NullHackJsonLiteralAdapter;
import com.google.common.base.Charsets;
import com.google.common.base.Function;
import com.google.common.base.Objects;
import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import com.google.common.io.ByteSource;
import com.google.gson.Gson;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;
import com.google.gson.JsonSyntaxException;
import com.google.gson.TypeAdapter;
import com.google.gson.internal.JsonReaderInternalAccess;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;
import com.google.inject.AbstractModule;
import com.google.inject.ImplementedBy;
import com.google.inject.Provides;
public class ChefParserModule extends AbstractModule {
@ImplementedBy(PrivateKeyAdapterImpl.class)
public interface PrivateKeyAdapter extends JsonDeserializer<PrivateKey> {
}
@Singleton
public static class PrivateKeyAdapterImpl implements PrivateKeyAdapter {
private final Crypto crypto;
@Inject
PrivateKeyAdapterImpl(Crypto crypto) {
this.crypto = crypto;
}
@Override
public PrivateKey deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
String keyText = json.getAsString().replaceAll("\\n", "\n");
try {
return crypto.rsaKeyFactory().generatePrivate(
Pems.privateKeySpec(ByteSource.wrap(keyText.getBytes(Charsets.UTF_8))));
} catch (UnsupportedEncodingException e) {
Throwables.propagate(e);
return null;
} catch (InvalidKeySpecException e) {
Throwables.propagate(e);
return null;
} catch (IOException e) {
Throwables.propagate(e);
return null;
}
}
}
@ImplementedBy(PublicKeyAdapterImpl.class)
public interface PublicKeyAdapter extends JsonDeserializer<PublicKey> {
}
@Singleton
public static class PublicKeyAdapterImpl implements PublicKeyAdapter {
private final Crypto crypto;
@Inject
PublicKeyAdapterImpl(Crypto crypto) {
this.crypto = crypto;
}
@Override
public PublicKey deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
String keyText = json.getAsString().replaceAll("\\n", "\n");
try {
return crypto.rsaKeyFactory().generatePublic(
Pems.publicKeySpec(ByteSource.wrap(keyText.getBytes(Charsets.UTF_8))));
} catch (UnsupportedEncodingException e) {
Throwables.propagate(e);
return null;
} catch (InvalidKeySpecException e) {
Throwables.propagate(e);
return null;
} catch (IOException e) {
Throwables.propagate(e);
return null;
}
}
}
@ImplementedBy(X509CertificateAdapterImpl.class)
public interface X509CertificateAdapter extends JsonDeserializer<X509Certificate> {
}
@Singleton
public static class X509CertificateAdapterImpl implements X509CertificateAdapter {
private final Crypto crypto;
@Inject
X509CertificateAdapterImpl(Crypto crypto) {
this.crypto = crypto;
}
@Override
public X509Certificate deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
String keyText = json.getAsString().replaceAll("\\n", "\n");
try {
return Pems.x509Certificate(ByteSource.wrap(keyText.getBytes(Charsets.UTF_8)),
crypto.certFactory());
} catch (UnsupportedEncodingException e) {
Throwables.propagate(e);
return null;
} catch (IOException e) {
Throwables.propagate(e);
return null;
} catch (CertificateException e) {
Throwables.propagate(e);
return null;
}
}
}
/**
* writes or reads the literal directly
*/
@Singleton
public static class DataBagItemAdapter extends NullHackJsonLiteralAdapter<DatabagItem> {
final Gson gson = new Gson();
@Override
protected DatabagItem createJsonLiteralFromRawJson(String text) {
IdHolder idHolder = gson.fromJson(text, IdHolder.class);
checkState(idHolder.id != null,
"databag item must be a json hash ex. {\"id\":\"item1\",\"my_key\":\"my_data\"}; was %s", text);
text = text.replaceFirst(String.format("\\{\"id\"[ ]?:\"%s\",", idHolder.id), "{");
return new DatabagItem(idHolder.id, text);
}
@Override
protected String toString(DatabagItem value) {
String text = value.toString();
try {
IdHolder idHolder = gson.fromJson(text, IdHolder.class);
if (idHolder.id == null) {
text = text.replaceFirst("\\{", String.format("{\"id\":\"%s\",", value.getId()));
} else {
checkArgument(value.getId().equals(idHolder.id),
"incorrect id in databagItem text, should be %s: was %s", value.getId(), idHolder.id);
}
} catch (JsonSyntaxException e) {
throw new IllegalArgumentException(e);
}
return text;
}
}
private static class IdHolder {
private String id;
}
// The NullFilteringTypeAdapterFactories.MapTypeAdapter class is final. Do
// the same logic here
private static final class KeepLastRepeatedKeyMapTypeAdapter<K, V> extends TypeAdapter<Map<K, V>> {
protected final TypeAdapter<K> keyAdapter;
protected final TypeAdapter<V> valueAdapter;
protected KeepLastRepeatedKeyMapTypeAdapter(TypeAdapter<K> keyAdapter, TypeAdapter<V> valueAdapter) {
this.keyAdapter = keyAdapter;
this.valueAdapter = valueAdapter;
nullSafe();
}
public void write(JsonWriter out, Map<K, V> value) throws IOException {
if (value == null) {
out.nullValue();
return;
}
out.beginObject();
for (Map.Entry<K, V> element : value.entrySet()) {
out.name(String.valueOf(element.getKey()));
valueAdapter.write(out, element.getValue());
}
out.endObject();
}
public Map<K, V> read(JsonReader in) throws IOException {
Map<K, V> result = Maps.newHashMap();
in.beginObject();
while (in.hasNext()) {
JsonReaderInternalAccess.INSTANCE.promoteNameToValue(in);
K name = keyAdapter.read(in);
V value = valueAdapter.read(in);
if (value != null) {
// If there are repeated keys, overwrite them to only keep the last one
result.put(name, value);
}
}
in.endObject();
return ImmutableMap.copyOf(result);
}
@Override
public int hashCode() {
return Objects.hashCode(keyAdapter, valueAdapter);
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null || getClass() != obj.getClass())
return false;
KeepLastRepeatedKeyMapTypeAdapter<?, ?> that = KeepLastRepeatedKeyMapTypeAdapter.class.cast(obj);
return equal(this.keyAdapter, that.keyAdapter) && equal(this.valueAdapter, that.valueAdapter);
}
@Override
public String toString() {
return toStringHelper(this).add("keyAdapter", keyAdapter).add("valueAdapter", valueAdapter).toString();
}
}
public static class KeepLastRepeatedKeyMapTypeAdapterFactory extends MapTypeAdapterFactory {
public KeepLastRepeatedKeyMapTypeAdapterFactory() {
super(Map.class);
}
@SuppressWarnings("unchecked")
@Override
protected <K, V, T> TypeAdapter<T> newAdapter(TypeAdapter<K> keyAdapter, TypeAdapter<V> valueAdapter) {
return (TypeAdapter<T>) new KeepLastRepeatedKeyMapTypeAdapter<K, V>(keyAdapter, valueAdapter);
}
}
@Provides
@Singleton
public Map<Type, Object> provideCustomAdapterBindings(DataBagItemAdapter adapter, PrivateKeyAdapter privateAdapter,
PublicKeyAdapter publicAdapter, X509CertificateAdapter certAdapter) {
return ImmutableMap.<Type, Object> of(DatabagItem.class, adapter, PrivateKey.class, privateAdapter,
PublicKey.class, publicAdapter, X509Certificate.class, certAdapter);
}
@Provides
@Singleton
@CookbookParser
public Function<HttpResponse, Set<String>> provideCookbookDefinitionAdapter(ChefVersionSupplier chefVersionSupplier,
ParseCookbookDefinitionFromJson v10parser, ParseKeySetFromJson v09parser) {
return chefVersionSupplier.get() >= 10 ? v10parser : v09parser;
}
@Provides
@Singleton
@CookbookVersionsParser
public Function<HttpResponse, Set<String>> provideCookbookDefinitionAdapter(ChefVersionSupplier chefVersionSupplier,
ParseCookbookVersionsV10FromJson v10parser, ParseCookbookVersionsV09FromJson v09parser) {
return chefVersionSupplier.get() >= 10 ? v10parser : v09parser;
}
@Override
protected void configure() {
bind(DateAdapter.class).to(Iso8601DateAdapter.class);
bind(MapTypeAdapterFactory.class).to(KeepLastRepeatedKeyMapTypeAdapterFactory.class);
}
}

View File

@ -0,0 +1,113 @@
/*
* 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.config;
/**
* Configuration properties and constants used in Chef connections.
*/
public final class ChefProperties {
/**
* The name of the Chef logger.
*/
public static final String CHEF_LOGGER = "jclouds.chef";
/**
* Databag that holds chef bootstrap hints, should be a json ball in the
* following format:
* <p>
* {"tag":{"run_list":["recipe[apache2]"]}}
*/
public static final String CHEF_BOOTSTRAP_DATABAG = "chef.bootstrap-databag";
/**
* The name of the validator client used to allow nodes to autoregister in
* the Chef server.
* <p>
* This property must be set prior to running the
* {@link ChefService#createBootstrapScriptForGroup(String)} method.
*/
public static final String CHEF_VALIDATOR_NAME = "chef.validator-name";
/**
* The credential of the validator client used to allow nodes to autoregister
* in the Chef server.
* <p>
* This property must be set prior to running the
* {@link ChefService#createBootstrapScriptForGroup(String)} method.
*/
public static final String CHEF_VALIDATOR_CREDENTIAL = "chef.validator-credential";
/**
* The version of the Chef gem to install when bootstrapping nodes.
* <p>
* If this property is not set, by default the latest available Chef gem will
* be installed. The values can be fixed versions such as '0.10.8' or
* constrained values such as '>= 0.10.8'.
* <p>
* This property must be set prior to running the
* {@link ChefService#createBootstrapScriptForGroup(String)} method.
*/
public static final String CHEF_VERSION = "chef.version";
/**
* Boolean property. Default (false).
* <p>
* When bootstrapping a node, forces a gem system update before installing
* the Chef gems.
* <p>
* This property must be set prior to running the
* {@link ChefService#createBootstrapScriptForGroup(String)} method.
*/
public static final String CHEF_UPDATE_GEM_SYSTEM = "chef.update-gem-system";
/**
* To be used in conjunction with {@link #CHEF_UPDATE_GEM_SYSTEM}. This
* property will force the version of RubyGems to update the system to.
* <p>
* This property must be set prior to running the
* {@link ChefService#createBootstrapScriptForGroup(String)} method.
*/
public static final String CHEF_GEM_SYSTEM_VERSION = "chef.gem-system-version";
/**
* Boolean property. Default (false).
* <p>
* When bootstrapping a node, updates the existing gems before installing
* Chef.
* <p>
* This property must be set prior to running the
* {@link ChefService#createBootstrapScriptForGroup(String)} method.
*/
public static final String CHEF_UPDATE_GEMS = "chef.update-gems";
/**
* Boolean property. Default (true).
* <p>
* When bootstrapping a node, install the Chef client using the Omnibus
* installer.
* <p>
* This property must be set prior to running the
* {@link ChefService#createBootstrapScriptForGroup(String)} method.
*/
public static final String CHEF_USE_OMNIBUS = "chef.use-omnibus";
private ChefProperties() {
throw new AssertionError("intentionally unimplemented");
}
}

View File

@ -0,0 +1,41 @@
/*
* 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.config;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import javax.inject.Qualifier;
/**
* Used to configure the cookbook Json parser.
* <p>
* Chef Server version 0.9 and 0.10 return a different Json when rquesting the
* cookbook definitions. This annotation can be used to setup the cookbook
* parser.
*/
@Target({ METHOD, PARAMETER, FIELD })
@Retention(RUNTIME)
@Qualifier
public @interface CookbookParser {
}

View File

@ -0,0 +1,41 @@
/*
* 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.config;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import javax.inject.Qualifier;
/**
* Used to configure the cookbook versions Json parser.
* <p>
* Chef Server version 0.9 and 0.10 return a different Json when rquesting the
* cookbook versions. This annotation can be used to setup the cookbook versions
* parser.
*/
@Target({ METHOD, PARAMETER, FIELD })
@Retention(RUNTIME)
@Qualifier
public @interface CookbookVersionsParser {
}

View File

@ -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.config;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import javax.inject.Qualifier;
/**
* Used to configure the Chef install script.
*/
@Target({ METHOD, PARAMETER, FIELD })
@Retention(RUNTIME)
@Qualifier
public @interface InstallChef {
}

View File

@ -0,0 +1,40 @@
/*
* 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.config;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import javax.inject.Qualifier;
/**
* Used to configure the validator client information.
* <p>
* In a Chef server it must be only one validator client. This client is used by
* new nodes to autoregister themselves in the Chef server.
*/
@Target({ METHOD, PARAMETER, FIELD })
@Retention(RUNTIME)
@Qualifier
public @interface Validator {
}

View File

@ -0,0 +1,235 @@
/*
* 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.domain;
import static org.jclouds.chef.util.CollectionUtils.copyOfOrEmpty;
import static com.google.common.base.Preconditions.checkNotNull;
import java.beans.ConstructorProperties;
import java.util.List;
import java.util.Set;
import org.jclouds.domain.JsonBall;
import org.jclouds.javax.annotation.Nullable;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.gson.annotations.SerializedName;
/**
* An attribute in a cookbook metadata.
*/
public class Attribute {
public static Builder builder() {
return new Builder();
}
public static class Builder {
private String required;
private boolean calculated;
private ImmutableSet.Builder<String> choice = ImmutableSet.builder();
private JsonBall defaultValue;
private String type;
private ImmutableList.Builder<String> recipes = ImmutableList.builder();
private String displayName;
private String description;
public Builder required(String required) {
this.required = checkNotNull(required, "required");
return this;
}
public Builder calculated(boolean calculated) {
this.calculated = calculated;
return this;
}
public Builder choice(String choice) {
this.choice.add(checkNotNull(choice, "choice"));
return this;
}
public Builder choices(Iterable<String> choices) {
this.choice.addAll(checkNotNull(choices, "choices"));
return this;
}
public Builder defaultValue(JsonBall defaultValue) {
this.defaultValue = checkNotNull(defaultValue, "defaultValue");
return this;
}
public Builder type(String type) {
this.type = checkNotNull(type, "type");
return this;
}
public Builder recipe(String recipe) {
this.recipes.add(checkNotNull(recipe, "recipe"));
return this;
}
public Builder recipes(Iterable<String> recipes) {
this.recipes.addAll(checkNotNull(recipes, "recipes"));
return this;
}
public Builder displayName(String displayName) {
this.displayName = checkNotNull(displayName, "displayName");
return this;
}
public Builder description(String description) {
this.description = checkNotNull(description, "description");
return this;
}
public Attribute build() {
return new Attribute(required, calculated, choice.build(), defaultValue, type, recipes.build(), displayName,
description);
}
}
private final String required;
private final boolean calculated;
private final Set<String> choice;
@SerializedName("default")
private final JsonBall defaultValue;
private final String type;
private final List<String> recipes;
@SerializedName("display_name")
private final String displayName;
private final String description;
@ConstructorProperties({ "required", "calculated", "choice", "default", "type", "recipes", "display_name",
"description" })
protected Attribute(String required, boolean calculated, @Nullable Set<String> choice, JsonBall defaultValue,
String type, @Nullable List<String> recipes, String displayName, String description) {
this.required = required;
this.calculated = calculated;
this.choice = copyOfOrEmpty(choice);
this.defaultValue = defaultValue;
this.type = type;
this.recipes = copyOfOrEmpty(recipes);
this.displayName = displayName;
this.description = description;
}
public String getRequired() {
return required;
}
public boolean isCalculated() {
return calculated;
}
public Set<String> getChoice() {
return choice;
}
public JsonBall getDefaultValue() {
return defaultValue;
}
public String getType() {
return type;
}
public List<String> getRecipes() {
return recipes;
}
public String getDisplayName() {
return displayName;
}
public String getDescription() {
return description;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (calculated ? 1231 : 1237);
result = prime * result + ((choice == null) ? 0 : choice.hashCode());
result = prime * result + ((defaultValue == null) ? 0 : defaultValue.hashCode());
result = prime * result + ((description == null) ? 0 : description.hashCode());
result = prime * result + ((displayName == null) ? 0 : displayName.hashCode());
result = prime * result + ((recipes == null) ? 0 : recipes.hashCode());
result = prime * result + ((required == null) ? 0 : required.hashCode());
result = prime * result + ((type == null) ? 0 : type.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Attribute other = (Attribute) obj;
if (calculated != other.calculated)
return false;
if (choice == null) {
if (other.choice != null)
return false;
} else if (!choice.equals(other.choice))
return false;
if (defaultValue == null) {
if (other.defaultValue != null)
return false;
} else if (!defaultValue.equals(other.defaultValue))
return false;
if (description == null) {
if (other.description != null)
return false;
} else if (!description.equals(other.description))
return false;
if (displayName == null) {
if (other.displayName != null)
return false;
} else if (!displayName.equals(other.displayName))
return false;
if (recipes == null) {
if (other.recipes != null)
return false;
} else if (!recipes.equals(other.recipes))
return false;
if (required == null) {
if (other.required != null)
return false;
} else if (!required.equals(other.required))
return false;
if (type == null) {
if (other.type != null)
return false;
} else if (!type.equals(other.type))
return false;
return true;
}
@Override
public String toString() {
return "Attribute [calculated=" + calculated + ", choice=" + choice + ", defaultValue=" + defaultValue
+ ", description=" + description + ", displayName=" + displayName + ", recipes=" + recipes + ", required="
+ required + ", type=" + type + "]";
}
}

View File

@ -0,0 +1,95 @@
/*
* 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.domain;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.List;
import org.jclouds.domain.JsonBall;
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList;
/**
* Configures how the nodes in a group will bootstrap.
*
* @since 1.7
*/
public class BootstrapConfig {
public static Builder builder() {
return new Builder();
}
public static class Builder {
private ImmutableList.Builder<String> runList = ImmutableList.builder();
private String environment;
private JsonBall attribtues;
/**
* Sets the run list that will be executed in the nodes of the group.
*/
public Builder runList(Iterable<String> runList) {
this.runList.addAll(checkNotNull(runList, "runList"));
return this;
}
/**
* Sets the environment where the nodes in the group will be deployed.
*/
public Builder environment(String environment) {
this.environment = checkNotNull(environment, "environment");
return this;
}
/**
* Sets the attributes that will be populated to the deployed nodes.
*/
public Builder attributes(JsonBall attributes) {
this.attribtues = checkNotNull(attributes, "attributes");
return this;
}
public BootstrapConfig build() {
return new BootstrapConfig(runList.build(), Optional.fromNullable(environment),
Optional.fromNullable(attribtues));
}
}
private final List<String> runList;
private final Optional<String> environment;
private final Optional<JsonBall> attribtues;
protected BootstrapConfig(List<String> runList, Optional<String> environment, Optional<JsonBall> attribtues) {
this.runList = checkNotNull(runList, "runList");
this.environment = checkNotNull(environment, "environment");
this.attribtues = checkNotNull(attribtues, "attributes");
}
public List<String> getRunList() {
return runList;
}
public Optional<String> getEnvironment() {
return environment;
}
public Optional<JsonBall> getAttribtues() {
return attribtues;
}
}

View File

@ -0,0 +1,102 @@
/*
* 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.domain;
import static com.google.common.base.Preconditions.checkNotNull;
import java.beans.ConstructorProperties;
import java.net.URI;
import com.google.gson.annotations.SerializedName;
/**
* The checksum of an uploaded resource.
*/
public class ChecksumStatus {
public static Builder builder() {
return new Builder();
}
public static class Builder {
private URI url;
private boolean needsUpload;
public Builder url(URI url) {
this.url = checkNotNull(url, "url");
return this;
}
public Builder needsUpload(boolean needsUpload) {
this.needsUpload = needsUpload;
return this;
}
public ChecksumStatus build() {
return new ChecksumStatus(url, needsUpload);
}
}
private final URI url;
@SerializedName("needs_upload")
private final boolean needsUpload;
@ConstructorProperties({ "url", "needs_upload" })
protected ChecksumStatus(URI url, boolean needsUpload) {
this.url = url;
this.needsUpload = needsUpload;
}
public URI getUrl() {
return url;
}
public boolean needsUpload() {
return needsUpload;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (needsUpload ? 1231 : 1237);
result = prime * result + ((url == null) ? 0 : url.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
ChecksumStatus other = (ChecksumStatus) obj;
if (needsUpload != other.needsUpload)
return false;
if (url == null) {
if (other.url != null)
return false;
} else if (!url.equals(other.url))
return false;
return true;
}
@Override
public String toString() {
return "ChecksumStatus [needsUpload=" + needsUpload + ", url=" + url + "]";
}
}

View File

@ -0,0 +1,182 @@
/*
* 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.domain;
import static com.google.common.base.Preconditions.checkNotNull;
import java.beans.ConstructorProperties;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;
import org.jclouds.javax.annotation.Nullable;
import com.google.gson.annotations.SerializedName;
/**
* Client object.
*/
public class Client {
public static Builder builder() {
return new Builder();
}
public static class Builder {
private X509Certificate certificate;
private PrivateKey privateKey;
private String orgname;
private String clientname;
private String name;
private boolean validator;
public Builder certificate(X509Certificate certificate) {
this.certificate = checkNotNull(certificate, "certificate");
return this;
}
public Builder privateKey(PrivateKey privateKey) {
this.privateKey = checkNotNull(privateKey, "privateKey");
return this;
}
public Builder orgname(String orgname) {
this.orgname = checkNotNull(orgname, "orgname");
return this;
}
public Builder clientname(String clientname) {
this.clientname = checkNotNull(clientname, "clientname");
return this;
}
public Builder name(String name) {
this.name = checkNotNull(name, "name");
return this;
}
public Builder isValidator(boolean validator) {
this.validator = validator;
return this;
}
public Client build() {
return new Client(certificate, orgname, clientname, name, validator, privateKey);
}
}
private final X509Certificate certificate;
@SerializedName("private_key")
private final PrivateKey privateKey;
private final String orgname;
private final String clientname;
private final String name;
private final boolean validator;
@ConstructorProperties({ "certificate", "orgname", "clientname", "name", "validator", "private_key" })
protected Client(X509Certificate certificate, String orgname, String clientname, String name, boolean validator,
@Nullable PrivateKey privateKey) {
this.certificate = certificate;
this.orgname = orgname;
this.clientname = clientname;
this.name = name;
this.validator = validator;
this.privateKey = privateKey;
}
public PrivateKey getPrivateKey() {
return privateKey;
}
public X509Certificate getCertificate() {
return certificate;
}
public String getOrgname() {
return orgname;
}
public String getClientname() {
return clientname;
}
public String getName() {
return name;
}
public boolean isValidator() {
return validator;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((certificate == null) ? 0 : certificate.hashCode());
result = prime * result + ((clientname == null) ? 0 : clientname.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + ((orgname == null) ? 0 : orgname.hashCode());
result = prime * result + ((privateKey == null) ? 0 : privateKey.hashCode());
result = prime * result + (validator ? 1231 : 1237);
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Client other = (Client) obj;
if (certificate == null) {
if (other.certificate != null)
return false;
} else if (!certificate.equals(other.certificate))
return false;
if (clientname == null) {
if (other.clientname != null)
return false;
} else if (!clientname.equals(other.clientname))
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (orgname == null) {
if (other.orgname != null)
return false;
} else if (!orgname.equals(other.orgname))
return false;
if (privateKey == null) {
if (other.privateKey != null)
return false;
} else if (!privateKey.equals(other.privateKey))
return false;
if (validator != other.validator)
return false;
return true;
}
@Override
public String toString() {
return "Client [name=" + name + ", clientname=" + clientname + ", orgname=" + orgname + ", isValidator="
+ validator + ", certificate=" + certificate + ", privateKey=" + (privateKey == null ? "not " : "")
+ "present]";
}
}

View File

@ -0,0 +1,217 @@
/*
* 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.domain;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.jclouds.chef.util.CollectionUtils.copyOfOrEmpty;
import java.beans.ConstructorProperties;
import java.net.URI;
import java.util.Set;
import org.jclouds.javax.annotation.Nullable;
import com.google.common.collect.ImmutableSet;
/**
* Cookbook definition as returned by the Chef server >= 0.10.8.
*/
public class CookbookDefinition {
public static Builder builder() {
return new Builder();
}
public static class Builder {
private String name;
private URI url;
private ImmutableSet.Builder<Version> versions = ImmutableSet.builder();
public Builder name(String name) {
this.name = checkNotNull(name, "name");
return this;
}
public Builder url(URI url) {
this.url = checkNotNull(url, "url");
return this;
}
public Builder version(Version version) {
this.versions.add(checkNotNull(version, "version"));
return this;
}
public Builder versions(Iterable<Version> versions) {
this.versions.addAll(checkNotNull(versions, "versions"));
return this;
}
public Builder from(CookbookDefinition def) {
this.url = checkNotNull(def.getUrl(), "url");
this.versions.addAll(checkNotNull(def.getVersions(), "versions"));
this.name = def.getName();
return this;
}
public CookbookDefinition build() {
return new CookbookDefinition(name, url, versions.build());
}
}
private final String name;
private final URI url;
private final Set<Version> versions;
@ConstructorProperties({"name", "url", "versions" })
protected CookbookDefinition(String name, URI url, @Nullable Set<Version> versions) {
this.name = name;
this.url = url;
this.versions = copyOfOrEmpty(versions);
}
public String getName() {
return name;
}
public URI getUrl() {
return url;
}
public Set<Version> getVersions() {
return versions;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + ((url == null) ? 0 : url.hashCode());
result = prime * result + ((versions == null) ? 0 : versions.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
CookbookDefinition other = (CookbookDefinition) obj;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (url == null) {
if (other.url != null)
return false;
} else if (!url.equals(other.url))
return false;
if (versions == null) {
if (other.versions != null)
return false;
} else if (!versions.equals(other.versions))
return false;
return true;
}
@Override
public String toString() {
return "CookbookDefinition [name=" + name + ", url=" + url + ", versions=" + versions + "]";
}
public static class Version {
public static Builder builder() {
return new Builder();
}
public static class Builder {
private URI url;
private String version;
public Builder url(URI url) {
this.url = checkNotNull(url, "url");
return this;
}
public Builder version(String version) {
this.version = checkNotNull(version, "version");
return this;
}
public Version build() {
return new Version(url, version);
}
}
private final URI url;
private final String version;
@ConstructorProperties({ "url", "version" })
protected Version(URI url, String version) {
this.url = url;
this.version = version;
}
public URI getUrl() {
return url;
}
public String getVersion() {
return version;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((url == null) ? 0 : url.hashCode());
result = prime * result + ((version == null) ? 0 : version.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Version other = (Version) obj;
if (url == null) {
if (other.url != null)
return false;
} else if (!url.equals(other.url))
return false;
if (version == null) {
if (other.version != null)
return false;
} else if (!version.equals(other.version))
return false;
return true;
}
@Override
public String toString() {
return "Version [url=" + url + ", version=" + version + "]";
}
}
}

View File

@ -0,0 +1,369 @@
/*
* 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.domain;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.jclouds.chef.util.CollectionUtils.copyOfOrEmpty;
import java.beans.ConstructorProperties;
import java.util.Set;
import org.jclouds.javax.annotation.Nullable;
import com.google.common.collect.ImmutableSet;
import com.google.gson.annotations.SerializedName;
/**
* Cookbook object.
*/
public class CookbookVersion {
public static Builder builder(String name, String version) {
return new Builder(name, version);
}
public static class Builder {
private String cookbookName;
private ImmutableSet.Builder<Resource> definitions = ImmutableSet.builder();
private ImmutableSet.Builder<Attribute> attributes = ImmutableSet.builder();
private ImmutableSet.Builder<Resource> files = ImmutableSet.builder();
private Metadata metadata = Metadata.builder().build();
private ImmutableSet.Builder<Resource> providers = ImmutableSet.builder();
private ImmutableSet.Builder<Resource> resources = ImmutableSet.builder();
private ImmutableSet.Builder<Resource> templates = ImmutableSet.builder();
private ImmutableSet.Builder<Resource> libraries = ImmutableSet.builder();
private String version;
private ImmutableSet.Builder<Resource> recipes = ImmutableSet.builder();
private ImmutableSet.Builder<Resource> rootFiles = ImmutableSet.builder();
public Builder(String name, String version) {
this.cookbookName = checkNotNull(name, "name");
this.version = checkNotNull(version, "version");
}
public Builder cookbookName(String cookbookName) {
this.cookbookName = checkNotNull(cookbookName, "cookbookName");
return this;
}
public Builder definition(Resource definition) {
this.definitions.add(checkNotNull(definition, "definition"));
return this;
}
public Builder definitions(Iterable<Resource> definitions) {
this.definitions.addAll(checkNotNull(definitions, "definitions"));
return this;
}
public Builder attribute(Attribute attribute) {
this.attributes.add(checkNotNull(attribute, "attribute"));
return this;
}
public Builder attributes(Iterable<Attribute> attributes) {
this.attributes.addAll(checkNotNull(attributes, "attributes"));
return this;
}
public Builder file(Resource file) {
this.files.add(checkNotNull(file, "file"));
return this;
}
public Builder files(Iterable<Resource> files) {
this.files.addAll(checkNotNull(files, "files"));
return this;
}
public Builder metadata(Metadata metadata) {
this.metadata = checkNotNull(metadata, "metadata");
return this;
}
public Builder provider(Resource provider) {
this.providers.add(checkNotNull(provider, "provider"));
return this;
}
public Builder providers(Iterable<Resource> providers) {
this.providers.addAll(checkNotNull(providers, "providers"));
return this;
}
public Builder resource(Resource resource) {
this.resources.add(checkNotNull(resource, "resource"));
return this;
}
public Builder resources(Iterable<Resource> resources) {
this.resources.addAll(checkNotNull(resources, "resources"));
return this;
}
public Builder template(Resource template) {
this.templates.add(checkNotNull(template, "template"));
return this;
}
public Builder templates(Iterable<Resource> templates) {
this.templates.addAll(checkNotNull(templates, "templates"));
return this;
}
public Builder library(Resource library) {
this.libraries.add(checkNotNull(library, "library"));
return this;
}
public Builder libraries(Iterable<Resource> libraries) {
this.libraries.addAll(checkNotNull(libraries, "libraries"));
return this;
}
public Builder version(String version) {
this.version = checkNotNull(version, "version");
return this;
}
public Builder recipe(Resource recipe) {
this.recipes.add(checkNotNull(recipe, "recipe"));
return this;
}
public Builder recipes(Iterable<Resource> recipes) {
this.recipes.addAll(checkNotNull(recipes, "recipes"));
return this;
}
public Builder rootFile(Resource rootFile) {
this.rootFiles.add(checkNotNull(rootFile, "rootFile"));
return this;
}
public Builder rootFiles(Iterable<Resource> rootFiles) {
this.rootFiles.addAll(checkNotNull(rootFiles, "rootFiles"));
return this;
}
public CookbookVersion build() {
return new CookbookVersion(checkNotNull(cookbookName, "name") + "-" + checkNotNull(version, "version"),
definitions.build(), attributes.build(), files.build(), metadata, providers.build(), cookbookName,
resources.build(), templates.build(), libraries.build(), version, recipes.build(), rootFiles.build());
}
}
private final String name;
private final Set<Resource> definitions;
private final Set<Attribute> attributes;
private final Set<Resource> files;
private final Metadata metadata;
private final Set<Resource> providers;
@SerializedName("cookbook_name")
private final String cookbookName;
private final Set<Resource> resources;
private final Set<Resource> templates;
private final Set<Resource> libraries;
private final String version;
private final Set<Resource> recipes;
@SerializedName("root_files")
private final Set<Resource> rootFiles;
// internal
@SerializedName("json_class")
private String _jsonClass = "Chef::CookbookVersion";
@SerializedName("chef_type")
private String _chefType = "cookbook_version";
@ConstructorProperties({ "name", "definitions", "attributes", "files", "metadata", "providers", "cookbook_name",
"resources", "templates", "libraries", "version", "recipes", "root_files" })
protected CookbookVersion(String name, @Nullable Set<Resource> definitions, @Nullable Set<Attribute> attributes,
@Nullable Set<Resource> files, Metadata metadata, @Nullable Set<Resource> providers, String cookbookName,
@Nullable Set<Resource> resources, @Nullable Set<Resource> templates, @Nullable Set<Resource> libraries,
String version, @Nullable Set<Resource> recipes, @Nullable Set<Resource> rootFiles) {
this.name = name;
this.definitions = copyOfOrEmpty(definitions);
this.attributes = copyOfOrEmpty(attributes);
this.files = copyOfOrEmpty(files);
this.metadata = metadata;
this.providers = copyOfOrEmpty(providers);
this.cookbookName = cookbookName;
this.resources = copyOfOrEmpty(resources);
this.templates = copyOfOrEmpty(templates);
this.libraries = copyOfOrEmpty(libraries);
this.version = version;
this.recipes = copyOfOrEmpty(recipes);
this.rootFiles = copyOfOrEmpty(rootFiles);
}
public String getName() {
return name;
}
public Set<Resource> getDefinitions() {
return definitions;
}
public Set<Attribute> getAttributes() {
return attributes;
}
public Set<Resource> getFiles() {
return files;
}
public Metadata getMetadata() {
return metadata;
}
public Set<Resource> getSuppliers() {
return providers;
}
public String getCookbookName() {
return cookbookName;
}
public Set<Resource> getResources() {
return resources;
}
public Set<Resource> getTemplates() {
return templates;
}
public Set<Resource> getLibraries() {
return libraries;
}
public String getVersion() {
return version;
}
public Set<Resource> getRecipes() {
return recipes;
}
public Set<Resource> getRootFiles() {
return rootFiles;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((attributes == null) ? 0 : attributes.hashCode());
result = prime * result + ((cookbookName == null) ? 0 : cookbookName.hashCode());
result = prime * result + ((definitions == null) ? 0 : definitions.hashCode());
result = prime * result + ((files == null) ? 0 : files.hashCode());
result = prime * result + ((libraries == null) ? 0 : libraries.hashCode());
result = prime * result + ((metadata == null) ? 0 : metadata.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + ((providers == null) ? 0 : providers.hashCode());
result = prime * result + ((recipes == null) ? 0 : recipes.hashCode());
result = prime * result + ((resources == null) ? 0 : resources.hashCode());
result = prime * result + ((rootFiles == null) ? 0 : rootFiles.hashCode());
result = prime * result + ((templates == null) ? 0 : templates.hashCode());
result = prime * result + ((version == null) ? 0 : version.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
CookbookVersion other = (CookbookVersion) obj;
if (attributes == null) {
if (other.attributes != null)
return false;
} else if (!attributes.equals(other.attributes))
return false;
if (cookbookName == null) {
if (other.cookbookName != null)
return false;
} else if (!cookbookName.equals(other.cookbookName))
return false;
if (definitions == null) {
if (other.definitions != null)
return false;
} else if (!definitions.equals(other.definitions))
return false;
if (files == null) {
if (other.files != null)
return false;
} else if (!files.equals(other.files))
return false;
if (libraries == null) {
if (other.libraries != null)
return false;
} else if (!libraries.equals(other.libraries))
return false;
if (metadata == null) {
if (other.metadata != null)
return false;
} else if (!metadata.equals(other.metadata))
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (providers == null) {
if (other.providers != null)
return false;
} else if (!providers.equals(other.providers))
return false;
if (recipes == null) {
if (other.recipes != null)
return false;
} else if (!recipes.equals(other.recipes))
return false;
if (resources == null) {
if (other.resources != null)
return false;
} else if (!resources.equals(other.resources))
return false;
if (rootFiles == null) {
if (other.rootFiles != null)
return false;
} else if (!rootFiles.equals(other.rootFiles))
return false;
if (templates == null) {
if (other.templates != null)
return false;
} else if (!templates.equals(other.templates))
return false;
if (version == null) {
if (other.version != null)
return false;
} else if (!version.equals(other.version))
return false;
return true;
}
@Override
public String toString() {
return "Cookbook [attributes=" + attributes + ", cookbookName=" + cookbookName + ", definitions=" + definitions
+ ", files=" + files + ", libraries=" + libraries + ", metadata=" + metadata + ", name=" + name
+ ", providers=" + providers + ", recipes=" + recipes + ", resources=" + resources + ", rootFiles="
+ rootFiles + ", templates=" + templates + ", version=" + version + "]";
}
}

View File

@ -0,0 +1,63 @@
/*
* 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.domain;
import static com.google.common.base.Preconditions.checkNotNull;
import org.jclouds.domain.JsonBall;
/**
* An item in a data bag.
*/
public class DatabagItem extends JsonBall {
private final String id;
public DatabagItem(String id, String value) {
super(value);
this.id = checkNotNull(id, "id");
}
@Override
public int hashCode() {
final int prime = 31;
int result = super.hashCode();
result = prime * result + ((id == null) ? 0 : id.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (!super.equals(obj))
return false;
if (getClass() != obj.getClass())
return false;
DatabagItem other = (DatabagItem) obj;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
return true;
}
public String getId() {
return id;
}
}

View File

@ -0,0 +1,178 @@
/*
* 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.domain;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.jclouds.chef.util.CollectionUtils.copyOfOrEmpty;
import java.beans.ConstructorProperties;
import java.util.Map;
import org.jclouds.domain.JsonBall;
import org.jclouds.javax.annotation.Nullable;
import com.google.common.collect.ImmutableMap;
import com.google.gson.annotations.SerializedName;
/**
* An environment.
*/
public class Environment {
public static Builder builder() {
return new Builder();
}
public static class Builder {
private String name;
private ImmutableMap.Builder<String, JsonBall> attributes = ImmutableMap.builder();
private ImmutableMap.Builder<String, JsonBall> overrideAttributes = ImmutableMap.builder();
private String description = "";
private ImmutableMap.Builder<String, String> cookbookVersions = ImmutableMap.builder();
public Builder name(String name) {
this.name = checkNotNull(name, "name");
return this;
}
public Builder attribute(String key, JsonBall value) {
this.attributes.put(checkNotNull(key, "key"), checkNotNull(value, "value"));
return this;
}
public Builder attributes(Map<String, JsonBall> attributes) {
this.attributes.putAll(checkNotNull(attributes, "attributes"));
return this;
}
public Builder overrideAttribute(String key, JsonBall value) {
this.overrideAttributes.put(checkNotNull(key, "key"), checkNotNull(value, "value"));
return this;
}
public Builder overrideAttributes(Map<String, JsonBall> overrideAttributes) {
this.overrideAttributes.putAll(checkNotNull(overrideAttributes, "overrideAttributes"));
return this;
}
public Builder cookbookVersion(String key, String version) {
this.cookbookVersions.put(checkNotNull(key, "key"), checkNotNull(version, "version"));
return this;
}
public Builder cookbookVersions(Map<String, String> cookbookVersions) {
this.cookbookVersions.putAll(checkNotNull(cookbookVersions, "cookbookVersions"));
return this;
}
public Builder description(String description) {
this.description = checkNotNull(description, "description");
return this;
}
public Environment build() {
return new Environment(name, attributes.build(), overrideAttributes.build(), description,
cookbookVersions.build());
}
}
private final String name;
@SerializedName("default_attributes")
private final Map<String, JsonBall> attributes;
@SerializedName("override_attributes")
private final Map<String, JsonBall> overrideAttributes;
private final String description;
@SerializedName("cookbook_versions")
private final Map<String, String> cookbookVersions;
// internal
@SerializedName("json_class")
private final String _jsonClass = "Chef::Environment";
@SerializedName("chef_type")
private final String _chefType = "environment";
@ConstructorProperties({ "name", "default_attributes", "override_attributes", "description", "cookbook_versions" })
protected Environment(String name, @Nullable Map<String, JsonBall> attributes,
@Nullable Map<String, JsonBall> overrideAttributes, String description,
@Nullable Map<String, String> cookbookVersions) {
this.name = name;
this.attributes = copyOfOrEmpty(attributes);
this.overrideAttributes = copyOfOrEmpty(overrideAttributes);
this.description = description;
this.cookbookVersions = copyOfOrEmpty(cookbookVersions);
}
public String getName() {
return name;
}
public Map<String, JsonBall> getAttributes() {
return attributes;
}
public Map<String, JsonBall> getOverrideAttributes() {
return overrideAttributes;
}
public String getDescription() {
return description;
}
public Map<String, String> getCookbookVersions() {
return cookbookVersions;
}
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
Environment that = (Environment) o;
if (attributes != null ? !attributes.equals(that.attributes) : that.attributes != null)
return false;
if (cookbookVersions != null ? !cookbookVersions.equals(that.cookbookVersions) : that.cookbookVersions != null)
return false;
if (description != null ? !description.equals(that.description) : that.description != null)
return false;
if (!name.equals(that.name))
return false;
if (overrideAttributes != null ? !overrideAttributes.equals(that.overrideAttributes)
: that.overrideAttributes != null)
return false;
return true;
}
@Override
public int hashCode() {
int result = name.hashCode();
result = 31 * result + (attributes != null ? attributes.hashCode() : 0);
result = 31 * result + (overrideAttributes != null ? overrideAttributes.hashCode() : 0);
result = 31 * result + (description != null ? description.hashCode() : 0);
result = 31 * result + (cookbookVersions != null ? cookbookVersions.hashCode() : 0);
return result;
}
@Override
public String toString() {
return "Environment [" + "name='" + name + '\'' + ", attributes=" + attributes + ", overrideAttributes="
+ overrideAttributes + ", description='" + description + '\'' + ", cookbookVersions=" + cookbookVersions
+ ']';
}
}

View File

@ -0,0 +1,447 @@
/*
* 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.domain;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.jclouds.chef.util.CollectionUtils.copyOfOrEmpty;
import java.beans.ConstructorProperties;
import java.util.Map;
import org.jclouds.javax.annotation.Nullable;
import com.google.common.collect.ImmutableMap;
import com.google.gson.annotations.SerializedName;
/**
* A metadata object.
*/
public class Metadata {
public static Builder builder() {
return new Builder();
}
public static class Builder {
private String license;
private String maintainer;
private ImmutableMap.Builder<String, String> suggestions = ImmutableMap.builder();
private ImmutableMap.Builder<String, String> dependencies = ImmutableMap.builder();
private String maintainerEmail;
private ImmutableMap.Builder<String, String> conflicting = ImmutableMap.builder();
private String description;
private ImmutableMap.Builder<String, String> providing = ImmutableMap.builder();
private ImmutableMap.Builder<String, String> platforms = ImmutableMap.builder();
private String version;
private ImmutableMap.Builder<String, String> recipes = ImmutableMap.builder();
private ImmutableMap.Builder<String, String> replacing = ImmutableMap.builder();
private String name;
private ImmutableMap.Builder<String, String> groupings = ImmutableMap.builder();
private String longDescription;
private ImmutableMap.Builder<String, Attribute> attributes = ImmutableMap.builder();
private ImmutableMap.Builder<String, String> recommendations = ImmutableMap.builder();
public Builder license(String license) {
this.license = checkNotNull(license, "license");
return this;
}
public Builder maintainer(String maintainer) {
this.maintainer = checkNotNull(maintainer, "maintainer");
return this;
}
public Builder suggestion(String key, String value) {
this.suggestions.put(checkNotNull(key, "key"), checkNotNull(value, "value"));
return this;
}
public Builder suggestions(Map<String, String> suggestions) {
this.suggestions.putAll(checkNotNull(suggestions, "suggestions"));
return this;
}
public Builder dependency(String key, String value) {
this.dependencies.put(checkNotNull(key, "key"), checkNotNull(value, "value"));
return this;
}
public Builder dependencies(Map<String, String> dependencies) {
this.dependencies.putAll(checkNotNull(dependencies, "dependencies"));
return this;
}
public Builder maintainerEmail(String maintainerEmail) {
this.maintainerEmail = checkNotNull(maintainerEmail, "maintainerEmail");
return this;
}
public Builder conflicting(String key, String value) {
this.conflicting.put(checkNotNull(key, "key"), checkNotNull(value, "value"));
return this;
}
public Builder conflicting(Map<String, String> conflicting) {
this.conflicting.putAll(checkNotNull(conflicting, "conflicting"));
return this;
}
public Builder description(String description) {
this.description = checkNotNull(description, "description");
return this;
}
public Builder providing(String key, String value) {
this.providing.put(checkNotNull(key, "key"), checkNotNull(value, "value"));
return this;
}
public Builder providing(Map<String, String> providing) {
this.providing.putAll(checkNotNull(providing, "providing"));
return this;
}
public Builder platform(String key, String value) {
this.platforms.put(checkNotNull(key, "key"), checkNotNull(value, "value"));
return this;
}
public Builder platforms(Map<String, String> platforms) {
this.platforms.putAll(checkNotNull(platforms, "platforms"));
return this;
}
public Builder version(String version) {
this.version = checkNotNull(version, "version");
return this;
}
public Builder recipe(String key, String value) {
this.recipes.put(checkNotNull(key, "key"), checkNotNull(value, "value"));
return this;
}
public Builder recipes(Map<String, String> recipes) {
this.recipes.putAll(checkNotNull(recipes, "recipes"));
return this;
}
public Builder replacing(String key, String value) {
this.replacing.put(checkNotNull(key, "key"), checkNotNull(value, "value"));
return this;
}
public Builder replacing(Map<String, String> replacing) {
this.replacing.putAll(checkNotNull(replacing, "replacing"));
return this;
}
public Builder name(String name) {
this.name = checkNotNull(name, "name");
return this;
}
public Builder grouping(String key, String value) {
this.groupings.put(checkNotNull(key, "key"), checkNotNull(value, "value"));
return this;
}
public Builder grouping(Map<String, String> groupings) {
this.groupings.putAll(checkNotNull(groupings, "groupings"));
return this;
}
public Builder longDescription(String longDescription) {
this.longDescription = checkNotNull(longDescription, "longDescription");
return this;
}
public Builder attribute(String key, Attribute value) {
this.attributes.put(checkNotNull(key, "key"), checkNotNull(value, "value"));
return this;
}
public Builder attributes(Map<String, Attribute> attributes) {
this.attributes.putAll(checkNotNull(attributes, "attributes"));
return this;
}
public Builder recommendation(String key, String value) {
this.recommendations.put(checkNotNull(key, "key"), checkNotNull(value, "value"));
return this;
}
public Builder recommendations(Map<String, String> recommendations) {
this.recommendations.putAll(checkNotNull(recommendations, "recommendations"));
return this;
}
public Metadata build() {
return new Metadata(license, maintainer, suggestions.build(), dependencies.build(), maintainerEmail,
conflicting.build(), description, providing.build(), platforms.build(), version, recipes.build(),
replacing.build(), name, groupings.build(), longDescription, attributes.build(), recommendations.build());
}
}
private final String license;
private final String maintainer;
private final Map<String, String> suggestions;
private final Map<String, String> dependencies;
@SerializedName("maintainer_email")
private final String maintainerEmail;
private final Map<String, String> conflicting;
private final String description;
private final Map<String, String> providing;
private final Map<String, String> platforms;
private final String version;
private final Map<String, String> recipes;
private final Map<String, String> replacing;
private final String name;
private final Map<String, String> groupings;
@SerializedName("long_description")
private final String longDescription;
private final Map<String, Attribute> attributes;
private final Map<String, String> recommendations;
@ConstructorProperties({ "license", "maintainer", "suggestions", "dependencies", "maintainer_email", "conflicting",
"description", "providing", "platforms", "version", "recipes", "replacing", "name", "groupings",
"long_description", "attributes", "recommendations" })
protected Metadata(String license, String maintainer, @Nullable Map<String, String> suggestions,
@Nullable Map<String, String> dependencies, String maintainerEmail, @Nullable Map<String, String> conflicting,
String description, @Nullable Map<String, String> providing, @Nullable Map<String, String> platforms,
String version, @Nullable Map<String, String> recipes, @Nullable Map<String, String> replacing, String name,
@Nullable Map<String, String> groupings, String longDescription, @Nullable Map<String, Attribute> attributes,
@Nullable Map<String, String> recommendations) {
this.license = license;
this.maintainer = maintainer;
this.suggestions = copyOfOrEmpty(suggestions);
this.dependencies = copyOfOrEmpty(dependencies);
this.maintainerEmail = maintainerEmail;
this.conflicting = copyOfOrEmpty(conflicting);
this.description = description;
this.providing = copyOfOrEmpty(providing);
this.platforms = copyOfOrEmpty(platforms);
this.version = version;
this.recipes = copyOfOrEmpty(recipes);
this.replacing = copyOfOrEmpty(replacing);
this.name = name;
this.groupings = copyOfOrEmpty(groupings);
this.longDescription = longDescription;
this.attributes = copyOfOrEmpty(attributes);
this.recommendations = copyOfOrEmpty(recommendations);
}
public String getLicense() {
return license;
}
public String getMaintainer() {
return maintainer;
}
public Map<String, String> getSuggestions() {
return suggestions;
}
public Map<String, String> getDependencies() {
return dependencies;
}
public String getMaintainerEmail() {
return maintainerEmail;
}
public Map<String, String> getConflicting() {
return conflicting;
}
public String getDescription() {
return description;
}
public Map<String, String> getProviding() {
return providing;
}
public Map<String, String> getPlatforms() {
return platforms;
}
public String getVersion() {
return version;
}
public Map<String, String> getRecipes() {
return recipes;
}
public Map<String, String> getReplacing() {
return replacing;
}
public String getName() {
return name;
}
public Map<String, String> getGroupings() {
return groupings;
}
public String getLongDescription() {
return longDescription;
}
public Map<String, Attribute> getAttributes() {
return attributes;
}
public Map<String, String> getRecommendations() {
return recommendations;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((attributes == null) ? 0 : attributes.hashCode());
result = prime * result + ((conflicting == null) ? 0 : conflicting.hashCode());
result = prime * result + ((dependencies == null) ? 0 : dependencies.hashCode());
result = prime * result + ((description == null) ? 0 : description.hashCode());
result = prime * result + ((groupings == null) ? 0 : groupings.hashCode());
result = prime * result + ((license == null) ? 0 : license.hashCode());
result = prime * result + ((longDescription == null) ? 0 : longDescription.hashCode());
result = prime * result + ((maintainer == null) ? 0 : maintainer.hashCode());
result = prime * result + ((maintainerEmail == null) ? 0 : maintainerEmail.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + ((platforms == null) ? 0 : platforms.hashCode());
result = prime * result + ((providing == null) ? 0 : providing.hashCode());
result = prime * result + ((recipes == null) ? 0 : recipes.hashCode());
result = prime * result + ((recommendations == null) ? 0 : recommendations.hashCode());
result = prime * result + ((replacing == null) ? 0 : replacing.hashCode());
result = prime * result + ((suggestions == null) ? 0 : suggestions.hashCode());
result = prime * result + ((version == null) ? 0 : version.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Metadata other = (Metadata) obj;
if (attributes == null) {
if (other.attributes != null)
return false;
} else if (!attributes.equals(other.attributes))
return false;
if (conflicting == null) {
if (other.conflicting != null)
return false;
} else if (!conflicting.equals(other.conflicting))
return false;
if (dependencies == null) {
if (other.dependencies != null)
return false;
} else if (!dependencies.equals(other.dependencies))
return false;
if (description == null) {
if (other.description != null)
return false;
} else if (!description.equals(other.description))
return false;
if (groupings == null) {
if (other.groupings != null)
return false;
} else if (!groupings.equals(other.groupings))
return false;
if (license == null) {
if (other.license != null)
return false;
} else if (!license.equals(other.license))
return false;
if (longDescription == null) {
if (other.longDescription != null)
return false;
} else if (!longDescription.equals(other.longDescription))
return false;
if (maintainer == null) {
if (other.maintainer != null)
return false;
} else if (!maintainer.equals(other.maintainer))
return false;
if (maintainerEmail == null) {
if (other.maintainerEmail != null)
return false;
} else if (!maintainerEmail.equals(other.maintainerEmail))
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (platforms == null) {
if (other.platforms != null)
return false;
} else if (!platforms.equals(other.platforms))
return false;
if (providing == null) {
if (other.providing != null)
return false;
} else if (!providing.equals(other.providing))
return false;
if (recipes == null) {
if (other.recipes != null)
return false;
} else if (!recipes.equals(other.recipes))
return false;
if (recommendations == null) {
if (other.recommendations != null)
return false;
} else if (!recommendations.equals(other.recommendations))
return false;
if (replacing == null) {
if (other.replacing != null)
return false;
} else if (!replacing.equals(other.replacing))
return false;
if (suggestions == null) {
if (other.suggestions != null)
return false;
} else if (!suggestions.equals(other.suggestions))
return false;
if (version == null) {
if (other.version != null)
return false;
} else if (!version.equals(other.version))
return false;
return true;
}
@Override
public String toString() {
return "Metadata [attributes=" + attributes + ", conflicting=" + conflicting + ", dependencies=" + dependencies
+ ", description=" + description + ", groupings=" + groupings + ", license=" + license
+ ", longDescription=" + longDescription + ", maintainer=" + maintainer + ", maintainerEmail="
+ maintainerEmail + ", name=" + name + ", platforms=" + platforms + ", providing=" + providing
+ ", recipes=" + recipes + ", recommendations=" + recommendations + ", replacing=" + replacing
+ ", suggestions=" + suggestions + ", version=" + version + "]";
}
}

View File

@ -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.domain;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.jclouds.chef.util.CollectionUtils.copyOfOrEmpty;
import java.beans.ConstructorProperties;
import java.util.List;
import java.util.Map;
import org.jclouds.domain.JsonBall;
import org.jclouds.javax.annotation.Nullable;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.gson.annotations.SerializedName;
/**
* Node object.
*/
public class Node {
public static Builder builder() {
return new Builder();
}
public static class Builder {
private String name;
private ImmutableMap.Builder<String, JsonBall> normalAttributes = ImmutableMap.builder();
private ImmutableMap.Builder<String, JsonBall> overrideAttributes = ImmutableMap.builder();
private ImmutableMap.Builder<String, JsonBall> defaultAttributes = ImmutableMap.builder();
private ImmutableMap.Builder<String, JsonBall> automaticAttributes = ImmutableMap.builder();
private ImmutableList.Builder<String> runList = ImmutableList.builder();
private String environment;
public Builder name(String name) {
this.name = checkNotNull(name, "name");
return this;
}
public Builder normalAttribute(String key, JsonBall value) {
this.normalAttributes.put(checkNotNull(key, "key"), checkNotNull(value, "value"));
return this;
}
public Builder normalAttributes(Map<String, JsonBall> normalAttributes) {
this.normalAttributes.putAll(checkNotNull(normalAttributes, "normalAttributes"));
return this;
}
public Builder overrideAttribute(String key, JsonBall value) {
this.overrideAttributes.put(checkNotNull(key, "key"), checkNotNull(value, "value"));
return this;
}
public Builder overrideAttributes(Map<String, JsonBall> overrideAttributes) {
this.overrideAttributes.putAll(checkNotNull(overrideAttributes, "overrideAttributes"));
return this;
}
public Builder defaultAttribute(String key, JsonBall value) {
this.defaultAttributes.put(checkNotNull(key, "key"), checkNotNull(value, "value"));
return this;
}
public Builder defaultAttributes(Map<String, JsonBall> defaultAttributes) {
this.defaultAttributes.putAll(checkNotNull(defaultAttributes, "defaultAttributes"));
return this;
}
public Builder automaticAttribute(String key, JsonBall value) {
this.automaticAttributes.put(checkNotNull(key, "key"), checkNotNull(value, "value"));
return this;
}
public Builder automaticAttributes(Map<String, JsonBall> automaticAttribute) {
this.automaticAttributes.putAll(checkNotNull(automaticAttribute, "automaticAttribute"));
return this;
}
public Builder runListElement(String element) {
this.runList.add(checkNotNull(element, "element"));
return this;
}
public Builder runList(Iterable<String> runList) {
this.runList.addAll(checkNotNull(runList, "runList"));
return this;
}
/**
* @since Chef 0.10
*/
public Builder environment(String environment) {
this.environment = checkNotNull(environment, "environment");
return this;
}
public Node build() {
return new Node(name, normalAttributes.build(), overrideAttributes.build(), defaultAttributes.build(),
automaticAttributes.build(), runList.build(), environment);
}
}
private final String name;
@SerializedName("normal")
private final Map<String, JsonBall> normalAttributes;
@SerializedName("override")
private final Map<String, JsonBall> overrideAttributes;
@SerializedName("default")
private final Map<String, JsonBall> defaultAttributes;
@SerializedName("automatic")
private final Map<String, JsonBall> automaticAttributes;
@SerializedName("run_list")
private final List<String> runList;
@SerializedName("chef_environment")
private final String environment;
// internal
@SerializedName("json_class")
private final String _jsonClass = "Chef::Node";
@SerializedName("chef_type")
private final String _chefType = "node";
@ConstructorProperties({ "name", "normal", "override", "default", "automatic", "run_list", "chef_environment" })
protected Node(String name, @Nullable Map<String, JsonBall> normalAttributes,
@Nullable Map<String, JsonBall> overrideAttributes, @Nullable Map<String, JsonBall> defaultAttributes,
@Nullable Map<String, JsonBall> automaticAttributes, List<String> runList, @Nullable String environment) {
this.name = name;
this.environment = environment;
this.normalAttributes = copyOfOrEmpty(normalAttributes);
this.overrideAttributes = copyOfOrEmpty(overrideAttributes);
this.defaultAttributes = copyOfOrEmpty(defaultAttributes);
this.automaticAttributes = copyOfOrEmpty(automaticAttributes);
this.runList = copyOfOrEmpty(runList);
}
public String getName() {
return name;
}
public Map<String, JsonBall> getNormalAttributes() {
return normalAttributes;
}
public Map<String, JsonBall> getOverrideAttributes() {
return overrideAttributes;
}
public Map<String, JsonBall> getDefaultAttributes() {
return defaultAttributes;
}
public Map<String, JsonBall> getAutomaticAttributes() {
return automaticAttributes;
}
public List<String> getRunList() {
return runList;
}
/**
* @since Chef 0.10
*/
public String getEnvironment() {
return environment;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((_chefType == null) ? 0 : _chefType.hashCode());
result = prime * result + ((_jsonClass == null) ? 0 : _jsonClass.hashCode());
result = prime * result + ((automaticAttributes == null) ? 0 : automaticAttributes.hashCode());
result = prime * result + ((defaultAttributes == null) ? 0 : defaultAttributes.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + ((normalAttributes == null) ? 0 : normalAttributes.hashCode());
result = prime * result + ((overrideAttributes == null) ? 0 : overrideAttributes.hashCode());
result = prime * result + ((runList == null) ? 0 : runList.hashCode());
result = prime * result + ((environment == null) ? 0 : environment.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Node other = (Node) obj;
if (_chefType == null) {
if (other._chefType != null)
return false;
} else if (!_chefType.equals(other._chefType))
return false;
if (_jsonClass == null) {
if (other._jsonClass != null)
return false;
} else if (!_jsonClass.equals(other._jsonClass))
return false;
if (automaticAttributes == null) {
if (other.automaticAttributes != null)
return false;
} else if (!automaticAttributes.equals(other.automaticAttributes))
return false;
if (defaultAttributes == null) {
if (other.defaultAttributes != null)
return false;
} else if (!defaultAttributes.equals(other.defaultAttributes))
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (normalAttributes == null) {
if (other.normalAttributes != null)
return false;
} else if (!normalAttributes.equals(other.normalAttributes))
return false;
if (overrideAttributes == null) {
if (other.overrideAttributes != null)
return false;
} else if (!overrideAttributes.equals(other.overrideAttributes))
return false;
if (runList == null) {
if (other.runList != null)
return false;
} else if (!runList.equals(other.runList))
return false;
if (environment == null) {
if (other.environment != null)
return false;
} else if (!environment.equals(other.environment))
return false;
return true;
}
@Override
public String toString() {
return "Node [name=" + name + ", runList=" + runList + ", normalAttributes=" + normalAttributes
+ ", defaultAttributes=" + defaultAttributes + ", overrideAttributes=" + overrideAttributes
+ ", chefEnvironment=" + environment + ", automaticAttributes=" + automaticAttributes + "]";
}
}

View File

@ -0,0 +1,169 @@
/*
* 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.domain;
import static com.google.common.base.Preconditions.checkNotNull;
import java.beans.ConstructorProperties;
import java.net.URI;
import java.util.Arrays;
import org.jclouds.io.payloads.FilePayload;
import com.google.common.primitives.Bytes;
/**
* Resource object.
*/
public class Resource {
public static Builder builder() {
return new Builder();
}
public static class Builder {
private String name;
private URI url;
private byte[] checksum;
private String path;
private String specificity = "default";
public Builder name(String name) {
this.name = checkNotNull(name, "name");
return this;
}
public Builder url(URI url) {
this.url = checkNotNull(url, "url");
return this;
}
public Builder checksum(byte[] checksum) {
this.checksum = checkNotNull(checksum, "checksum");
return this;
}
public Builder path(String path) {
this.path = checkNotNull(path, "path");
return this;
}
public Builder specificity(String specificity) {
this.specificity = checkNotNull(specificity, "specificity");
return this;
}
public Builder fromPayload(FilePayload payload) {
checkNotNull(payload, "payload");
this.name(payload.getRawContent().getName());
this.checksum(payload.getContentMetadata().getContentMD5());
this.path(payload.getRawContent().getPath());
return this;
}
public Resource build() {
return new Resource(name, url, checksum, path, specificity);
}
}
private final String name;
private final URI url;
private final byte[] checksum;
private final String path;
private final String specificity;
@ConstructorProperties({ "name", "url", "checksum", "path", "specificity" })
protected Resource(String name, URI url, byte[] checksum, String path, String specificity) {
this.name = name;
this.url = url;
this.checksum = checksum;
this.path = path;
this.specificity = specificity;
}
public String getName() {
return name;
}
public URI getUrl() {
return url;
}
public byte[] getChecksum() {
return checksum;
}
public String getPath() {
return path;
}
public String getSpecificity() {
return specificity;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + Arrays.hashCode(checksum);
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + ((path == null) ? 0 : path.hashCode());
result = prime * result + ((specificity == null) ? 0 : specificity.hashCode());
result = prime * result + ((url == null) ? 0 : url.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Resource other = (Resource) obj;
if (!Arrays.equals(checksum, other.checksum))
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (path == null) {
if (other.path != null)
return false;
} else if (!path.equals(other.path))
return false;
if (specificity == null) {
if (other.specificity != null)
return false;
} else if (!specificity.equals(other.specificity))
return false;
if (url == null) {
if (other.url != null)
return false;
} else if (!url.equals(other.url))
return false;
return true;
}
@Override
public String toString() {
return "Resource [checksum=" + Bytes.asList(checksum) + ", name=" + name + ", path=" + path + ", specificity="
+ specificity + ", url=" + url + "]";
}
}

View File

@ -0,0 +1,205 @@
/*
* 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.domain;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.jclouds.chef.util.CollectionUtils.copyOfOrEmpty;
import java.beans.ConstructorProperties;
import java.util.List;
import java.util.Map;
import org.jclouds.domain.JsonBall;
import org.jclouds.javax.annotation.Nullable;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.gson.annotations.SerializedName;
/**
* Role object.
*/
public class Role {
public static Builder builder() {
return new Builder();
}
public static class Builder {
private String name;
private String description;
private ImmutableMap.Builder<String, JsonBall> overrideAttributes = ImmutableMap.builder();
private ImmutableMap.Builder<String, JsonBall> defaultAttributes = ImmutableMap.builder();
private ImmutableList.Builder<String> runList = ImmutableList.builder();
public Builder name(String name) {
this.name = checkNotNull(name, "name");
return this;
}
public Builder description(String description) {
this.description = checkNotNull(description, "description");
return this;
}
public Builder overrideAttribute(String key, JsonBall value) {
this.overrideAttributes.put(checkNotNull(key, "key"), checkNotNull(value, "value"));
return this;
}
public Builder overrideAttributes(Map<String, JsonBall> overrideAttributes) {
this.overrideAttributes.putAll(checkNotNull(overrideAttributes, "overrideAttributes"));
return this;
}
public Builder defaultAttribute(String key, JsonBall value) {
this.defaultAttributes.put(checkNotNull(key, "key"), checkNotNull(value, "value"));
return this;
}
public Builder defaultAttributes(Map<String, JsonBall> defaultAttributes) {
this.defaultAttributes.putAll(checkNotNull(defaultAttributes, "defaultAttributes"));
return this;
}
public Builder runListElement(String element) {
this.runList.add(checkNotNull(element, "element"));
return this;
}
public Builder runList(Iterable<String> runList) {
this.runList.addAll(checkNotNull(runList, "runList"));
return this;
}
public Role build() {
return new Role(name, description, defaultAttributes.build(), runList.build(), overrideAttributes.build());
}
}
private final String name;
private final String description;
@SerializedName("override_attributes")
private final Map<String, JsonBall> overrideAttributes;
@SerializedName("default_attributes")
private final Map<String, JsonBall> defaultAttributes;
@SerializedName("run_list")
private final List<String> runList;
// internal
@SerializedName("json_class")
private final String _jsonClass = "Chef::Role";
@SerializedName("chef_type")
private final String _chefType = "role";
@ConstructorProperties({ "name", "description", "default_attributes", "run_list", "override_attributes" })
protected Role(String name, String description, @Nullable Map<String, JsonBall> defaultAttributes,
@Nullable List<String> runList, @Nullable Map<String, JsonBall> overrideAttributes) {
this.name = name;
this.description = description;
this.defaultAttributes = copyOfOrEmpty(defaultAttributes);
this.runList = copyOfOrEmpty(runList);
this.overrideAttributes = copyOfOrEmpty(overrideAttributes);
}
public String getName() {
return name;
}
public String getDescription() {
return description;
}
public Map<String, JsonBall> getOverrideAttributes() {
return overrideAttributes;
}
public Map<String, JsonBall> getDefaultAttributes() {
return defaultAttributes;
}
public List<String> getRunList() {
return runList;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((_chefType == null) ? 0 : _chefType.hashCode());
result = prime * result + ((_jsonClass == null) ? 0 : _jsonClass.hashCode());
result = prime * result + ((defaultAttributes == null) ? 0 : defaultAttributes.hashCode());
result = prime * result + ((description == null) ? 0 : description.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + ((overrideAttributes == null) ? 0 : overrideAttributes.hashCode());
result = prime * result + ((runList == null) ? 0 : runList.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Role other = (Role) obj;
if (_chefType == null) {
if (other._chefType != null)
return false;
} else if (!_chefType.equals(other._chefType))
return false;
if (_jsonClass == null) {
if (other._jsonClass != null)
return false;
} else if (!_jsonClass.equals(other._jsonClass))
return false;
if (defaultAttributes == null) {
if (other.defaultAttributes != null)
return false;
} else if (!defaultAttributes.equals(other.defaultAttributes))
return false;
if (description == null) {
if (other.description != null)
return false;
} else if (!description.equals(other.description))
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (overrideAttributes == null) {
if (other.overrideAttributes != null)
return false;
} else if (!overrideAttributes.equals(other.overrideAttributes))
return false;
if (runList == null) {
if (other.runList != null)
return false;
} else if (!runList.equals(other.runList))
return false;
return true;
}
@Override
public String toString() {
return "Role [name=" + name + ", description=" + description + ", defaultAttributes=" + defaultAttributes
+ ", overrideAttributes=" + overrideAttributes + ", runList=" + runList + "]";
}
}

View File

@ -0,0 +1,195 @@
/*
* 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.domain;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.jclouds.chef.util.CollectionUtils.copyOfOrEmpty;
import java.beans.ConstructorProperties;
import java.util.Date;
import java.util.Set;
import org.jclouds.javax.annotation.Nullable;
import com.google.common.collect.ImmutableSet;
import com.google.gson.annotations.SerializedName;
/**
* Sandbox object.
*/
public class Sandbox {
public static Builder builder() {
return new Builder();
}
public static class Builder {
private String rev;
private boolean isCompleted;
private Date createTime;
private ImmutableSet.Builder<String> checksums = ImmutableSet.builder();
private String name;
private String guid;
public Builder rev(String rev) {
this.rev = checkNotNull(rev, "rev");
return this;
}
public Builder isCompleted(boolean isCompleted) {
this.isCompleted = isCompleted;
return this;
}
public Builder createTime(Date createTime) {
this.createTime = createTime;
return this;
}
public Builder checksum(String checksum) {
this.checksums.add(checkNotNull(checksum, "checksum"));
return this;
}
public Builder checksums(Iterable<String> checksums) {
this.checksums.addAll(checkNotNull(checksums, "checksums"));
return this;
}
public Builder name(String name) {
this.name = checkNotNull(name, "name");
return this;
}
public Builder guid(String guid) {
this.guid = checkNotNull(guid, "guid");
return this;
}
public Sandbox build() {
return new Sandbox(rev, isCompleted, createTime, checksums.build(), name, guid);
}
}
@SerializedName("_rev")
private final String rev;
@SerializedName("is_completed")
private final boolean isCompleted;
@SerializedName("create_time")
private final Date createTime;
private final Set<String> checksums;
private final String name;
private final String guid;
// internal
@SerializedName("json_class")
private final String _jsonClass = "Chef::Sandbox";
@SerializedName("chef_type")
private final String _chefType = "sandbox";
@ConstructorProperties({ "_rev", "is_completed", "create_time", "checksums", "name", "guid" })
protected Sandbox(String rev, boolean isCompleted, Date createTime, @Nullable Set<String> checksums, String name,
String guid) {
this.rev = rev;
this.isCompleted = isCompleted;
this.createTime = createTime;
this.checksums = copyOfOrEmpty(checksums);
this.name = name;
this.guid = guid;
}
public String getRev() {
return rev;
}
public boolean isCompleted() {
return isCompleted;
}
public Date getCreateTime() {
return createTime;
}
public Set<String> getChecksums() {
return checksums;
}
public String getName() {
return name;
}
public String getGuid() {
return guid;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((checksums == null) ? 0 : checksums.hashCode());
result = prime * result + ((createTime == null) ? 0 : createTime.hashCode());
result = prime * result + ((guid == null) ? 0 : guid.hashCode());
result = prime * result + (isCompleted ? 1231 : 1237);
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + ((rev == null) ? 0 : rev.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Sandbox other = (Sandbox) obj;
if (checksums == null) {
if (other.checksums != null)
return false;
} else if (!checksums.equals(other.checksums))
return false;
if (createTime == null) {
if (other.createTime != null)
return false;
} else if (!createTime.equals(other.createTime))
return false;
if (guid == null) {
if (other.guid != null)
return false;
} else if (!guid.equals(other.guid))
return false;
if (isCompleted != other.isCompleted)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (rev == null) {
if (other.rev != null)
return false;
} else if (!rev.equals(other.rev))
return false;
return true;
}
@Override
public String toString() {
return "Sandbox [checksums=" + checksums + ", createTime=" + createTime + ", guid=" + guid + ", isCompleted="
+ isCompleted + ", name=" + name + ", rev=" + rev + "]";
}
}

View File

@ -0,0 +1,46 @@
/*
* 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.domain;
import java.util.LinkedHashSet;
import com.google.common.collect.Iterables;
/**
* A result of a search.
*/
public class SearchResult<T> extends LinkedHashSet<T> {
private static final long serialVersionUID = 4000610660948065287L;
private long start;
SearchResult() {
}
public SearchResult(long start, Iterable<T> results) {
this.start = start;
Iterables.addAll(this, results);
}
/**
*
* @return the result position this started from from
*/
long getStart() {
return start;
}
}

View File

@ -0,0 +1,136 @@
/*
* 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.domain;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.jclouds.chef.util.CollectionUtils.copyOfOrEmpty;
import java.beans.ConstructorProperties;
import java.net.URI;
import java.util.List;
import java.util.Map;
import org.jclouds.javax.annotation.Nullable;
import com.google.common.collect.ImmutableMap;
import com.google.gson.annotations.SerializedName;
/**
* An upload sandbox.
*/
public class UploadSandbox {
public static Builder builder() {
return new Builder();
}
public static class Builder {
private URI uri;
private ImmutableMap.Builder<List<Byte>, ChecksumStatus> checksums = ImmutableMap.builder();
private String sandboxId;
public Builder uri(URI uri) {
this.uri = checkNotNull(uri, "uri");
return this;
}
public Builder checksum(List<Byte> key, ChecksumStatus value) {
this.checksums.put(checkNotNull(key, "key"), checkNotNull(value, "value"));
return this;
}
public Builder checksums(Map<List<Byte>, ChecksumStatus> checksums) {
this.checksums.putAll(checkNotNull(checksums, "checksums"));
return this;
}
public Builder sandboxId(String sandboxId) {
this.sandboxId = checkNotNull(sandboxId, "sandboxId");
return this;
}
public UploadSandbox build() {
return new UploadSandbox(uri, checksums.build(), sandboxId);
}
}
private final URI uri;
private final Map<List<Byte>, ChecksumStatus> checksums;
@SerializedName("sandbox_id")
private final String sandboxId;
@ConstructorProperties({ "uri", "checksums", "sandbox_id" })
protected UploadSandbox(URI uri, @Nullable Map<List<Byte>, ChecksumStatus> checksums, String sandboxId) {
this.uri = uri;
this.checksums = copyOfOrEmpty(checksums);
this.sandboxId = sandboxId;
}
public URI getUri() {
return uri;
}
public Map<List<Byte>, ChecksumStatus> getChecksums() {
return checksums;
}
public String getSandboxId() {
return sandboxId;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((checksums == null) ? 0 : checksums.hashCode());
result = prime * result + ((sandboxId == null) ? 0 : sandboxId.hashCode());
result = prime * result + ((uri == null) ? 0 : uri.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
UploadSandbox other = (UploadSandbox) obj;
if (checksums == null) {
if (other.checksums != null)
return false;
} else if (!checksums.equals(other.checksums))
return false;
if (sandboxId == null) {
if (other.sandboxId != null)
return false;
} else if (!sandboxId.equals(other.sandboxId))
return false;
if (uri == null) {
if (other.uri != null)
return false;
} else if (!uri.equals(other.uri))
return false;
return true;
}
@Override
public String toString() {
return "UploadSandbox [checksums=" + checksums + ", id=" + sandboxId + ", uri=" + uri + "]";
}
}

View File

@ -0,0 +1,199 @@
/*
* 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.filters;
import static com.google.common.base.Charsets.UTF_8;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.hash.Hashing.sha1;
import static com.google.common.io.BaseEncoding.base64;
import java.io.IOException;
import java.security.PrivateKey;
import java.util.NoSuchElementException;
import javax.annotation.Resource;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Provider;
import javax.inject.Singleton;
import org.jclouds.Constants;
import org.jclouds.crypto.Crypto;
import org.jclouds.date.TimeStamp;
import org.jclouds.domain.Credentials;
import org.jclouds.http.HttpException;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpRequestFilter;
import org.jclouds.http.HttpUtils;
import org.jclouds.http.internal.SignatureWire;
import org.jclouds.io.ByteStreams2;
import org.jclouds.io.Payload;
import org.jclouds.io.Payloads;
import org.jclouds.io.payloads.MultipartForm;
import org.jclouds.io.payloads.Part;
import org.jclouds.io.payloads.RSAEncryptingPayload;
import org.jclouds.logging.Logger;
import org.jclouds.util.Strings2;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Predicate;
import com.google.common.base.Splitter;
import com.google.common.base.Supplier;
import com.google.common.base.Throwables;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Iterables;
import com.google.common.collect.Multimap;
import com.google.common.io.ByteSource;
/**
* Ported from mixlib-authentication in order to sign Chef requests.
*
* @see <a href= "http://github.com/opscode/mixlib-authentication" />
*/
@Singleton
public class SignedHeaderAuth implements HttpRequestFilter {
public static final String SIGNING_DESCRIPTION = "version=1.0";
private final SignatureWire signatureWire;
private final Supplier<Credentials> creds;
private final Supplier<PrivateKey> supplyKey;
private final Provider<String> timeStampProvider;
private final String emptyStringHash;
private final HttpUtils utils;
private final Crypto crypto;
@Resource
@Named(Constants.LOGGER_SIGNATURE)
Logger signatureLog = Logger.NULL;
@Inject
public SignedHeaderAuth(SignatureWire signatureWire, @org.jclouds.location.Provider Supplier<Credentials> creds,
Supplier<PrivateKey> supplyKey, @TimeStamp Provider<String> timeStampProvider, HttpUtils utils, Crypto crypto) {
this.signatureWire = checkNotNull(signatureWire, "signatureWire");
this.creds = checkNotNull(creds, "creds");
this.supplyKey = checkNotNull(supplyKey, "supplyKey");
this.timeStampProvider = checkNotNull(timeStampProvider, "timeStampProvider");
this.emptyStringHash = hashBody(Payloads.newStringPayload(""));
this.utils = checkNotNull(utils, "utils");
this.crypto = checkNotNull(crypto, "crypto");
}
public HttpRequest filter(HttpRequest input) throws HttpException {
HttpRequest request = input.toBuilder().endpoint(input.getEndpoint().toString().replace("%3F", "?")).build();
String contentHash = hashBody(request.getPayload());
Multimap<String, String> headers = ArrayListMultimap.create();
headers.put("X-Ops-Content-Hash", contentHash);
String timestamp = timeStampProvider.get();
String toSign = createStringToSign(request.getMethod(), hashPath(request.getEndpoint().getPath()), contentHash,
timestamp);
headers.put("X-Ops-Userid", creds.get().identity);
headers.put("X-Ops-Sign", SIGNING_DESCRIPTION);
request = calculateAndReplaceAuthorizationHeaders(request, toSign);
headers.put("X-Ops-Timestamp", timestamp);
utils.logRequest(signatureLog, request, "<<");
return request.toBuilder().replaceHeaders(headers).build();
}
@VisibleForTesting
HttpRequest calculateAndReplaceAuthorizationHeaders(HttpRequest request, String toSign) throws HttpException {
String signature = sign(toSign);
if (signatureWire.enabled())
signatureWire.input(Strings2.toInputStream(signature));
String[] signatureLines = Iterables.toArray(Splitter.fixedLength(60).split(signature), String.class);
Multimap<String, String> headers = ArrayListMultimap.create();
for (int i = 0; i < signatureLines.length; i++) {
headers.put("X-Ops-Authorization-" + (i + 1), signatureLines[i]);
}
return request.toBuilder().replaceHeaders(headers).build();
}
public String createStringToSign(String request, String hashedPath, String contentHash, String timestamp) {
return new StringBuilder().append("Method:").append(request).append("\n").append("Hashed Path:")
.append(hashedPath).append("\n").append("X-Ops-Content-Hash:").append(contentHash).append("\n")
.append("X-Ops-Timestamp:").append(timestamp).append("\n").append("X-Ops-UserId:")
.append(creds.get().identity).toString();
}
@VisibleForTesting
String hashPath(String path) {
try {
return base64().encode(ByteSource.wrap(canonicalPath(path).getBytes(UTF_8)).hash(sha1()).asBytes());
} catch (Exception e) {
Throwables.propagateIfPossible(e);
throw new HttpException("error creating sigature for path: " + path, e);
}
}
/**
* Build the canonicalized path, which collapses multiple slashes (/) and
* removes a trailing slash unless the path is only "/"
*/
@VisibleForTesting
String canonicalPath(String path) {
path = path.replaceAll("\\/+", "/");
return path.endsWith("/") && path.length() > 1 ? path.substring(0, path.length() - 1) : path;
}
@VisibleForTesting
String hashBody(Payload payload) {
if (payload == null)
return emptyStringHash;
payload = useTheFilePartIfForm(payload);
checkArgument(payload != null, "payload was null");
checkArgument(payload.isRepeatable(), "payload must be repeatable: " + payload);
try {
return base64().encode(ByteStreams2.hashAndClose(payload.getInput(), sha1()).asBytes());
} catch (Exception e) {
Throwables.propagateIfPossible(e);
throw new HttpException("error creating sigature for payload: " + payload, e);
}
}
private Payload useTheFilePartIfForm(Payload payload) {
if (payload instanceof MultipartForm) {
Iterable<? extends Part> parts = MultipartForm.class.cast(payload).getRawContent();
try {
payload = Iterables.find(parts, new Predicate<Part>() {
@Override
public boolean apply(Part input) {
return "file".equals(input.getName());
}
});
} catch (NoSuchElementException e) {
}
}
return payload;
}
public String sign(String toSign) {
try {
byte[] encrypted = ByteStreams2.toByteArrayAndClose(new RSAEncryptingPayload(crypto, Payloads.newStringPayload(toSign), supplyKey.get()).openStream());
return base64().encode(encrypted);
} catch (IOException e) {
throw new HttpException("error signing request", e);
}
}
}

View File

@ -0,0 +1,61 @@
/*
* 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.functions;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static org.jclouds.chef.config.ChefProperties.CHEF_BOOTSTRAP_DATABAG;
import java.lang.reflect.Type;
import java.util.Map;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import org.jclouds.chef.ChefApi;
import org.jclouds.chef.domain.DatabagItem;
import org.jclouds.domain.JsonBall;
import com.google.common.base.Function;
import com.google.inject.TypeLiteral;
/**
*
* Retrieves the bootstrap configuration for a specific group
*/
@Singleton
public class BootstrapConfigForGroup implements Function<String, DatabagItem> {
public static final Type BOOTSTRAP_CONFIG_TYPE = new TypeLiteral<Map<String, JsonBall>>() {
}.getType();
private final ChefApi api;
private final String databag;
@Inject
public BootstrapConfigForGroup(@Named(CHEF_BOOTSTRAP_DATABAG) String databag, ChefApi api) {
this.databag = checkNotNull(databag, "databag");
this.api = checkNotNull(api, "api");
}
@Override
public DatabagItem apply(String from) {
DatabagItem bootstrapConfig = api.getDatabagItem(databag, from);
checkState(bootstrapConfig != null, "databag item %s/%s not found", databag, from);
return bootstrapConfig;
}
}

View File

@ -0,0 +1,69 @@
/*
* 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.functions;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.collect.Sets.newHashSet;
import java.util.Set;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.chef.ChefApi;
import org.jclouds.chef.domain.Client;
import com.google.common.base.Function;
/**
*
* Generates a client relevant for a particular group
*/
@Singleton
public class ClientForGroup implements Function<String, Client> {
private final ChefApi chefApi;
@Inject
public ClientForGroup(ChefApi chefApi) {
this.chefApi = checkNotNull(chefApi, "chefApi");
}
@Override
public Client apply(String from) {
String clientName = findNextClientName(chefApi.listClients(), from + "-client-%02d");
Client client = chefApi.createClient(clientName);
// response from create only includes the key
return Client.builder() //
.clientname(clientName) //
.name(clientName) //
.isValidator(false) //
.privateKey(client.getPrivateKey()) //
.build();
}
private static String findNextClientName(Set<String> clients, String pattern) {
String clientName;
Set<String> names = newHashSet(clients);
int index = 0;
while (true) {
clientName = String.format(pattern, index++);
if (!names.contains(clientName))
break;
}
return clientName;
}
}

View File

@ -0,0 +1,130 @@
/*
* 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.functions;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Throwables.propagate;
import static org.jclouds.scriptbuilder.domain.Statements.appendFile;
import static org.jclouds.scriptbuilder.domain.Statements.exec;
import static org.jclouds.scriptbuilder.domain.Statements.newStatementList;
import java.lang.reflect.Type;
import java.net.URI;
import java.security.PrivateKey;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.chef.config.InstallChef;
import org.jclouds.chef.config.Validator;
import org.jclouds.crypto.Pems;
import org.jclouds.domain.JsonBall;
import org.jclouds.json.Json;
import org.jclouds.location.Provider;
import org.jclouds.scriptbuilder.ExitInsteadOfReturn;
import org.jclouds.scriptbuilder.domain.Statement;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.base.Optional;
import com.google.common.base.Splitter;
import com.google.common.base.Supplier;
import com.google.common.cache.CacheLoader;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.inject.TypeLiteral;
/**
*
* Generates a bootstrap script relevant for a particular group
*/
@Singleton
public class GroupToBootScript implements Function<String, Statement> {
private static final Pattern newLinePattern = Pattern.compile("(\\r\\n)|(\\n)");
@VisibleForTesting
static final Type RUN_LIST_TYPE = new TypeLiteral<Map<String, List<String>>>() {
}.getType();
private final Supplier<URI> endpoint;
private final Json json;
private final CacheLoader<String, ? extends JsonBall> bootstrapConfigForGroup;
private final Statement installChef;
private final Optional<String> validatorName;
private final Optional<PrivateKey> validatorCredential;
@Inject
public GroupToBootScript(@Provider Supplier<URI> endpoint, Json json,
CacheLoader<String, ? extends JsonBall> bootstrapConfigForGroup,
@InstallChef Statement installChef, @Validator Optional<String> validatorName,
@Validator Optional<PrivateKey> validatorCredential) {
this.endpoint = checkNotNull(endpoint, "endpoint");
this.json = checkNotNull(json, "json");
this.bootstrapConfigForGroup = checkNotNull(bootstrapConfigForGroup, "bootstrapConfigForGroup");
this.installChef = checkNotNull(installChef, "installChef");
this.validatorName = checkNotNull(validatorName, "validatorName");
this.validatorCredential = checkNotNull(validatorCredential, validatorCredential);
}
@Override
public Statement apply(String group) {
checkNotNull(group, "group");
String validatorClientName = validatorName.get();
PrivateKey validatorKey = validatorCredential.get();
JsonBall bootstrapConfig = null;
try {
bootstrapConfig = bootstrapConfigForGroup.load(group);
} catch (Exception e) {
throw propagate(e);
}
Map<String, JsonBall> config = json.fromJson(bootstrapConfig.toString(),
BootstrapConfigForGroup.BOOTSTRAP_CONFIG_TYPE);
Optional<JsonBall> environment = Optional.fromNullable(config.get("environment"));
String chefConfigDir = "{root}etc{fs}chef";
Statement createChefConfigDir = exec("{md} " + chefConfigDir);
Statement createClientRb = appendFile(chefConfigDir + "{fs}client.rb", ImmutableList.of("require 'rubygems'",
"require 'ohai'", "o = Ohai::System.new", "o.all_plugins",
String.format("node_name \"%s-\" + o[:ipaddress]", group), "log_level :info", "log_location STDOUT",
String.format("validation_client_name \"%s\"", validatorClientName),
String.format("chef_server_url \"%s\"", endpoint.get())));
Statement createValidationPem = appendFile(chefConfigDir + "{fs}validation.pem",
Splitter.on(newLinePattern).split(Pems.pem(validatorKey)));
String chefBootFile = chefConfigDir + "{fs}first-boot.json";
Statement createFirstBoot = appendFile(chefBootFile, Collections.singleton(json.toJson(bootstrapConfig)));
ImmutableMap.Builder<String, String> options = ImmutableMap.builder();
options.put("-j", chefBootFile);
if (environment.isPresent()) {
options.put("-E", environment.get().toString());
}
String strOptions = Joiner.on(' ').withKeyValueSeparator(" ").join(options.build());
Statement runChef = exec("chef-client " + strOptions);
return newStatementList(new ExitInsteadOfReturn(installChef), createChefConfigDir, createClientRb, createValidationPem,
createFirstBoot, runChef);
}
}

View File

@ -0,0 +1,49 @@
/*
* 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.functions;
import java.util.Set;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.chef.config.CookbookParser;
import org.jclouds.http.HttpResponse;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function;
/**
* Parses a cookbook definition from a Json response, taking care of using the
* appropriate parser.
*/
@Singleton
public class ParseCookbookDefinitionCheckingChefVersion implements Function<HttpResponse, Set<String>> {
@VisibleForTesting
final Function<HttpResponse, Set<String>> parser;
@Inject
ParseCookbookDefinitionCheckingChefVersion(@CookbookParser Function<HttpResponse, Set<String>> parser) {
this.parser = parser;
}
@Override
public Set<String> apply(HttpResponse response) {
return parser.apply(response);
}
}

View File

@ -0,0 +1,50 @@
/*
* 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.functions;
import java.util.Map;
import java.util.Set;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.chef.domain.CookbookDefinition;
import org.jclouds.http.HttpResponse;
import org.jclouds.http.functions.ParseJson;
import com.google.common.base.Function;
/**
* Parses a cookbook definition from a Json response, assuming a Chef Server >=
* 0.10.8.
*/
@Singleton
public class ParseCookbookDefinitionFromJson implements Function<HttpResponse, Set<String>> {
/** Parser for responses from chef server >= 0.10.8 */
private final ParseJson<Map<String, CookbookDefinition>> parser;
@Inject
ParseCookbookDefinitionFromJson(ParseJson<Map<String, CookbookDefinition>> parser) {
this.parser = parser;
}
@Override
public Set<String> apply(HttpResponse response) {
return parser.apply(response).keySet();
}
}

View File

@ -0,0 +1,52 @@
/*
* 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.functions;
import com.google.common.base.Function;
import org.jclouds.chef.domain.CookbookDefinition;
import org.jclouds.http.HttpResponse;
import org.jclouds.http.functions.ParseJson;
import javax.inject.Inject;
import javax.inject.Singleton;
import java.util.Map;
/**
* Parses the cookbook versions in a Chef Server >= 0.10.8.
*/
@Singleton
public class ParseCookbookDefinitionFromJsonv10 implements Function<HttpResponse, CookbookDefinition> {
/** Parser for responses from chef server >= 0.10.8 */
private final ParseJson<Map<String, CookbookDefinition>> parser;
@Inject
ParseCookbookDefinitionFromJsonv10(ParseJson<Map<String, CookbookDefinition>> parser) {
this.parser = parser;
}
@Override
public CookbookDefinition apply(HttpResponse response) {
Map<String, CookbookDefinition> result = parser.apply(response);
String cookbookName = result.keySet().iterator().next();
CookbookDefinition def = result.values().iterator().next();
return CookbookDefinition.builder() //
.from(def) //
.name(cookbookName) //
.build();
}
}

View File

@ -0,0 +1,63 @@
/*
* 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.functions;
import com.google.common.base.Function;
import org.jclouds.chef.domain.CookbookDefinition;
import org.jclouds.http.HttpResponse;
import org.jclouds.http.functions.ParseJson;
import javax.inject.Inject;
import javax.inject.Singleton;
import java.util.Map;
import java.util.Set;
import static com.google.common.collect.Iterables.transform;
import static com.google.common.collect.Sets.newLinkedHashSet;
/**
* Parses the cookbook versions in a Chef Server >= 0.10.8.
*/
@Singleton
public class ParseCookbookDefinitionListFromJsonv10 implements Function<HttpResponse, Set<CookbookDefinition>> {
/**
* Parser for responses from chef server >= 0.10.8
*/
private final ParseJson<Map<String, CookbookDefinition>> parser;
@Inject
ParseCookbookDefinitionListFromJsonv10(ParseJson<Map<String, CookbookDefinition>> parser) {
this.parser = parser;
}
@Override
public Set<CookbookDefinition> apply(HttpResponse response) {
Set<Map.Entry<String, CookbookDefinition>> result = parser.apply(response).entrySet();
return newLinkedHashSet(transform(result, new Function<Map.Entry<String, CookbookDefinition>, CookbookDefinition>() {
@Override
public CookbookDefinition apply(Map.Entry<String, CookbookDefinition> input) {
String cookbookName = input.getKey();
CookbookDefinition def = input.getValue();
return CookbookDefinition.builder() //
.from(def) //
.name(cookbookName) //
.build();
}
}));
}
}

View File

@ -0,0 +1,49 @@
/*
* 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.functions;
import java.util.Set;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.chef.config.CookbookVersionsParser;
import org.jclouds.http.HttpResponse;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function;
/**
* Parses a cookbook versions from a Json response, taking care of using the
* appropriate parser.
*/
@Singleton
public class ParseCookbookVersionsCheckingChefVersion implements Function<HttpResponse, Set<String>> {
@VisibleForTesting
final Function<HttpResponse, Set<String>> parser;
@Inject
ParseCookbookVersionsCheckingChefVersion(@CookbookVersionsParser Function<HttpResponse, Set<String>> parser) {
this.parser = parser;
}
@Override
public Set<String> apply(HttpResponse response) {
return parser.apply(response);
}
}

View File

@ -0,0 +1,49 @@
/*
* 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.functions;
import java.util.Map;
import java.util.Set;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.http.HttpResponse;
import org.jclouds.http.functions.ParseJson;
import com.google.common.base.Function;
import static com.google.common.collect.Iterables.getFirst;
/**
* Parses the cookbook versions in a Chef Server <= 0.9.8.
*/
@Singleton
public class ParseCookbookVersionsV09FromJson implements Function<HttpResponse, Set<String>> {
private final ParseJson<Map<String, Set<String>>> json;
@Inject
ParseCookbookVersionsV09FromJson(ParseJson<Map<String, Set<String>>> json) {
this.json = json;
}
@Override
public Set<String> apply(HttpResponse response) {
return getFirst(json.apply(response).values(), null);
}
}

View File

@ -0,0 +1,59 @@
/*
* 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.functions;
import java.util.Map;
import java.util.Set;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.chef.domain.CookbookDefinition;
import org.jclouds.chef.domain.CookbookDefinition.Version;
import org.jclouds.http.HttpResponse;
import org.jclouds.http.functions.ParseJson;
import com.google.common.base.Function;
import static com.google.common.collect.Iterables.getFirst;
import static com.google.common.collect.Iterables.transform;
import static com.google.common.collect.Sets.newLinkedHashSet;
/**
* Parses the cookbook versions in a Chef Server >= 0.10.8.
*/
@Singleton
public class ParseCookbookVersionsV10FromJson implements Function<HttpResponse, Set<String>> {
/** Parser for responses from chef server >= 0.10.8 */
private final ParseJson<Map<String, CookbookDefinition>> parser;
@Inject
ParseCookbookVersionsV10FromJson(ParseJson<Map<String, CookbookDefinition>> parser) {
this.parser = parser;
}
@Override
public Set<String> apply(HttpResponse response) {
CookbookDefinition def = getFirst(parser.apply(response).values(), null);
return newLinkedHashSet(transform(def.getVersions(), new Function<Version, String>() {
@Override
public String apply(Version input) {
return input.getVersion();
}
}));
}
}

View File

@ -0,0 +1,55 @@
/*
* 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.functions;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.http.HttpResponse;
import org.jclouds.http.functions.ReturnStringIf2xx;
import com.google.common.base.Function;
@Singleton
public class ParseErrorFromJsonOrReturnBody implements Function<HttpResponse, String> {
Pattern pattern = Pattern.compile(".*\\[\"([^\"]+)\"\\].*");
private final ReturnStringIf2xx returnStringIf200;
@Inject
ParseErrorFromJsonOrReturnBody(ReturnStringIf2xx returnStringIf200) {
this.returnStringIf200 = returnStringIf200;
}
@Override
public String apply(HttpResponse response) {
String content = returnStringIf200.apply(response);
if (content == null)
return null;
return parse(content);
}
public String parse(String in) {
Matcher matcher = pattern.matcher(in);
if (matcher.find()) {
return matcher.group(1);
}
return in;
}
}

View File

@ -0,0 +1,45 @@
/*
* 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.functions;
import java.util.Map;
import java.util.Set;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.http.HttpResponse;
import org.jclouds.http.functions.ParseJson;
import com.google.common.base.Function;
@Singleton
public class ParseKeySetFromJson implements Function<HttpResponse, Set<String>> {
private final ParseJson<Map<String, String>> json;
@Inject
ParseKeySetFromJson(ParseJson<Map<String, String>> json) {
this.json = json;
}
@Override
public Set<String> apply(HttpResponse response) {
return json.apply(response).keySet();
}
}

View File

@ -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.functions;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.chef.domain.Client;
import org.jclouds.http.functions.ParseJson;
@Singleton
public class ParseSearchClientsFromJson extends ParseSearchResultFromJson<Client> {
// TODO add generic json parser detector
@Inject
ParseSearchClientsFromJson(ParseJson<Response<Client>> json) {
super(json);
}
}

View File

@ -0,0 +1,77 @@
/*
* 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.functions;
import java.util.List;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.chef.domain.DatabagItem;
import org.jclouds.chef.domain.SearchResult;
import org.jclouds.domain.JsonBall;
import org.jclouds.http.HttpResponse;
import org.jclouds.http.functions.ParseJson;
import org.jclouds.json.Json;
import com.google.common.base.Function;
import com.google.gson.annotations.SerializedName;
import static com.google.common.collect.Iterables.transform;
/**
* Parses the search result into a {@link DatabagItem} object.
* <p>
* When searching databags, the items are contained inside the
* <code>raw_data</code> list.
*/
@Singleton
public class ParseSearchDatabagFromJson implements Function<HttpResponse, SearchResult<DatabagItem>> {
private final ParseJson<Response> responseParser;
private final Json json;
static class Row {
@SerializedName("raw_data")
JsonBall rawData;
}
static class Response {
long start;
List<Row> rows;
}
@Inject
ParseSearchDatabagFromJson(ParseJson<Response> responseParser, Json json) {
this.responseParser = responseParser;
this.json = json;
}
@Override
public SearchResult<DatabagItem> apply(HttpResponse response) {
Response returnVal = responseParser.apply(response);
Iterable<DatabagItem> items = transform(returnVal.rows, new Function<Row, DatabagItem>() {
@Override
public DatabagItem apply(Row input) {
return json.fromJson(input.rawData.toString(), DatabagItem.class);
}
});
return new SearchResult<DatabagItem>(returnVal.start, items);
}
}

View File

@ -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.functions;
import org.jclouds.chef.domain.Environment;
import org.jclouds.http.functions.ParseJson;
import javax.inject.Inject;
import javax.inject.Singleton;
@Singleton
public class ParseSearchEnvironmentsFromJson extends ParseSearchResultFromJson<Environment> {
// TODO add generic json parser detector
@Inject
ParseSearchEnvironmentsFromJson(ParseJson<Response<Environment>> json) {
super(json);
}
}

View File

@ -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.functions;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.chef.domain.Node;
import org.jclouds.http.functions.ParseJson;
@Singleton
public class ParseSearchNodesFromJson extends ParseSearchResultFromJson<Node> {
// TODO add generic json parser detector
@Inject
ParseSearchNodesFromJson(ParseJson<Response<Node>> json) {
super(json);
}
}

View File

@ -0,0 +1,50 @@
/*
* 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.functions;
import java.util.List;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.chef.domain.SearchResult;
import org.jclouds.http.HttpResponse;
import org.jclouds.http.functions.ParseJson;
import com.google.common.base.Function;
@Singleton
public class ParseSearchResultFromJson<T> implements Function<HttpResponse, SearchResult<T>> {
private final ParseJson<Response<T>> json;
static class Response<T> {
long start;
List<T> rows;
}
@Inject
ParseSearchResultFromJson(ParseJson<Response<T>> json) {
this.json = json;
}
@Override
public SearchResult<T> apply(HttpResponse response) {
Response<T> returnVal = json.apply(response);
return new SearchResult<T>(returnVal.start, returnVal.rows);
}
}

View File

@ -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.functions;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.chef.domain.Role;
import org.jclouds.http.functions.ParseJson;
@Singleton
public class ParseSearchRolesFromJson extends ParseSearchResultFromJson<Role> {
// TODO add generic json parser detector
@Inject
ParseSearchRolesFromJson(ParseJson<Response<Role>> json) {
super(json);
}
}

View File

@ -0,0 +1,61 @@
/*
* 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.functions;
import static com.google.common.base.Preconditions.checkNotNull;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.chef.domain.DatabagItem;
import org.jclouds.domain.JsonBall;
import org.jclouds.json.Json;
import com.google.common.base.Function;
import com.google.inject.TypeLiteral;
/**
* Retrieves the run-list for a specific group
*/
@Singleton
public class RunListForGroup implements Function<String, List<String>> {
public static final Type RUN_LIST_TYPE = new TypeLiteral<List<String>>() {
}.getType();
private final BootstrapConfigForGroup bootstrapConfigForGroup;
private final Json json;
@Inject
public RunListForGroup(BootstrapConfigForGroup bootstrapConfigForGroup, Json json) {
this.bootstrapConfigForGroup = checkNotNull(bootstrapConfigForGroup, "bootstrapConfigForGroup");
this.json = checkNotNull(json, "json");
}
@Override
public List<String> apply(String from) {
DatabagItem bootstrapConfig = bootstrapConfigForGroup.apply(from);
Map<String, JsonBall> config = json.fromJson(bootstrapConfig.toString(),
BootstrapConfigForGroup.BOOTSTRAP_CONFIG_TYPE);
JsonBall runlist = config.get("run_list");
return json.fromJson(runlist.toString(), RUN_LIST_TYPE);
}
}

View File

@ -0,0 +1,42 @@
/*
* 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.functions;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import java.net.URI;
import javax.inject.Singleton;
import org.jclouds.chef.domain.Resource;
import com.google.common.base.Function;
/**
* Extracts the uri field of the given {@link Resource}.
*/
@Singleton
public class UriForResource implements Function<Object, URI> {
@Override
public URI apply(Object input) {
checkArgument(checkNotNull(input, "input") instanceof Resource,
"This function can only be applied to Resource objects");
return ((Resource) input).getUrl();
}
}

View File

@ -0,0 +1,67 @@
/*
* 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.handlers;
import static org.jclouds.http.HttpUtils.closeClientButKeepContentStream;
import javax.annotation.Resource;
import javax.inject.Named;
import org.jclouds.Constants;
import org.jclouds.http.HttpCommand;
import org.jclouds.http.HttpResponse;
import org.jclouds.http.HttpRetryHandler;
import org.jclouds.http.handlers.BackoffLimitedRetryHandler;
import org.jclouds.logging.Logger;
import com.google.inject.Inject;
/**
* Allow for eventual consistency on sandbox requests.
*/
public class ChefApiErrorRetryHandler implements HttpRetryHandler {
@Inject(optional = true)
@Named(Constants.PROPERTY_MAX_RETRIES)
private int retryCountLimit = 5;
@Resource
protected Logger logger = Logger.NULL;
private final BackoffLimitedRetryHandler backoffLimitedRetryHandler;
@Inject
ChefApiErrorRetryHandler(BackoffLimitedRetryHandler backoffLimitedRetryHandler) {
this.backoffLimitedRetryHandler = backoffLimitedRetryHandler;
}
public boolean shouldRetryRequest(HttpCommand command, HttpResponse response) {
if (command.getFailureCount() > retryCountLimit)
return false;
if (response.getStatusCode() == 400 && command.getCurrentRequest().getMethod().equals("PUT")
&& command.getCurrentRequest().getEndpoint().getPath().indexOf("sandboxes") != -1) {
if (response.getPayload() != null) {
String error = new String(closeClientButKeepContentStream(response));
if (error != null && error.indexOf("was not uploaded") != -1) {
return backoffLimitedRetryHandler.shouldRetryRequest(command, response);
}
}
}
return false;
}
}

View File

@ -0,0 +1,81 @@
/*
* 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.handlers;
import static com.google.common.base.Throwables.propagate;
import java.io.IOException;
import javax.annotation.Resource;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.chef.functions.ParseErrorFromJsonOrReturnBody;
import org.jclouds.http.HttpCommand;
import org.jclouds.http.HttpErrorHandler;
import org.jclouds.http.HttpResponse;
import org.jclouds.http.HttpResponseException;
import org.jclouds.logging.Logger;
import org.jclouds.rest.AuthorizationException;
import org.jclouds.rest.ResourceNotFoundException;
import com.google.common.io.Closeables;
/**
* This will parse and set an appropriate exception on the command object.
*/
@Singleton
public class ChefErrorHandler implements HttpErrorHandler {
@Resource
protected Logger logger = Logger.NULL;
private final ParseErrorFromJsonOrReturnBody errorParser;
@Inject
ChefErrorHandler(ParseErrorFromJsonOrReturnBody errorParser) {
this.errorParser = errorParser;
}
public void handleError(HttpCommand command, HttpResponse response) {
String message = errorParser.apply(response);
Exception exception = new HttpResponseException(command, response, message);
try {
message = message != null ? message : String.format("%s -> %s", command.getCurrentRequest().getRequestLine(),
response.getStatusLine());
switch (response.getStatusCode()) {
case 401:
case 403:
exception = new AuthorizationException(message, exception);
break;
case 404:
if (!command.getCurrentRequest().getMethod().equals("DELETE")) {
exception = new ResourceNotFoundException(message, exception);
}
break;
}
} finally {
if (response.getPayload() != null) {
try {
Closeables.close(response.getPayload().getInput(), true);
} catch (IOException e) {
throw propagate(e);
}
}
command.setException(exception);
}
}
}

View File

@ -0,0 +1,299 @@
/*
* 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.internal;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.jclouds.chef.config.ChefProperties.CHEF_BOOTSTRAP_DATABAG;
import java.io.IOException;
import java.io.InputStream;
import java.security.PrivateKey;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import javax.annotation.Resource;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import org.jclouds.chef.ChefApi;
import org.jclouds.chef.ChefContext;
import org.jclouds.chef.ChefService;
import org.jclouds.chef.config.ChefProperties;
import org.jclouds.chef.domain.BootstrapConfig;
import org.jclouds.chef.domain.Client;
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.functions.BootstrapConfigForGroup;
import org.jclouds.chef.functions.GroupToBootScript;
import org.jclouds.chef.functions.RunListForGroup;
import org.jclouds.chef.strategy.CleanupStaleNodesAndClients;
import org.jclouds.chef.strategy.CreateNodeAndPopulateAutomaticAttributes;
import org.jclouds.chef.strategy.DeleteAllClientsInList;
import org.jclouds.chef.strategy.DeleteAllNodesInList;
import org.jclouds.chef.strategy.ListClients;
import org.jclouds.chef.strategy.ListCookbookVersions;
import org.jclouds.chef.strategy.ListCookbookVersionsInEnvironment;
import org.jclouds.chef.strategy.ListEnvironments;
import org.jclouds.chef.strategy.ListNodes;
import org.jclouds.chef.strategy.ListNodesInEnvironment;
import org.jclouds.chef.strategy.UpdateAutomaticAttributesOnNode;
import org.jclouds.crypto.Crypto;
import org.jclouds.domain.JsonBall;
import org.jclouds.io.ByteStreams2;
import org.jclouds.io.Payloads;
import org.jclouds.io.payloads.RSADecryptingPayload;
import org.jclouds.io.payloads.RSAEncryptingPayload;
import org.jclouds.json.Json;
import org.jclouds.logging.Logger;
import org.jclouds.scriptbuilder.domain.Statement;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Supplier;
import com.google.common.collect.Maps;
import com.google.common.io.InputSupplier;
@Singleton
public class BaseChefService implements ChefService {
private final ChefContext chefContext;
private final ChefApi api;
private final CleanupStaleNodesAndClients cleanupStaleNodesAndClients;
private final CreateNodeAndPopulateAutomaticAttributes createNodeAndPopulateAutomaticAttributes;
private final DeleteAllNodesInList deleteAllNodesInList;
private final ListNodes listNodes;
private final DeleteAllClientsInList deleteAllClientsInList;
private final ListClients listClients;
private final UpdateAutomaticAttributesOnNode updateAutomaticAttributesOnNode;
private final Supplier<PrivateKey> privateKey;
private final GroupToBootScript groupToBootScript;
private final String databag;
private final BootstrapConfigForGroup bootstrapConfigForGroup;
private final RunListForGroup runListForGroup;
private final ListCookbookVersions listCookbookVersions;
private final ListCookbookVersionsInEnvironment listCookbookVersionsInEnvironment;
private final ListEnvironments listEnvironments;
private final ListNodesInEnvironment listNodesInEnvironment;
private final Json json;
private final Crypto crypto;
@Resource
@Named(ChefProperties.CHEF_LOGGER)
protected Logger logger = Logger.NULL;
@Inject
protected BaseChefService(ChefContext chefContext, ChefApi api,
CleanupStaleNodesAndClients cleanupStaleNodesAndClients,
CreateNodeAndPopulateAutomaticAttributes createNodeAndPopulateAutomaticAttributes,
DeleteAllNodesInList deleteAllNodesInList, ListNodes listNodes, DeleteAllClientsInList deleteAllClientsInList,
ListClients listClients, ListCookbookVersions listCookbookVersions,
UpdateAutomaticAttributesOnNode updateAutomaticAttributesOnNode, Supplier<PrivateKey> privateKey,
@Named(CHEF_BOOTSTRAP_DATABAG) String databag, GroupToBootScript groupToBootScript,
BootstrapConfigForGroup bootstrapConfigForGroup, RunListForGroup runListForGroup,
ListEnvironments listEnvironments, ListNodesInEnvironment listNodesInEnvironment,
ListCookbookVersionsInEnvironment listCookbookVersionsInEnvironment, Json json, Crypto crypto) {
this.chefContext = checkNotNull(chefContext, "chefContext");
this.api = checkNotNull(api, "api");
this.cleanupStaleNodesAndClients = checkNotNull(cleanupStaleNodesAndClients, "cleanupStaleNodesAndClients");
this.createNodeAndPopulateAutomaticAttributes = checkNotNull(createNodeAndPopulateAutomaticAttributes,
"createNodeAndPopulateAutomaticAttributes");
this.deleteAllNodesInList = checkNotNull(deleteAllNodesInList, "deleteAllNodesInList");
this.listNodes = checkNotNull(listNodes, "listNodes");
this.deleteAllClientsInList = checkNotNull(deleteAllClientsInList, "deleteAllClientsInList");
this.listClients = checkNotNull(listClients, "listClients");
this.listCookbookVersions = checkNotNull(listCookbookVersions, "listCookbookVersions");
this.updateAutomaticAttributesOnNode = checkNotNull(updateAutomaticAttributesOnNode,
"updateAutomaticAttributesOnNode");
this.privateKey = checkNotNull(privateKey, "privateKey");
this.groupToBootScript = checkNotNull(groupToBootScript, "groupToBootScript");
this.databag = checkNotNull(databag, "databag");
this.bootstrapConfigForGroup = checkNotNull(bootstrapConfigForGroup, "bootstrapConfigForGroup");
this.runListForGroup = checkNotNull(runListForGroup, "runListForGroup");
this.listEnvironments = checkNotNull(listEnvironments, "listEnvironments");
this.listNodesInEnvironment = checkNotNull(listNodesInEnvironment, "listNodesInEnvironment");
this.listCookbookVersionsInEnvironment = checkNotNull(listCookbookVersionsInEnvironment, "listCookbookVersionsInEnvironment");
this.json = checkNotNull(json, "json");
this.crypto = checkNotNull(crypto, "crypto");
}
@Override
public ChefContext getContext() {
return chefContext;
}
@Override
public byte[] encrypt(InputSupplier<? extends InputStream> supplier) throws IOException {
return ByteStreams2.toByteArrayAndClose(new RSAEncryptingPayload(crypto, Payloads.newPayload(supplier.getInput()), privateKey
.get()).openStream());
}
@Override
public byte[] decrypt(InputSupplier<? extends InputStream> supplier) throws IOException {
return ByteStreams2.toByteArrayAndClose(new RSADecryptingPayload(crypto, Payloads.newPayload(supplier.getInput()), privateKey
.get()).openStream());
}
@VisibleForTesting
String buildBootstrapConfiguration(BootstrapConfig bootstrapConfig) {
checkNotNull(bootstrapConfig, "bootstrapConfig must not be null");
Map<String, Object> configMap = Maps.newLinkedHashMap();
configMap.put("run_list", bootstrapConfig.getRunList());
if (bootstrapConfig.getEnvironment().isPresent()) {
configMap.put("environment", bootstrapConfig.getEnvironment().get());
}
if (bootstrapConfig.getAttribtues().isPresent()) {
Map<String, Object> attributes = json.fromJson(bootstrapConfig.getAttribtues().get().toString(),
BootstrapConfigForGroup.BOOTSTRAP_CONFIG_TYPE);
configMap.putAll(attributes);
}
return json.toJson(configMap);
}
@Override
public Statement createBootstrapScriptForGroup(String group) {
return groupToBootScript.apply(group);
}
@Override
public void updateBootstrapConfigForGroup(String group, BootstrapConfig bootstrapConfig) {
try {
api.createDatabag(databag);
} catch (IllegalStateException e) {
}
String jsonConfig = buildBootstrapConfiguration(bootstrapConfig);
DatabagItem runlist = new DatabagItem(group, jsonConfig);
if (api.getDatabagItem(databag, group) == null) {
api.createDatabagItem(databag, runlist);
} else {
api.updateDatabagItem(databag, runlist);
}
}
@Override
public List<String> getRunListForGroup(String group) {
return runListForGroup.apply(group);
}
@Override
public JsonBall getBootstrapConfigForGroup(String group) {
return bootstrapConfigForGroup.apply(group);
}
@Override
public void cleanupStaleNodesAndClients(String prefix, int secondsStale) {
cleanupStaleNodesAndClients.execute(prefix, secondsStale);
}
@Override
public Node createNodeAndPopulateAutomaticAttributes(String nodeName, Iterable<String> runList) {
return createNodeAndPopulateAutomaticAttributes.execute(nodeName, runList);
}
@Override
public void updateAutomaticAttributesOnNode(String nodeName) {
updateAutomaticAttributesOnNode.execute(nodeName);
}
@Override
public void deleteAllNodesInList(Iterable<String> names) {
deleteAllNodesInList.execute(names);
}
@Override
public void deleteAllClientsInList(Iterable<String> names) {
deleteAllClientsInList.execute(names);
}
@Override
public Iterable<? extends Node> listNodes() {
return listNodes.execute();
}
@Override
public Iterable<? extends Node> listNodes(ExecutorService executorService) {
return listNodes.execute(executorService);
}
@Override
public Iterable<? extends Client> listClients() {
return listClients.execute();
}
@Override
public Iterable<? extends Client> listClients(ExecutorService executorService) {
return listClients.execute(executorService);
}
@Override
public Iterable<? extends CookbookVersion> listCookbookVersions() {
return listCookbookVersions.execute();
}
@Override public Iterable<? extends CookbookVersion> listCookbookVersions(
ExecutorService executorService) {
return listCookbookVersions.execute(executorService);
}
@Override
public Iterable<? extends CookbookVersion> listCookbookVersionsInEnvironment(String environmentName) {
return listCookbookVersionsInEnvironment.execute(environmentName);
}
@Override
public Iterable<? extends CookbookVersion> listCookbookVersionsInEnvironment(String environmentName,
ExecutorService executorService) {
return listCookbookVersionsInEnvironment.execute(executorService, environmentName);
}
@Override
public Iterable<? extends CookbookVersion> listCookbookVersionsInEnvironment(String environmentName,
String numVersions) {
return listCookbookVersionsInEnvironment.execute(environmentName, numVersions);
}
@Override
public Iterable<? extends CookbookVersion> listCookbookVersionsInEnvironment(String environmentName,
String numVersions, ExecutorService executorService) {
return listCookbookVersionsInEnvironment.execute(executorService, environmentName, numVersions);
}
@Override
public Iterable<? extends Environment> listEnvironments() {
return listEnvironments.execute();
}
@Override
public Iterable<? extends Node> listNodesInEnvironment(String environmentName) {
return listNodesInEnvironment.execute(environmentName);
}
@Override
public Iterable<? extends Node> listNodesInEnvironment(String environmentName, ExecutorService executorService) {
return listNodesInEnvironment.execute(executorService, environmentName);
}
}

View File

@ -0,0 +1,55 @@
/*
* 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.internal;
import static com.google.common.base.Preconditions.checkNotNull;
import java.io.IOException;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.Context;
import org.jclouds.chef.ChefContext;
import org.jclouds.chef.ChefService;
import org.jclouds.internal.BaseView;
import org.jclouds.location.Provider;
import com.google.common.reflect.TypeToken;
@Singleton
public class ChefContextImpl extends BaseView implements ChefContext {
private final ChefService chefService;
@Inject
protected ChefContextImpl(@Provider Context backend, @Provider TypeToken<? extends Context> backendType,
ChefService chefService) {
super(backend, backendType);
this.chefService = checkNotNull(chefService, "chefService");
}
@Override
public ChefService getChefService() {
return chefService;
}
@Override
public void close() throws IOException {
delegate().close();
}
}

View File

@ -0,0 +1,64 @@
/*
* 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.options;
/**
* Options for the create client method.
*/
public class CreateClientOptions implements Cloneable {
/** Administrator flag. This flag will be ignored in Opscode Hosted Chef. */
private boolean admin;
public CreateClientOptions() {
}
CreateClientOptions(final boolean admin) {
super();
this.admin = admin;
}
public boolean isAdmin() {
return admin;
}
public CreateClientOptions admin() {
this.admin = true;
return this;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return new CreateClientOptions(admin);
}
@Override
public String toString() {
return "[admin=" + admin + "]";
}
public static class Builder {
/**
* @see CreateClientOptions#admin()
*/
public static CreateClientOptions admin() {
CreateClientOptions options = new CreateClientOptions();
return options.admin();
}
}
}

View File

@ -0,0 +1,95 @@
/*
* 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.options;
import static com.google.common.base.Preconditions.checkNotNull;
import org.jclouds.http.options.BaseHttpRequestOptions;
/**
* Options for the search api.
*/
public class SearchOptions extends BaseHttpRequestOptions {
/**
* A valid search string.
*/
public SearchOptions query(String query) {
this.queryParameters.put("q", checkNotNull(query, "query"));
return this;
}
/**
* A sort string, such as 'name DESC'.
*/
public SearchOptions sort(String sort) {
this.queryParameters.put("sort", checkNotNull(sort, "sort"));
return this;
}
/**
* The number of rows to return.
*/
public SearchOptions rows(int rows) {
this.queryParameters.put("rows", String.valueOf(rows));
return this;
}
/**
* The result number to start from.
*/
public SearchOptions start(int start) {
this.queryParameters.put("start", String.valueOf(start));
return this;
}
public static class Builder {
/**
* @see SearchOptions#query(String)
*/
public static SearchOptions query(String query) {
SearchOptions options = new SearchOptions();
return options.query(query);
}
/**
* @see SearchOptions#sort(String)
*/
public static SearchOptions start(String start) {
SearchOptions options = new SearchOptions();
return options.sort(start);
}
/**
* @see SearchOptions#rows(int)
*/
public static SearchOptions rows(int rows) {
SearchOptions options = new SearchOptions();
return options.rows(rows);
}
/**
* @see SearchOptions#start(int)
*/
public static SearchOptions start(int start) {
SearchOptions options = new SearchOptions();
return options.start(start);
}
}
}

View File

@ -0,0 +1,93 @@
/*
* 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.predicates;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.collect.Iterables.any;
import static com.google.common.collect.Iterables.get;
import org.jclouds.chef.domain.CookbookVersion;
import org.jclouds.chef.domain.Resource;
import com.google.common.base.Predicate;
import com.google.common.base.Splitter;
import com.google.common.collect.LinkedListMultimap;
import com.google.common.collect.Multimap;
/**
* Container for cookbook filters (predicates).
*
* This class has static methods that create customized predicates to use with
* {@link org.jclouds.chef.ChefService}.
*/
public class CookbookVersionPredicates {
/**
* @see #containsRecipes
*/
public static Predicate<CookbookVersion> containsRecipe(String recipe) {
return containsRecipes(checkNotNull(recipe, "recipe must be defined"));
}
/**
* Note that the default recipe of a cookbook is its name. Otherwise, you
* prefix the recipe with the name of the cookbook. ex. {@code apache2} will
* be the default recipe where {@code apache2::mod_proxy} is a specific one
* in the cookbook.
*
* @param recipes
* names of the recipes.
* @return true if the cookbook version contains a recipe in the list.
*/
public static Predicate<CookbookVersion> containsRecipes(String... recipes) {
checkNotNull(recipes, "recipes must be defined");
final Multimap<String, String> search = LinkedListMultimap.create();
for (String recipe : recipes) {
if (recipe.indexOf("::") != -1) {
Iterable<String> nameRecipe = Splitter.on("::").split(recipe);
search.put(get(nameRecipe, 0), get(nameRecipe, 1) + ".rb");
} else {
search.put(recipe, "default.rb");
}
}
return new Predicate<CookbookVersion>() {
@Override
public boolean apply(final CookbookVersion cookbookVersion) {
return search.containsKey(cookbookVersion.getCookbookName())
&& any(search.get(cookbookVersion.getCookbookName()), new Predicate<String>() {
@Override
public boolean apply(final String recipeName) {
return any(cookbookVersion.getRecipes(), new Predicate<Resource>() {
@Override
public boolean apply(Resource resource) {
return resource.getName().equals(recipeName);
}
});
}
});
}
@Override
public String toString() {
return "containsRecipes(" + search + ")";
}
};
}
}

View File

@ -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.strategy;
import org.jclouds.chef.strategy.internal.CleanupStaleNodesAndClientsImpl;
import com.google.inject.ImplementedBy;
/**
*
* Cleans up nodes and clients who have been hanging around too long.
*/
@ImplementedBy(CleanupStaleNodesAndClientsImpl.class)
public interface CleanupStaleNodesAndClients {
void execute(String prefix, int secondsStale);
}

View File

@ -0,0 +1,33 @@
/*
* 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.strategy;
import org.jclouds.chef.domain.Node;
import org.jclouds.chef.strategy.internal.CreateNodeAndPopulateAutomaticAttributesImpl;
import com.google.inject.ImplementedBy;
/**
*
* Creates a new node with automatic attributes.
*/
@ImplementedBy(CreateNodeAndPopulateAutomaticAttributesImpl.class)
public interface CreateNodeAndPopulateAutomaticAttributes {
Node execute(Node node);
Node execute(String nodeName, Iterable<String> runList);
}

View File

@ -0,0 +1,34 @@
/*
* 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.strategy;
import org.jclouds.chef.strategy.internal.DeleteAllClientsInListImpl;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.inject.ImplementedBy;
/**
* Deletes all clients in a given list.
*/
@ImplementedBy(DeleteAllClientsInListImpl.class)
public interface DeleteAllClientsInList {
void execute(Iterable<String> names);
void execute(ListeningExecutorService executor, Iterable<String> names);
}

View File

@ -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.strategy;
import org.jclouds.chef.strategy.internal.DeleteAllNodesInListImpl;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.inject.ImplementedBy;
@ImplementedBy(DeleteAllNodesInListImpl.class)
public interface DeleteAllNodesInList {
void execute(Iterable<String> names);
void execute(ListeningExecutorService executor, Iterable<String> names);
}

View File

@ -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.strategy;
import com.google.inject.ImplementedBy;
import org.jclouds.chef.domain.Client;
import org.jclouds.chef.strategy.internal.ListClientsImpl;
import java.util.concurrent.ExecutorService;
@ImplementedBy(ListClientsImpl.class)
public interface ListClients {
Iterable<? extends Client> execute();
Iterable<? extends Client> execute(ExecutorService executor);
}

View File

@ -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.strategy;
import com.google.inject.ImplementedBy;
import org.jclouds.chef.domain.CookbookVersion;
import org.jclouds.chef.strategy.internal.ListCookbookVersionsImpl;
import java.util.concurrent.ExecutorService;
@ImplementedBy(ListCookbookVersionsImpl.class)
public interface ListCookbookVersions {
Iterable<? extends CookbookVersion> execute();
Iterable<? extends CookbookVersion> execute(ExecutorService executor);
}

View File

@ -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.strategy;
import com.google.inject.ImplementedBy;
import org.jclouds.chef.domain.CookbookVersion;
import org.jclouds.chef.strategy.internal.ListCookbookVersionsInEnvironmentImpl;
import java.util.concurrent.ExecutorService;
@ImplementedBy(ListCookbookVersionsInEnvironmentImpl.class)
public interface ListCookbookVersionsInEnvironment {
Iterable<? extends CookbookVersion> execute(String environmentName);
Iterable<? extends CookbookVersion> execute(String environmentName, String numVersions);
Iterable<? extends CookbookVersion> execute(ExecutorService executor, String environmentName);
Iterable<? extends CookbookVersion> execute(ExecutorService executor, String environmentName, String numVersions);
}

View File

@ -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.strategy;
import com.google.inject.ImplementedBy;
import org.jclouds.chef.domain.Environment;
import org.jclouds.chef.strategy.internal.ListEnvironmentsImpl;
import java.util.concurrent.ExecutorService;
@ImplementedBy(ListEnvironmentsImpl.class)
public interface ListEnvironments {
Iterable<? extends Environment> execute();
Iterable<? extends Environment> execute(ExecutorService executor);
}

View File

@ -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.strategy;
import com.google.inject.ImplementedBy;
import org.jclouds.chef.domain.Node;
import org.jclouds.chef.strategy.internal.ListNodesImpl;
import java.util.concurrent.ExecutorService;
@ImplementedBy(ListNodesImpl.class)
public interface ListNodes {
Iterable<? extends Node> execute();
Iterable<? extends Node> execute(ExecutorService executor);
}

View File

@ -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.strategy;
import com.google.inject.ImplementedBy;
import org.jclouds.chef.domain.Node;
import org.jclouds.chef.strategy.internal.ListNodesInEnvironmentImpl;
import java.util.concurrent.ExecutorService;
@ImplementedBy(ListNodesInEnvironmentImpl.class)
public interface ListNodesInEnvironment {
Iterable<? extends Node> execute(String environmentName);
Iterable<? extends Node> execute(ExecutorService executor, String environmentName);
}

View File

@ -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.strategy;
import org.jclouds.chef.strategy.internal.UpdateAutomaticAttributesOnNodeImpl;
import com.google.inject.ImplementedBy;
/**
*
* Updates node with new automatic attributes.
*/
@ImplementedBy(UpdateAutomaticAttributesOnNodeImpl.class)
public interface UpdateAutomaticAttributesOnNode {
void execute(String nodeName);
}

View File

@ -0,0 +1,97 @@
/*
* 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.strategy.internal;
import com.google.common.base.Function;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListeningExecutorService;
import org.jclouds.chef.ChefApi;
import org.jclouds.chef.domain.CookbookVersion;
import org.jclouds.logging.Logger;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Callable;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.collect.Iterables.concat;
import static com.google.common.collect.Iterables.transform;
import static com.google.common.util.concurrent.Futures.allAsList;
import static com.google.common.util.concurrent.Futures.getUnchecked;
public abstract class BaseListCookbookVersionsImpl {
protected final ChefApi api;
protected Logger logger = Logger.NULL;
BaseListCookbookVersionsImpl(ChefApi api) {
this.api = checkNotNull(api, "api");
}
protected Iterable<? extends CookbookVersion> execute(Iterable<String> toGet) {
return concat(transform(toGet, new Function<String, Iterable<? extends CookbookVersion>>() {
@Override
public Iterable<? extends CookbookVersion> apply(final String cookbook) {
// TODO getting each version could also go parallel
Set<String> cookbookVersions = api.listVersionsOfCookbook(cookbook);
Iterable<? extends CookbookVersion> cookbooksVersions = transform(cookbookVersions,
new Function<String, CookbookVersion>() {
@Override
public CookbookVersion apply(final String version) {
return api.getCookbook(cookbook, version);
}
}
);
logger.trace(String.format("getting versions of cookbook: %s", cookbook));
return cookbooksVersions;
}
}));
}
protected Iterable<? extends CookbookVersion> executeConcurrently(final ListeningExecutorService executor,
Iterable<String> cookbookNames) {
return concat(transform(cookbookNames, new Function<String, Iterable<? extends CookbookVersion>>() {
@Override
public Iterable<? extends CookbookVersion> apply(final String cookbook) {
// TODO getting each version could also go parallel
Set<String> cookbookVersions = api.listVersionsOfCookbook(cookbook);
ListenableFuture<List<CookbookVersion>> futures = allAsList(transform(cookbookVersions,
new Function<String, ListenableFuture<CookbookVersion>>() {
@Override
public ListenableFuture<CookbookVersion> apply(final String version) {
return executor.submit(new Callable<CookbookVersion>() {
@Override
public CookbookVersion call() throws Exception {
return api.getCookbook(cookbook, version);
}
});
}
}
));
logger.trace(String.format("getting versions of cookbook: %s", cookbook));
return getUnchecked(futures);
}
}));
}
}

View File

@ -0,0 +1,77 @@
/*
* 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.strategy.internal;
import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListeningExecutorService;
import org.jclouds.chef.ChefApi;
import org.jclouds.chef.domain.Node;
import org.jclouds.logging.Logger;
import java.util.List;
import java.util.concurrent.Callable;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.collect.Iterables.transform;
import static com.google.common.util.concurrent.Futures.allAsList;
import static com.google.common.util.concurrent.Futures.getUnchecked;
public abstract class BaseListNodesImpl {
protected final ChefApi api;
protected Logger logger = Logger.NULL;
BaseListNodesImpl(ChefApi api) {
this.api = checkNotNull(api, "api");
}
protected Iterable<? extends Node> execute(Iterable<String> toGet) {
Iterable<? extends Node> nodes = transform(toGet, new Function<String, Node>() {
@Override
public Node apply(final String input) {
return api.getNode(input);
}
}
);
logger.trace(String.format("getting nodes: %s", Joiner.on(',').join(toGet)));
return nodes;
}
protected Iterable<? extends Node> executeConcurrently(final ListeningExecutorService executor,
Iterable<String> toGet) {
ListenableFuture<List<Node>> futures = allAsList(transform(toGet, new Function<String, ListenableFuture<Node>>() {
@Override
public ListenableFuture<Node> apply(final String input) {
return executor.submit(new Callable<Node>() {
@Override
public Node call() throws Exception {
return api.getNode(input);
}
});
}
}));
logger.trace(String.format("getting nodes: %s", Joiner.on(',').join(toGet)));
return getUnchecked(futures);
}
}

View File

@ -0,0 +1,102 @@
/*
* 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.strategy.internal;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Predicates.and;
import static com.google.common.base.Predicates.notNull;
import static com.google.common.collect.Iterables.filter;
import static com.google.common.collect.Iterables.transform;
import static org.jclouds.chef.util.ChefUtils.fromOhaiTime;
import java.util.Calendar;
import java.util.Date;
import javax.annotation.Resource;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import org.jclouds.chef.config.ChefProperties;
import org.jclouds.chef.domain.Node;
import org.jclouds.chef.strategy.CleanupStaleNodesAndClients;
import org.jclouds.chef.strategy.DeleteAllClientsInList;
import org.jclouds.chef.strategy.DeleteAllNodesInList;
import org.jclouds.chef.strategy.ListNodes;
import org.jclouds.domain.JsonBall;
import org.jclouds.logging.Logger;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
/**
*
* Cleans up nodes and apis who have been hanging around too long.
*/
@Singleton
public class CleanupStaleNodesAndClientsImpl implements CleanupStaleNodesAndClients {
@Resource
@Named(ChefProperties.CHEF_LOGGER)
protected Logger logger = Logger.NULL;
private final ListNodes nodeLister;
private final DeleteAllNodesInList nodeDeleter;
private final DeleteAllClientsInList clientDeleter;
@Inject
public CleanupStaleNodesAndClientsImpl(DeleteAllNodesInList nodeDeleter, DeleteAllClientsInList clientDeleter,
ListNodes nodeLister) {
this.nodeLister = checkNotNull(nodeLister, "nodeLister");
this.nodeDeleter = checkNotNull(nodeDeleter, "nodeDeleter");
this.clientDeleter = checkNotNull(clientDeleter, "clientDeleter");
}
@Override
public void execute(final String prefix, int secondsStale) {
final Calendar expired = Calendar.getInstance();
expired.setTime(new Date());
expired.add(Calendar.SECOND, -secondsStale);
Iterable<? extends Node> staleNodes = filter(
nodeLister.execute(), and(notNull(), new Predicate<Node>() {
@Override
public boolean apply(Node input) {
return input.getName().startsWith(prefix);
}
},
new Predicate<Node>() {
@Override
public boolean apply(Node input) {
JsonBall dateLong = input.getAutomaticAttributes().get("ohai_time");
if (dateLong == null)
return true;
Calendar nodeUpdate = Calendar.getInstance();
nodeUpdate.setTime(fromOhaiTime(dateLong));
return expired.after(nodeUpdate);
}
}));
Iterable<String> nodeNames = transform(staleNodes, new Function<Node, String>() {
@Override
public String apply(Node from) {
return from.getName();
}
});
nodeDeleter.execute(nodeNames);
clientDeleter.execute(nodeNames);
}
}

View File

@ -0,0 +1,83 @@
/*
* 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.strategy.internal;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Map;
import javax.annotation.Resource;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import org.jclouds.chef.ChefApi;
import org.jclouds.chef.config.ChefProperties;
import org.jclouds.chef.domain.Node;
import org.jclouds.chef.strategy.CreateNodeAndPopulateAutomaticAttributes;
import org.jclouds.domain.JsonBall;
import org.jclouds.logging.Logger;
import org.jclouds.ohai.Automatic;
import com.google.common.base.Supplier;
/**
*
* Updates node with new automatic attributes.
*/
@Singleton
public class CreateNodeAndPopulateAutomaticAttributesImpl implements CreateNodeAndPopulateAutomaticAttributes {
@Resource
@Named(ChefProperties.CHEF_LOGGER)
protected Logger logger = Logger.NULL;
private final ChefApi chef;
private final Supplier<Map<String, JsonBall>> automaticSupplier;
@Inject
public CreateNodeAndPopulateAutomaticAttributesImpl(ChefApi chef,
@Automatic Supplier<Map<String, JsonBall>> automaticSupplier) {
this.chef = checkNotNull(chef, "chef");
this.automaticSupplier = checkNotNull(automaticSupplier, "automaticSupplier");
}
@Override
public Node execute(Node node) {
logger.trace("creating node %s", node.getName());
Node withAutomatic = Node.builder() //
.name(node.getName()) //
.normalAttributes(node.getNormalAttributes()) //
.overrideAttributes(node.getOverrideAttributes()) //
.defaultAttributes(node.getDefaultAttributes()) //
.automaticAttributes(node.getAutomaticAttributes()) //
.automaticAttributes(automaticSupplier.get()) //
.runList(node.getRunList()) //
.environment(node.getEnvironment()) //
.build();
chef.createNode(withAutomatic);
logger.debug("created node %s", withAutomatic.getName());
return node;
}
@Override
public Node execute(String nodeName, Iterable<String> runList) {
return execute(Node.builder().name(nodeName).runList(runList).environment("_default").build());
}
}

View File

@ -0,0 +1,85 @@
/*
* 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.strategy.internal;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.collect.Iterables.transform;
import static com.google.common.util.concurrent.Futures.allAsList;
import static com.google.common.util.concurrent.Futures.getUnchecked;
import java.util.List;
import java.util.concurrent.Callable;
import javax.annotation.Resource;
import javax.inject.Named;
import javax.inject.Singleton;
import org.jclouds.Constants;
import org.jclouds.chef.ChefApi;
import org.jclouds.chef.config.ChefProperties;
import org.jclouds.chef.domain.Client;
import org.jclouds.chef.strategy.DeleteAllClientsInList;
import org.jclouds.logging.Logger;
import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.inject.Inject;
/**
* Concurrently delete all given clients.
*/
@Singleton
public class DeleteAllClientsInListImpl implements DeleteAllClientsInList {
protected final ChefApi api;
protected final ListeningExecutorService userExecutor;
@Resource
@Named(ChefProperties.CHEF_LOGGER)
protected Logger logger = Logger.NULL;
@Inject
DeleteAllClientsInListImpl(@Named(Constants.PROPERTY_USER_THREADS) ListeningExecutorService userExecutor, ChefApi api) {
this.userExecutor = checkNotNull(userExecutor, "userExecuor");
this.api = checkNotNull(api, "api");
}
@Override
public void execute(Iterable<String> names) {
execute(userExecutor, names);
}
@Override
public void execute(final ListeningExecutorService executor, Iterable<String> names) {
ListenableFuture<List<Client>> futures = allAsList(transform(names,
new Function<String, ListenableFuture<Client>>() {
@Override
public ListenableFuture<Client> apply(final String input) {
return executor.submit(new Callable<Client>() {
@Override
public Client call() throws Exception {
return api.deleteClient(input);
}
});
}
}));
logger.trace(String.format("deleting clients: %s", Joiner.on(',').join(names)));
getUnchecked(futures);
}
}

View File

@ -0,0 +1,81 @@
/*
* 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.strategy.internal;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.collect.Iterables.transform;
import static com.google.common.util.concurrent.Futures.allAsList;
import static com.google.common.util.concurrent.Futures.getUnchecked;
import java.util.List;
import java.util.concurrent.Callable;
import javax.annotation.Resource;
import javax.inject.Named;
import javax.inject.Singleton;
import org.jclouds.Constants;
import org.jclouds.chef.ChefApi;
import org.jclouds.chef.config.ChefProperties;
import org.jclouds.chef.domain.Node;
import org.jclouds.chef.strategy.DeleteAllNodesInList;
import org.jclouds.logging.Logger;
import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.inject.Inject;
@Singleton
public class DeleteAllNodesInListImpl implements DeleteAllNodesInList {
protected final ChefApi api;
protected final ListeningExecutorService userExecutor;
@Resource
@Named(ChefProperties.CHEF_LOGGER)
protected Logger logger = Logger.NULL;
@Inject
DeleteAllNodesInListImpl(@Named(Constants.PROPERTY_USER_THREADS) ListeningExecutorService userExecutor, ChefApi api) {
this.userExecutor = checkNotNull(userExecutor, "userExecuor");
this.api = checkNotNull(api, "api");
}
@Override
public void execute(Iterable<String> names) {
execute(userExecutor, names);
}
@Override
public void execute(final ListeningExecutorService executor, Iterable<String> names) {
ListenableFuture<List<Node>> futures = allAsList(transform(names, new Function<String, ListenableFuture<Node>>() {
@Override
public ListenableFuture<Node> apply(final String input) {
return executor.submit(new Callable<Node>() {
@Override
public Node call() throws Exception {
return api.deleteNode(input);
}
});
}
}));
logger.trace(String.format("deleting nodes: %s", Joiner.on(',').join(names)));
getUnchecked(futures);
}
}

View File

@ -0,0 +1,109 @@
/*
* 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.strategy.internal;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.collect.Iterables.transform;
import static com.google.common.util.concurrent.Futures.allAsList;
import static com.google.common.util.concurrent.Futures.getUnchecked;
import java.util.List;
import java.util.concurrent.Callable;
import javax.annotation.Resource;
import javax.inject.Named;
import javax.inject.Singleton;
import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.common.util.concurrent.MoreExecutors;
import com.google.inject.Inject;
import org.jclouds.chef.ChefApi;
import org.jclouds.chef.config.ChefProperties;
import org.jclouds.chef.domain.Client;
import org.jclouds.chef.strategy.ListClients;
import org.jclouds.logging.Logger;
import java.util.concurrent.ExecutorService;
@Singleton
public class ListClientsImpl implements ListClients {
protected final ChefApi api;
@Resource
@Named(ChefProperties.CHEF_LOGGER)
protected Logger logger = Logger.NULL;
@Inject
ListClientsImpl(ChefApi api) {
this.api = checkNotNull(api, "api");
}
@Override
public Iterable<? extends Client> execute() {
Iterable<String> toGet = api.listClients();
Iterable<? extends Client> clients = transform(toGet,
new Function<String, Client>() {
@Override
public Client apply(final String input) {
return api.getClient(input);
}
}
);
logger.trace(String.format("getting clients: %s", Joiner.on(',').join(toGet)));
return clients;
}
@Override
public Iterable<? extends Client> execute(ExecutorService executorService) {
return this.execute(MoreExecutors.listeningDecorator(executorService));
}
private Iterable<? extends Client> execute(ListeningExecutorService listeningExecutor) {
return executeConcurrently(listeningExecutor, api.listClients());
}
private Iterable<? extends Client> executeConcurrently(final ListeningExecutorService executor,
Iterable<String> toGet) {
ListenableFuture<List<Client>> futures = allAsList(transform(toGet,
new Function<String, ListenableFuture<Client>>() {
@Override
public ListenableFuture<Client> apply(final String input) {
return executor.submit(new Callable<Client>() {
@Override
public Client call() throws Exception {
return api.getClient(input);
}
});
}
}
));
logger.trace(String.format("getting clients: %s", Joiner.on(',').join(toGet)));
return getUnchecked(futures);
}
}

View File

@ -0,0 +1,60 @@
/*
* 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.strategy.internal;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.common.util.concurrent.MoreExecutors;
import com.google.inject.Inject;
import org.jclouds.chef.ChefApi;
import org.jclouds.chef.config.ChefProperties;
import org.jclouds.chef.domain.CookbookVersion;
import org.jclouds.chef.strategy.ListCookbookVersions;
import org.jclouds.logging.Logger;
import javax.annotation.Resource;
import javax.inject.Named;
import javax.inject.Singleton;
import java.util.concurrent.ExecutorService;
@Singleton
public class ListCookbookVersionsImpl extends BaseListCookbookVersionsImpl implements ListCookbookVersions {
@Resource
@Named(ChefProperties.CHEF_LOGGER)
protected Logger logger = Logger.NULL;
@Inject
ListCookbookVersionsImpl(ChefApi api) {
super(api);
}
@Override
public Iterable<? extends CookbookVersion> execute() {
return super.execute(api.listCookbooks());
}
@Override
public Iterable<? extends CookbookVersion> execute(ExecutorService executor) {
return this.executeConcurrently(MoreExecutors.listeningDecorator(executor));
}
private Iterable<? extends CookbookVersion> executeConcurrently(ListeningExecutorService executor) {
return super.executeConcurrently(executor, api.listCookbooks());
}
}

View File

@ -0,0 +1,117 @@
/*
* 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.strategy.internal;
import static com.google.common.collect.Iterables.transform;
import javax.annotation.Resource;
import javax.inject.Named;
import javax.inject.Singleton;
import com.google.common.base.Function;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.common.util.concurrent.MoreExecutors;
import com.google.inject.Inject;
import org.jclouds.chef.ChefApi;
import org.jclouds.chef.config.ChefProperties;
import org.jclouds.chef.domain.CookbookDefinition;
import org.jclouds.chef.domain.CookbookVersion;
import org.jclouds.chef.strategy.ListCookbookVersionsInEnvironment;
import org.jclouds.logging.Logger;
import java.util.concurrent.ExecutorService;
@Singleton
public class ListCookbookVersionsInEnvironmentImpl extends BaseListCookbookVersionsImpl
implements ListCookbookVersionsInEnvironment {
@Resource
@Named(ChefProperties.CHEF_LOGGER)
protected Logger logger = Logger.NULL;
@Inject
ListCookbookVersionsInEnvironmentImpl(ChefApi api) {
super(api);
}
@Override
public Iterable<? extends CookbookVersion> execute(String environmentName) {
return super.execute(transform(api.listCookbooksInEnvironment(environmentName),
new Function<CookbookDefinition, String>() {
@Override
public String apply(CookbookDefinition cookbookDefinition) {
return cookbookDefinition.getName();
}
}
));
}
@Override
public Iterable<? extends CookbookVersion> execute(String environmentName, String numVersions) {
return super.execute(transform(api.listCookbooksInEnvironment(environmentName, numVersions),
new Function<CookbookDefinition, String>() {
@Override
public String apply(CookbookDefinition cookbookDefinition) {
return cookbookDefinition.getName();
}
}
));
}
@Override
public Iterable<? extends CookbookVersion> execute(ExecutorService executor,
String environmentName) {
return this.executeConcurrently(MoreExecutors.listeningDecorator(executor), environmentName);
}
@Override
public Iterable<? extends CookbookVersion> execute(ExecutorService executor,
String environmentName, String numVersions) {
return this.executeConcurrently(MoreExecutors.listeningDecorator(executor), environmentName, numVersions);
}
private Iterable<? extends CookbookVersion> executeConcurrently(ListeningExecutorService executor,
String environmentName) {
return super.execute(
transform(api.listCookbooksInEnvironment(environmentName), new Function<CookbookDefinition, String>() {
@Override
public String apply(CookbookDefinition cookbookDefinition) {
return cookbookDefinition.getName();
}
})
);
}
private Iterable<? extends CookbookVersion> executeConcurrently(ListeningExecutorService executor,
String environmentName, String numVersions) {
return super.execute(transform(api.listCookbooksInEnvironment(environmentName, numVersions),
new Function<CookbookDefinition, String>() {
@Override
public String apply(CookbookDefinition cookbookDefinition) {
return cookbookDefinition.getName();
}
}
));
}
}

View File

@ -0,0 +1,96 @@
/*
* 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.strategy.internal;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.collect.Iterables.transform;
import static com.google.common.util.concurrent.Futures.allAsList;
import static com.google.common.util.concurrent.Futures.getUnchecked;
import java.util.List;
import java.util.concurrent.Callable;
import javax.annotation.Resource;
import javax.inject.Named;
import javax.inject.Singleton;
import org.jclouds.Constants;
import org.jclouds.chef.ChefApi;
import org.jclouds.chef.config.ChefProperties;
import org.jclouds.chef.domain.Environment;
import org.jclouds.chef.strategy.ListEnvironments;
import org.jclouds.logging.Logger;
import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.inject.Inject;
import com.google.common.util.concurrent.MoreExecutors;
import java.util.concurrent.ExecutorService;
@Singleton
public class ListEnvironmentsImpl implements ListEnvironments {
protected final ChefApi api;
protected final ListeningExecutorService userExecutor;
@Resource
@Named(ChefProperties.CHEF_LOGGER)
protected Logger logger = Logger.NULL;
@Inject
ListEnvironmentsImpl(@Named(Constants.PROPERTY_USER_THREADS) ListeningExecutorService userExecutor, ChefApi api) {
this.userExecutor = checkNotNull(userExecutor, "userExecuor");
this.api = checkNotNull(api, "api");
}
@Override
public Iterable<? extends Environment> execute() {
return execute(userExecutor);
}
@Override
public Iterable<? extends Environment> execute(ExecutorService executor) {
return this.execute(MoreExecutors.listeningDecorator(executor));
}
private Iterable<? extends Environment> execute(ListeningExecutorService executor) {
return execute(executor, api.listEnvironments());
}
private Iterable<? extends Environment> execute(final ListeningExecutorService executor, Iterable<String> toGet) {
ListenableFuture<List<Environment>> futures = allAsList(transform(toGet,
new Function<String, ListenableFuture<Environment>>() {
@Override
public ListenableFuture<Environment> apply(final String input) {
return executor.submit(new Callable<Environment>() {
@Override
public Environment call() throws Exception {
return api.getEnvironment(input);
}
});
}
}));
logger.trace(String.format("deleting environments: %s", Joiner.on(',').join(toGet)));
return getUnchecked(futures);
}
}

View File

@ -0,0 +1,62 @@
/*
* 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.strategy.internal;
import javax.annotation.Resource;
import javax.inject.Named;
import javax.inject.Singleton;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.common.util.concurrent.MoreExecutors;
import com.google.inject.Inject;
import org.jclouds.chef.ChefApi;
import org.jclouds.chef.config.ChefProperties;
import org.jclouds.chef.domain.Node;
import org.jclouds.chef.strategy.ListNodes;
import org.jclouds.logging.Logger;
import java.util.concurrent.ExecutorService;
@Singleton
public class ListNodesImpl extends BaseListNodesImpl implements ListNodes {
@Resource
@Named(ChefProperties.CHEF_LOGGER)
protected Logger logger = Logger.NULL;
@Inject
ListNodesImpl(ChefApi api) {
super(api);
}
@Override
public Iterable<? extends Node> execute() {
return super.execute(api.listNodes());
}
@Override
public Iterable<? extends Node> execute(ExecutorService executor) {
return this.executeConcurrently(MoreExecutors.listeningDecorator(executor));
}
private Iterable<? extends Node> executeConcurrently(ListeningExecutorService executor) {
return super.executeConcurrently(executor, api.listNodes());
}
}

View File

@ -0,0 +1,62 @@
/*
* 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.strategy.internal;
import javax.annotation.Resource;
import javax.inject.Named;
import javax.inject.Singleton;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.common.util.concurrent.MoreExecutors;
import com.google.inject.Inject;
import org.jclouds.chef.ChefApi;
import org.jclouds.chef.config.ChefProperties;
import org.jclouds.chef.domain.Node;
import org.jclouds.chef.strategy.ListNodesInEnvironment;
import org.jclouds.logging.Logger;
import java.util.concurrent.ExecutorService;
@Singleton
public class ListNodesInEnvironmentImpl extends BaseListNodesImpl implements ListNodesInEnvironment {
@Resource
@Named(ChefProperties.CHEF_LOGGER)
protected Logger logger = Logger.NULL;
@Inject
ListNodesInEnvironmentImpl(ChefApi api) {
super(api);
}
@Override
public Iterable<? extends Node> execute(String environmentName) {
return super.execute(api.listNodesInEnvironment(environmentName));
}
@Override
public Iterable<? extends Node> execute(ExecutorService executor, String environmentName) {
return this.executeConcurrently(MoreExecutors.listeningDecorator(executor), environmentName);
}
private Iterable<? extends Node> executeConcurrently(ListeningExecutorService executor,
String environmentName) {
return super.executeConcurrently(executor, api.listNodesInEnvironment(environmentName));
}
}

View File

@ -0,0 +1,75 @@
/*
* 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.strategy.internal;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Map;
import javax.annotation.Resource;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import org.jclouds.chef.ChefApi;
import org.jclouds.chef.config.ChefProperties;
import org.jclouds.chef.domain.Node;
import org.jclouds.chef.strategy.UpdateAutomaticAttributesOnNode;
import org.jclouds.domain.JsonBall;
import org.jclouds.logging.Logger;
import org.jclouds.ohai.Automatic;
import com.google.common.base.Supplier;
/**
*
* Updates node with new automatic attributes.
*/
@Singleton
public class UpdateAutomaticAttributesOnNodeImpl implements UpdateAutomaticAttributesOnNode {
@Resource
@Named(ChefProperties.CHEF_LOGGER)
protected Logger logger = Logger.NULL;
private final ChefApi chef;
private final Supplier<Map<String, JsonBall>> automaticSupplier;
@Inject
public UpdateAutomaticAttributesOnNodeImpl(ChefApi chef, @Automatic Supplier<Map<String, JsonBall>> automaticSupplier) {
this.chef = checkNotNull(chef, "chef");
this.automaticSupplier = checkNotNull(automaticSupplier, "automaticSupplier");
}
@Override
public void execute(String nodeName) {
logger.trace("updating node %s", nodeName);
Node node = chef.getNode(nodeName);
Node updated = Node.builder() //
.name(node.getName()) //
.normalAttributes(node.getNormalAttributes()) //
.overrideAttributes(node.getOverrideAttributes()) //
.defaultAttributes(node.getDefaultAttributes()) //
.automaticAttributes(automaticSupplier.get()) //
.runList(node.getRunList()) //
.environment(node.getEnvironment()) //
.build();
chef.updateNode(updated);
logger.debug("updated node %s", nodeName);
}
}

View File

@ -0,0 +1,73 @@
/*
* 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.suppliers;
import static com.google.common.base.Objects.firstNonNull;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.annotation.Resource;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import org.jclouds.chef.config.ChefProperties;
import org.jclouds.logging.Logger;
import org.jclouds.rest.annotations.ApiVersion;
import com.google.common.base.Supplier;
/**
* Properly supply the version of the Chef Server.
*/
@Singleton
public class ChefVersionSupplier implements Supplier<Integer> {
/** The default version to assume in case we can not parse it. */
public static final Integer FALLBACK_VERSION = 10;
@Resource
@Named(ChefProperties.CHEF_LOGGER)
private Logger logger = Logger.NULL;
/** The configured version of the Chef Server API. */
private final String apiVersion;
@Inject
ChefVersionSupplier(@ApiVersion String apiVersion) {
this.apiVersion = checkNotNull(apiVersion, "apiVersion must not be null");
}
@Override
public Integer get() {
// Old versions of Chef have versions like 0.9.x, 0.10.x, but newer
// versions are in the format 10.x.y, 11.x.y
Pattern versionPattern = Pattern.compile("(?:0\\.(\\d+)|(\\d+)\\.\\d+)(?:\\.\\d)*");
Matcher m = versionPattern.matcher(apiVersion);
if (!m.matches()) {
logger.warn("Configured version does not match the standard version pattern. Assuming version %s",
FALLBACK_VERSION);
return FALLBACK_VERSION;
}
return Integer.valueOf(firstNonNull(m.group(1), m.group(2)));
}
}

View File

@ -0,0 +1,387 @@
/*
* 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.test;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Throwables.propagate;
import static com.google.common.collect.Iterables.transform;
import static com.google.common.collect.Sets.newLinkedHashSet;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.util.List;
import java.util.Set;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import org.jclouds.blobstore.config.LocalBlobStore;
import org.jclouds.blobstore.domain.Blob;
import org.jclouds.blobstore.domain.PageSet;
import org.jclouds.blobstore.domain.StorageMetadata;
import org.jclouds.chef.ChefApi;
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.options.CreateClientOptions;
import org.jclouds.chef.options.SearchOptions;
import org.jclouds.io.Payload;
import org.jclouds.lifecycle.Closer;
import org.jclouds.util.Strings2;
import com.google.common.base.Function;
/**
* In-memory chef simulator.
*/
public class TransientChefApi implements ChefApi {
@Singleton
private static class StorageMetadataToName implements Function<PageSet<? extends StorageMetadata>, Set<String>> {
@Override
public Set<String> apply(PageSet<? extends StorageMetadata> from) {
return newLinkedHashSet(transform(from, new Function<StorageMetadata, String>() {
@Override
public String apply(StorageMetadata from) {
return from.getName();
}
}));
}
}
@Singleton
private static class BlobToDatabagItem implements Function<Blob, DatabagItem> {
@Override
public DatabagItem apply(Blob from) {
try {
return from == null ? null : new DatabagItem(from.getMetadata().getName(), Strings2.toStringAndClose(from
.getPayload().getInput()));
} catch (IOException e) {
propagate(e);
return null;
}
}
}
private final LocalBlobStore databags;
private final BlobToDatabagItem blobToDatabagItem;
private final StorageMetadataToName storageMetadataToName;
private final Closer closer;
@Inject
TransientChefApi(@Named("databags") LocalBlobStore databags, StorageMetadataToName storageMetadataToName,
BlobToDatabagItem blobToDatabagItem, Closer closer) {
this.databags = checkNotNull(databags, "databags");
this.storageMetadataToName = checkNotNull(storageMetadataToName, "storageMetadataToName");
this.blobToDatabagItem = checkNotNull(blobToDatabagItem, "blobToDatabagItem");
this.closer = checkNotNull(closer, "closer");
}
@Override
public Sandbox commitSandbox(String id, boolean isCompleted) {
throw new UnsupportedOperationException();
}
@Override
public Client createClient(String clientName) {
throw new UnsupportedOperationException();
}
@Override
public Client createClient(String clientName, CreateClientOptions options) {
throw new UnsupportedOperationException();
}
@Override
public void createDatabag(String databagName) {
databags.createContainerInLocation(null, databagName);
}
@Override
public DatabagItem createDatabagItem(String databagName, DatabagItem databagItem) {
Blob blob = databags.blobBuilder(databagItem.getId()).payload(databagItem.toString()).build();
databags.putBlob(databagName, blob);
return databagItem;
}
@Override
public void createNode(Node node) {
throw new UnsupportedOperationException();
}
@Override
public void createRole(Role role) {
throw new UnsupportedOperationException();
}
@Override
public Client deleteClient(String clientName) {
throw new UnsupportedOperationException();
}
@Override
public CookbookVersion deleteCookbook(String cookbookName, String version) {
throw new UnsupportedOperationException();
}
@Override
public void deleteDatabag(String databagName) {
databags.deleteContainer(databagName);
}
@Override
public DatabagItem deleteDatabagItem(String databagName, String databagItemId) {
DatabagItem item = blobToDatabagItem.apply(databags.getBlob(databagName, databagItemId));
databags.removeBlob(databagName, databagItemId);
return item;
}
@Override
public Node deleteNode(String nodeName) {
throw new UnsupportedOperationException();
}
@Override
public Role deleteRole(String rolename) {
throw new UnsupportedOperationException();
}
@Override
public Client generateKeyForClient(String clientName) {
throw new UnsupportedOperationException();
}
@Override
public Client getClient(String clientName) {
throw new UnsupportedOperationException();
}
@Override
public CookbookVersion getCookbook(String cookbookName, String version) {
throw new UnsupportedOperationException();
}
@Override
public DatabagItem getDatabagItem(String databagName, String databagItemId) {
return blobToDatabagItem.apply(databags.getBlob(databagName, databagItemId));
}
@Override
public Node getNode(String nodeName) {
throw new UnsupportedOperationException();
}
@Override
public Role getRole(String roleName) {
throw new UnsupportedOperationException();
}
@Override
public UploadSandbox createUploadSandboxForChecksums(Set<List<Byte>> md5s) {
throw new UnsupportedOperationException();
}
@Override
public Set<String> listVersionsOfCookbook(String cookbookName) {
throw new UnsupportedOperationException();
}
@Override
public Set<String> listClients() {
throw new UnsupportedOperationException();
}
@Override
public Set<String> listCookbooks() {
throw new UnsupportedOperationException();
}
@Override
public Set<String> listDatabagItems(String databagName) {
return storageMetadataToName.apply(databags.list(databagName));
}
@Override
public Set<String> listDatabags() {
return storageMetadataToName.apply(databags.list());
}
@Override
public Set<String> listNodes() {
throw new UnsupportedOperationException();
}
@Override
public Set<String> listRoles() {
throw new UnsupportedOperationException();
}
@Override
public Set<String> listSearchIndexes() {
throw new UnsupportedOperationException();
}
@Override
public SearchResult<? extends Client> searchClients() {
throw new UnsupportedOperationException();
}
@Override
public SearchResult<? extends Client> searchClients(SearchOptions options) {
throw new UnsupportedOperationException();
}
@Override
public SearchResult<? extends DatabagItem> searchDatabagItems(String databagName) {
throw new UnsupportedOperationException();
}
@Override
public SearchResult<? extends DatabagItem> searchDatabagItems(String databagName, SearchOptions options) {
throw new UnsupportedOperationException();
}
@Override
public SearchResult<? extends Node> searchNodes() {
throw new UnsupportedOperationException();
}
@Override
public SearchResult<? extends Node> searchNodes(SearchOptions options) {
throw new UnsupportedOperationException();
}
@Override
public SearchResult<? extends Role> searchRoles() {
throw new UnsupportedOperationException();
}
@Override
public SearchResult<? extends Role> searchRoles(SearchOptions options) {
throw new UnsupportedOperationException();
}
@Override
public CookbookVersion updateCookbook(String cookbookName, String version, CookbookVersion cookbook) {
throw new UnsupportedOperationException();
}
@Override
public DatabagItem updateDatabagItem(String databagName, DatabagItem item) {
return createDatabagItem(databagName, item);
}
@Override
public Node updateNode(Node node) {
throw new UnsupportedOperationException();
}
@Override
public Role updateRole(Role role) {
throw new UnsupportedOperationException();
}
@Override
public void uploadContent(URI location, Payload content) {
throw new UnsupportedOperationException();
}
@Override
public InputStream getResourceContents(Resource resource) {
throw new UnsupportedOperationException();
}
@Override
public Set<String> listEnvironments() {
throw new UnsupportedOperationException();
}
@Override
public void createEnvironment(Environment environment) {
throw new UnsupportedOperationException();
}
@Override
public Environment deleteEnvironment(String environmentName) {
throw new UnsupportedOperationException();
}
@Override
public Environment getEnvironment(String environmentName) {
throw new UnsupportedOperationException();
}
@Override
public Environment updateEnvironment(Environment environment) {
throw new UnsupportedOperationException();
}
@Override
public Set<CookbookDefinition> listCookbooksInEnvironment(String environmentName) {
throw new UnsupportedOperationException();
}
@Override
public Set<CookbookDefinition> listCookbooksInEnvironment(String environmentName, String numVersions) {
throw new UnsupportedOperationException();
}
@Override
public CookbookDefinition getCookbookInEnvironment(String environmentName, String cookbookName) {
throw new UnsupportedOperationException();
}
@Override
public CookbookDefinition getCookbookInEnvironment(String environmentName, String cookbookName, String numVersions) {
throw new UnsupportedOperationException();
}
@Override
public SearchResult<? extends Environment> searchEnvironments() {
throw new UnsupportedOperationException();
}
@Override
public SearchResult<? extends Environment> searchEnvironments(SearchOptions options) {
throw new UnsupportedOperationException();
}
@Override
public Set<String> listRecipesInEnvironment(String environmentName) {
throw new UnsupportedOperationException();
}
@Override
public Set<String> listNodesInEnvironment(String environmentName) {
throw new UnsupportedOperationException();
}
@Override
public void close() throws IOException {
closer.close();
}
}

View File

@ -0,0 +1,75 @@
/*
* 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.test;
import java.net.URI;
import org.jclouds.chef.ChefApiMetadata;
import org.jclouds.chef.config.ChefBootstrapModule;
import org.jclouds.chef.config.ChefParserModule;
import org.jclouds.chef.test.config.TransientChefApiModule;
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 the Amazon-specific Chef API
*/
public class TransientChefApiMetadata extends BaseHttpApiMetadata<TransientChefApi> {
@Override
public Builder toBuilder() {
return new Builder().fromApiMetadata(this);
}
public TransientChefApiMetadata() {
this(new Builder());
}
protected TransientChefApiMetadata(Builder builder) {
super(builder);
}
public static class Builder extends BaseHttpApiMetadata.Builder<TransientChefApi, Builder> {
protected Builder() {
id("transientchef")
.name("In-memory Chef API")
.identityName("unused")
.defaultIdentity("api")
.documentation(URI.create("http://localhost"))
.defaultCredential(
"-----BEGIN RSA PRIVATE KEY-----\nMIIEpQIBAAKCAQEAyb2ZJJqGm0KKR+8nfQJNsSd+F9tXNMV7CfOcW6jsqs8EZgiV\nR09hD1IYOj4YqM0qJONlgyg4xRWewdSG7QTPj1lJpVAida9sXy2+kzyagZA1Am0O\nZcbqb5hoeIDgcX+eDa79s0u0DomjcfO9EKhvHLBz+zM+3QqPRkPV8nYTbfs+HjVz\nzOU6D1B0XR3+IPZZl2AnWs2d0qhnStHcDUvnRVQ0P482YwN9VgceOZtpPz0DCKEJ\n5Tx5STub8k0/zt/VAMHQafLSuQMLd2s4ZLuOZptN//uAsTmxireqd37z+8ZTdBbJ\n8LEpJ+iCXuSfm5aUh7iw6oxvToY2AL53+jK2UQIDAQABAoIBAQDA88B3i/xWn0vX\nBVxFamCYoecuNjGwXXkSyZew616A+EOCu47bh4aTurdFbYL0YFaAtaWvzlaN2eHg\nDb+HDuTefE29+WkcGk6SshPmiz5T0XOCAICWw6wSVDkHmGwS4jZvbAFm7W8nwGk9\nYhxgxFiRngswJZFopOLoF5WXs2td8guIYNslMpo7tu50iFnBHwKO2ZsPAk8t9nnS\nxlDavKruymEmqHCr3+dtio5eaenJcp3fjoXBQOKUk3ipII29XRB8NqeCVV/7Kxwq\nckqOBEbRwBclckyIbD+RiAgKvOelORjEiE9R42vuqvxRA6k9kd9o7utlX0AUtpEn\n3gZc6LepAoGBAP9ael5Y75+sK2JJUNOOhO8ae45cdsilp2yI0X+UBaSuQs2+dyPp\nkpEHAxd4pmmSvn/8c9TlEZhr+qYbABXVPlDncxpIuw2Ajbk7s/S4XaSKsRqpXL57\nzj/QOqLkRk8+OVV9q6lMeQNqLtEj1u6JPviX70Ro+FQtRttNOYbfdP/fAoGBAMpA\nXjR5woV5sUb+REg9vEuYo8RSyOarxqKFCIXVUNsLOx+22+AK4+CQpbueWN7jotrl\nYD6uT6svWi3AAC7kiY0UI/fjVPRCUi8tVoQUE0TaU5VLITaYOB+W/bBaDE4M9560\n1NuDWO90baA5dfU44iuzva02rGJXK9+nS3o8nk/PAoGBALOL6djnDe4mwAaG6Jco\ncd4xr8jkyPzCRZuyBCSBbwphIUXLc7hDprPky064ncJD1UDmwIdkXd/fpMkg2QmA\n/CUk6LEFjMisqHojOaCL9gQZJPhLN5QUN2x1PJWGjs1vQh8Tkx0iUUCOa8bQPXNR\n+34OTsW6TUna4CSZAycLfhffAoGBAIggVsefBCvuQkF0NeUhmDCRZfhnd8y55RHR\n1HCvqKIlpv+rhcX/zmyBLuteopYyRJRsOiE2FW00i8+rIPRu4Z3Q5nybx7w3PzV9\noHN5R5baE9OyI4KpZWztpYYitZF67NcnAvVULHHOvVJQGnKYfLHJYmrJF7GA1ojM\nAuMdFbjFAoGAPxUhxwFy8gaqBahKUEZn4F81HFP5ihGhkT4QL6AFPO2e+JhIGjuR\n27+85hcFqQ+HHVtFsm81b/a+R7P4UuCRgc8eCjxQMoJ1Xl4n7VbjPbHMnIN0Ryvd\nO4ZpWDWYnCO021JTOUUOJ4J/y0416Bvkw0z59y7sNX7wDBBHHbK/XCc=\n-----END RSA PRIVATE KEY-----\n")
.defaultEndpoint("transientchef")
.defaultProperties(ChefApiMetadata.defaultProperties())
.defaultModules(
ImmutableSet.<Class<? extends Module>> of(TransientChefApiModule.class, ChefParserModule.class,
ChefBootstrapModule.class, JMXOhaiModule.class));
}
@Override
public TransientChefApiMetadata build() {
return new TransientChefApiMetadata(this);
}
@Override
protected Builder self() {
return this;
}
}
}

View File

@ -0,0 +1,114 @@
/*
* 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.test.config;
import static com.google.common.util.concurrent.MoreExecutors.sameThreadExecutor;
import java.io.IOException;
import java.security.PrivateKey;
import java.security.spec.InvalidKeySpecException;
import java.util.List;
import javax.inject.Singleton;
import org.jclouds.ContextBuilder;
import org.jclouds.blobstore.TransientApiMetadata;
import org.jclouds.blobstore.config.LocalBlobStore;
import org.jclouds.chef.ChefApi;
import org.jclouds.chef.config.Validator;
import org.jclouds.chef.domain.Client;
import org.jclouds.chef.functions.BootstrapConfigForGroup;
import org.jclouds.chef.functions.ClientForGroup;
import org.jclouds.chef.functions.RunListForGroup;
import org.jclouds.chef.test.TransientChefApi;
import org.jclouds.concurrent.config.ExecutorServiceModule;
import org.jclouds.crypto.Crypto;
import org.jclouds.domain.JsonBall;
import org.jclouds.rest.ConfiguresHttpApi;
import org.jclouds.rest.config.RestModule;
import com.google.common.base.Optional;
import com.google.common.base.Supplier;
import com.google.common.cache.CacheLoader;
import com.google.common.collect.ImmutableSet;
import com.google.inject.AbstractModule;
import com.google.inject.Injector;
import com.google.inject.Module;
import com.google.inject.Provides;
import com.google.inject.name.Names;
@ConfiguresHttpApi
public class TransientChefApiModule extends AbstractModule {
@Override
protected void configure() {
install(new RestModule());
bind(ChefApi.class).to(TransientChefApi.class);
bind(LocalBlobStore.class).annotatedWith(Names.named("databags"))
.toInstance(
ContextBuilder
.newBuilder(new TransientApiMetadata())
.modules(
ImmutableSet.<Module> of(new ExecutorServiceModule(sameThreadExecutor(),
sameThreadExecutor()))).buildInjector().getInstance(LocalBlobStore.class));
}
@Provides
@Singleton
public Supplier<PrivateKey> supplyKey() {
return new Supplier<PrivateKey>() {
@Override
public PrivateKey get() {
return null;
}
};
}
@Provides
@Singleton
CacheLoader<String, List<String>> runListForGroup(RunListForGroup runListForGroup) {
return CacheLoader.from(runListForGroup);
}
@Provides
@Singleton
CacheLoader<String, ? extends JsonBall> bootstrapConfigForGroup(BootstrapConfigForGroup bootstrapConfigForGroup) {
return CacheLoader.from(bootstrapConfigForGroup);
}
@Provides
@Singleton
CacheLoader<String, Client> groupToClient(ClientForGroup clientForGroup) {
return CacheLoader.from(clientForGroup);
}
@Provides
@Singleton
@Validator
public Optional<String> provideValidatorName(Injector injector) {
return Optional.absent();
}
@Provides
@Singleton
@Validator
public Optional<PrivateKey> provideValidatorCredential(Crypto crypto, Injector injector)
throws InvalidKeySpecException, IOException {
return Optional.absent();
}
}

View File

@ -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.util;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Date;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.jclouds.domain.JsonBall;
import org.jclouds.ohai.Automatic;
import com.google.common.base.Predicate;
import com.google.common.base.Supplier;
import com.google.common.collect.Iterables;
import com.google.inject.Binder;
import com.google.inject.TypeLiteral;
import com.google.inject.multibindings.MapBinder;
public class ChefUtils {
public static Date fromOhaiTime(JsonBall ohaiDate) {
return new Date(Long.parseLong(checkNotNull(ohaiDate, "ohaiDate").toString().replaceAll("\\.[0-9]*$", "")));
}
public static JsonBall toOhaiTime(long millis) {
return new JsonBall(millis + "");
}
public static MapBinder<String, Supplier<JsonBall>> ohaiAutomaticAttributeBinder(Binder binder) {
MapBinder<String, Supplier<JsonBall>> mapbinder = MapBinder.newMapBinder(binder, new TypeLiteral<String>() {
}, new TypeLiteral<Supplier<JsonBall>>() {
}, Automatic.class);
return mapbinder;
}
/**
*
* @return NoSuchElementException if no element in the runList is a role.
*/
public static String findRoleInRunList(List<String> runList) {
final Pattern pattern = Pattern.compile("^role\\[(.*)\\]$");
String roleToParse = Iterables.find(runList, new Predicate<String>() {
@Override
public boolean apply(String input) {
return pattern.matcher(input).matches();
}
});
Matcher matcher = pattern.matcher(roleToParse);
matcher.find();
return matcher.group(1);
}
}

View File

@ -0,0 +1,69 @@
/*
* 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.util;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.jclouds.javax.annotation.Nullable;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
/**
* Utility methods to work with collections.
*/
public class CollectionUtils {
/**
* Creates an immutable list with the elements of the given list. If the
* input list is <code>null</code>, it returns an empty list.
*
* @param input
* The list used to build the immutable one.
* @return An immutable list with the elements of the given list.
*/
public static <T> ImmutableList<T> copyOfOrEmpty(@Nullable List<T> input) {
return input == null ? ImmutableList.<T> of() : ImmutableList.copyOf(input);
}
/**
* Creates an immutable set with the elements of the given set. If the input
* set is <code>null</code>, it returns an empty set.
*
* @param input
* The set used to build the immutable one.
* @return An immutable set with the elements of the given set.
*/
public static <T> ImmutableSet<T> copyOfOrEmpty(@Nullable Set<T> input) {
return input == null ? ImmutableSet.<T> of() : ImmutableSet.copyOf(input);
}
/**
* Creates an immutable map with the elements of the given map. If the input
* map is <code>null</code>, it returns an empty map.
*
* @param input
* The map used to build the immutable one.
* @return An immutable map with the elements of the given map.
*/
public static <K, V> ImmutableMap<K, V> copyOfOrEmpty(@Nullable Map<K, V> input) {
return input == null ? ImmutableMap.<K, V> of() : ImmutableMap.copyOf(input);
}
}

View File

@ -0,0 +1,83 @@
/*
* 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.util;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.collect.Iterables.addAll;
import static com.google.common.collect.Lists.newArrayList;
import static com.google.common.collect.Lists.transform;
import java.util.Arrays;
import java.util.List;
import com.google.common.base.Function;
import com.google.common.collect.ImmutableList;
/**
* builds a run list in the correct syntax for chef.
*/
public class RunListBuilder {
private List<String> list = newArrayList();
/**
* Add the following recipe to the run list
*/
public RunListBuilder addRecipe(String recipe) {
return addRecipes(checkNotNull(recipe, "recipe"));
}
/**
* Add the following recipes to the run list
*/
public RunListBuilder addRecipes(String... recipes) {
addAll(list, transform(Arrays.asList(checkNotNull(recipes, "recipes")), new Function<String, String>() {
@Override
public String apply(String from) {
return "recipe[" + from + "]";
}
}));
return this;
}
/**
* Add the following role to the run list
*/
public RunListBuilder addRole(String role) {
return addRoles(checkNotNull(role, "role"));
}
/**
* Add the following roles to the run list
*/
public RunListBuilder addRoles(String... roles) {
addAll(list, transform(Arrays.asList(checkNotNull(roles, "roles")), new Function<String, String>() {
@Override
public String apply(String from) {
return "role[" + from + "]";
}
}));
return this;
}
public List<String> build() {
return ImmutableList.copyOf(list);
}
}

View File

@ -0,0 +1,33 @@
/*
* 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.ohai;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import javax.inject.Qualifier;
@Retention(RUNTIME)
@Target({ TYPE, METHOD, PARAMETER })
@Qualifier
public @interface Automatic {
}

View File

@ -0,0 +1,48 @@
/*
* 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.ohai;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Map;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.domain.JsonBall;
import org.jclouds.ohai.functions.NestSlashKeys;
import com.google.common.base.Supplier;
import com.google.common.collect.Multimap;
@Singleton
public class AutomaticSupplier implements Supplier<Map<String, JsonBall>> {
private final Multimap<String, Supplier<JsonBall>> autoAttrs;
private final NestSlashKeys nester;
@Inject
AutomaticSupplier(@Automatic Multimap<String, Supplier<JsonBall>> autoAttrs, NestSlashKeys nester) {
this.autoAttrs = checkNotNull(autoAttrs, "autoAttrs");
this.nester = checkNotNull(nester, "nester");
}
@Override
public Map<String, JsonBall> get() {
return nester.apply(autoAttrs);
}
}

View File

@ -0,0 +1,28 @@
/*
* 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.ohai.config;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Retention(RUNTIME)
@Target(TYPE)
public @interface ConfiguresOhai {
}

View File

@ -0,0 +1,48 @@
/*
* 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.ohai.config;
import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;
import javax.inject.Singleton;
import org.jclouds.domain.JsonBall;
import org.jclouds.ohai.suppliers.UptimeSecondsSupplier;
import com.google.common.base.Supplier;
import com.google.inject.Provides;
import com.google.inject.multibindings.MapBinder;
/**
* Wires the components needed to parse ohai data from a JVM
*/
@ConfiguresOhai
public class JMXOhaiModule extends OhaiModule {
@Provides
@Singleton
protected RuntimeMXBean provideRuntimeMXBean() {
return ManagementFactory.getRuntimeMXBean();
}
public MapBinder<String, Supplier<JsonBall>> bindOhai() {
MapBinder<String, Supplier<JsonBall>> mapBinder = super.bindOhai();
mapBinder.addBinding("uptime_seconds").to(UptimeSecondsSupplier.class);
return mapBinder;
}
}

Some files were not shown because too many files have changed in this diff Show More