This commit is contained in:
Adrian Cole 2010-09-18 12:13:09 -07:00
parent 2b918d5827
commit 686d058b09
169 changed files with 1 additions and 17054 deletions

View File

@ -44,15 +44,5 @@
<artifactId>jclouds-twitter</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>jclouds-chef</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>jclouds-opscodeplatform</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</project>

View File

@ -1,185 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
$HeadURL$ $Revision$ $Date$ Copyright (C) 2010 Cloud Conscious,
LLC <info@cloudconscious.com>
====================================================================
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.html 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.jclouds</groupId>
<artifactId>jclouds-chef-project</artifactId>
<version>1.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>org.jclouds</groupId>
<artifactId>jclouds-chef-compute</artifactId>
<name>jclouds chef compute integration</name>
<description>provisions nodes with jclouds and kick's off chef to configure and integrate</description>
<properties>
<!--
for example: ec2, trmk-ecloud, bluelock-vclouddirector,
cloudservers, etc
-->
<jclouds.compute.provider>YOUR_PREFERRED_PROVIDER</jclouds.compute.provider>
<!-- leave blank unless you have a different url to override -->
<jclouds.compute.endpoint></jclouds.compute.endpoint>
<jclouds.compute.identity>YOUR_ACCOUNT</jclouds.compute.identity>
<jclouds.compute.credential>YOUR_CREDENTIAL</jclouds.compute.credential>
<!-- tag for nodes used in the tests -->
<jclouds.compute.tag>jcloudschef</jclouds.compute.tag>
<jclouds.chef.identity>YOUR_USER</jclouds.chef.identity>
<jclouds.chef.credential.pem>${user.home}/.chef/${jclouds.chef.identity}.pem</jclouds.chef.credential.pem>
<jclouds.opscodeplatform.org>YOUR_ORG</jclouds.opscodeplatform.org>
<jclouds.chef.endpoint>https://api.opscode.com/organizations/${jclouds.opscodeplatform.org}</jclouds.chef.endpoint>
</properties>
<!-- bootstrapping: need to fetch the project POM -->
<repositories>
<repository>
<id>jclouds-googlecode-deploy</id>
<url>http://jclouds.googlecode.com/svn/repo</url>
</repository>
<repository>
<id>jclouds-rimu-snapshots-nexus</id>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>jclouds-chef</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>jclouds-compute</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>jclouds-jsch</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>jclouds-log4j</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.14</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>jclouds-core</artifactId>
<version>${project.version}</version>
<type>test-jar</type>
<scope>test</scope>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>jclouds-compute</artifactId>
<version>${project.version}</version>
<type>test-jar</type>
<scope>test</scope>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>jclouds-allcompute</artifactId>
<version>${project.version}</version>
<scope>test</scope>
<optional>true</optional>
</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>
<excludes>
<exclude>none</exclude>
</excludes>
<includes>
<include>**/*LiveTest.java</include>
</includes>
<systemProperties>
<property>
<name>jclouds.compute.provider</name>
<value>${jclouds.compute.provider}</value>
</property>
<property>
<name>jclouds.compute.endpoint</name>
<value>${jclouds.compute.endpoint}</value>
</property>
<property>
<name>jclouds.compute.identity</name>
<value>${jclouds.compute.identity}</value>
</property>
<property>
<name>jclouds.compute.credential</name>
<value>${jclouds.compute.credential}</value>
</property>
<property>
<name>jclouds.compute.tag</name>
<value>${jclouds.compute.tag}</value>
</property>
<property>
<name>jclouds.compute.credential</name>
<value>${jclouds.compute.credential}</value>
</property>
<property>
<name>jclouds.chef.credential.pem</name>
<value>${jclouds.chef.credential.pem}</value>
</property>
<property>
<name>jclouds.chef.endpoint</name>
<value>${jclouds.chef.endpoint}</value>
</property>
</systemProperties>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>

View File

@ -1,165 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.compute;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.collect.Iterables.any;
import static com.google.common.collect.Iterables.concat;
import static com.google.common.collect.Iterables.getLast;
import static org.jclouds.chef.predicates.CookbookVersionPredicates.containsRecipe;
import static org.jclouds.chef.predicates.CookbookVersionPredicates.containsRecipes;
import static org.jclouds.compute.options.TemplateOptions.Builder.runScript;
import static org.testng.Assert.assertEquals;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.util.List;
import java.util.Properties;
import org.jclouds.chef.ChefContext;
import org.jclouds.chef.ChefContextFactory;
import org.jclouds.chef.domain.CookbookVersion;
import org.jclouds.chef.util.RunListBuilder;
import org.jclouds.compute.ComputeServiceContext;
import org.jclouds.compute.ComputeServiceContextFactory;
import org.jclouds.compute.RunNodesException;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.predicates.NodePredicates;
import org.jclouds.io.Payload;
import org.jclouds.logging.log4j.config.Log4JLoggingModule;
import org.jclouds.ssh.jsch.config.JschSshClientModule;
import org.jclouds.util.Utils;
import org.testng.annotations.AfterGroups;
import org.testng.annotations.BeforeGroups;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableSet;
import com.google.inject.Module;
/**
*
* @author Adrian Cole
*/
@Test(groups = "live", testName = "chef.ChefComputeServiceLiveTest")
public class ChefComputeServiceLiveTest {
private ComputeServiceContext computeContext;
private ChefContext chefContext;
private String tag;
private String clientName;
private String chefEndpoint;
private Iterable<? extends NodeMetadata> nodes;
@BeforeGroups(groups = { "live" })
public void setupAll() throws FileNotFoundException, IOException {
tag = System.getProperty("jclouds.compute.tag") != null ? System.getProperty("jclouds.compute.tag")
: "jcloudschef";
String computeProvider = checkNotNull(System.getProperty("jclouds.compute.provider"), "jclouds.compute.provider");
String computeEndpoint = System.getProperty("jclouds.compute.endpoint");
String computeIdentity = checkNotNull(System.getProperty("jclouds.compute.identity"), "jclouds.compute.identity");
String computeCredential = checkNotNull(System.getProperty("jclouds.compute.credential"),
"jclouds.compute.credential");
chefEndpoint = checkNotNull(System.getProperty("jclouds.chef.endpoint"), "jclouds.chef.endpoint");
String chefIdentity = checkNotNull(System.getProperty("jclouds.chef.identity"), "jclouds.chef.identity");
String chefCredentialFile = System.getProperty("jclouds.chef.credential.pem");
if (chefCredentialFile == null || chefCredentialFile.equals(""))
chefCredentialFile = System.getProperty("user.home") + "/.chef/" + chefIdentity + ".pem";
Properties props = new Properties();
props.setProperty(computeProvider + ".identity", computeIdentity);
props.setProperty(computeProvider + ".credential", computeCredential);
props.setProperty("chef.endpoint", chefEndpoint);
props.setProperty("chef.identity", chefIdentity);
props.setProperty("chef.credential.file", chefCredentialFile);
if (computeEndpoint != null && !computeEndpoint.trim().equals(""))
props.setProperty(computeProvider + ".endpoint", computeEndpoint);
computeContext = new ComputeServiceContextFactory().createContext(computeProvider, ImmutableSet.of(
new Log4JLoggingModule(), getSshModule()), props);
chefContext = new ChefContextFactory().createContext(ImmutableSet.<Module> of(new Log4JLoggingModule()), props);
}
protected Module getSshModule() {
return new JschSshClientModule();
}
@Test
public void testCanUpdateRunList() throws IOException {
String recipe = "apache2";
Iterable<? extends CookbookVersion> cookbookVersions = chefContext.getChefService().listCookbookVersions();
if (any(cookbookVersions, containsRecipe(recipe))) {
List<String> runList = new RunListBuilder().addRecipe(recipe).build();
chefContext.getChefService().updateRunListForTag(runList, tag);
assertEquals(chefContext.getChefService().getRunListForTag(tag), runList);
} else {
assert false : String.format("recipe %s not in %s", recipe, cookbookVersions);
}
// TODO move this to a unit test
assert any(cookbookVersions, containsRecipe("apache2::mod_proxy"));
assert any(cookbookVersions, containsRecipes("apache2", "apache2::mod_proxy", "apache2::mod_proxy_http"));
assert !any(cookbookVersions, containsRecipe("apache2::bar"));
assert !any(cookbookVersions, containsRecipe("foo::bar"));
}
@Test(dependsOnMethods = "testCanUpdateRunList")
public void testRunNodesWithBootstrap() throws IOException {
Payload bootstrap = chefContext.getChefService().createClientAndBootstrapScriptForTag(tag);
try {
nodes = computeContext.getComputeService().runNodesWithTag(tag, 1, runScript(bootstrap));
} catch (RunNodesException e) {
nodes = concat(e.getSuccessfulNodes(), e.getNodeErrors().keySet());
}
for (NodeMetadata node : nodes) {
URI uri = URI.create("http://" + getLast(node.getPublicAddresses()));
InputStream content = computeContext.utils().http().get(uri);
String string = Utils.toStringAndClose(content);
assert string.indexOf("It works!") >= 0 : string;
}
}
@AfterGroups(groups = { "live" })
public void teardownCompute() {
if (computeContext != null) {
computeContext.getComputeService().destroyNodesMatching(NodePredicates.withTag(tag));
computeContext.close();
}
}
@AfterGroups(groups = { "live" })
public void teardownChef() {
if (chefContext != null) {
chefContext.getChefService().cleanupStaleNodesAndClients(tag + "-", 1);
if (clientName != null && chefContext.getApi().clientExists(clientName))
chefContext.getApi().deleteClient(clientName);
chefContext.close();
}
}
}

View File

@ -1,203 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (C) 2009 Cloud Conscious, LLC.
<info@cloudconscious.com>
====================================================================
Licensed 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.
====================================================================
-->
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<!--
For more configuration infromation and examples see the Apache
Log4j website: http://logging.apache.org/log4j/
-->
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/"
debug="false">
<!-- A time/date based rolling appender -->
<appender name="COMPUTEFILE" class="org.apache.log4j.DailyRollingFileAppender">
<param name="File" value="target/test-data/jclouds-compute.log" />
<param name="Append" value="true" />
<!-- Rollover at midnight each day -->
<param name="DatePattern" value="'.'yyyy-MM-dd" />
<param name="Threshold" value="TRACE" />
<layout class="org.apache.log4j.PatternLayout">
<!-- The default pattern: Date Priority [Category] Message\n -->
<param name="ConversionPattern" value="%d %-5p [%c] (%t) %m%n" />
<!--
The full pattern: Date MS Priority [Category]
(Thread:NDC) Message\n <param name="ConversionPattern"
value="%d %-5r %-5p [%c] (%t:%x) %m%n"/>
-->
</layout>
</appender>
<!-- A time/date based rolling appender -->
<appender name="SSHFILE" class="org.apache.log4j.DailyRollingFileAppender">
<param name="File" value="target/test-data/jclouds-ssh.log" />
<param name="Append" value="true" />
<!-- Rollover at midnight each day -->
<param name="DatePattern" value="'.'yyyy-MM-dd" />
<param name="Threshold" value="TRACE" />
<layout class="org.apache.log4j.PatternLayout">
<!-- The default pattern: Date Priority [Category] Message\n -->
<param name="ConversionPattern" value="%d %-5p [%c] (%t) %m%n" />
<!--
The full pattern: Date MS Priority [Category]
(Thread:NDC) Message\n <param name="ConversionPattern"
value="%d %-5r %-5p [%c] (%t:%x) %m%n"/>
-->
</layout>
</appender>
<!-- A time/date based rolling appender -->
<appender name="CHEFFILE" class="org.apache.log4j.DailyRollingFileAppender">
<param name="File" value="target/test-data/jclouds-chef.log" />
<param name="Append" value="true" />
<!-- Rollover at midnight each day -->
<param name="DatePattern" value="'.'yyyy-MM-dd" />
<param name="Threshold" value="TRACE" />
<layout class="org.apache.log4j.PatternLayout">
<!-- The default pattern: Date Priority [Category] Message\n -->
<param name="ConversionPattern" value="%d %-5p [%c] (%t) %m%n" />
<!--
The full pattern: Date MS Priority [Category]
(Thread:NDC) Message\n <param name="ConversionPattern"
value="%d %-5r %-5p [%c] (%t:%x) %m%n"/>
-->
</layout>
</appender>
<!-- A time/date based rolling appender -->
<appender name="WIREFILE" class="org.apache.log4j.DailyRollingFileAppender">
<param name="File" value="target/test-data/jclouds-wire.log" />
<param name="Append" value="true" />
<!-- Rollover at midnight each day -->
<param name="DatePattern" value="'.'yyyy-MM-dd" />
<param name="Threshold" value="TRACE" />
<layout class="org.apache.log4j.PatternLayout">
<!-- The default pattern: Date Priority [Category] Message\n -->
<param name="ConversionPattern" value="%d %-5p [%c] (%t) %m%n" />
<!--
The full pattern: Date MS Priority [Category]
(Thread:NDC) Message\n <param name="ConversionPattern"
value="%d %-5r %-5p [%c] (%t:%x) %m%n"/>
-->
</layout>
</appender>
<!-- A time/date based rolling appender -->
<appender name="FILE" class="org.apache.log4j.DailyRollingFileAppender">
<param name="File" value="target/test-data/jclouds.log" />
<param name="Append" value="true" />
<!-- Rollover at midnight each day -->
<param name="DatePattern" value="'.'yyyy-MM-dd" />
<param name="Threshold" value="TRACE" />
<layout class="org.apache.log4j.PatternLayout">
<!-- The default pattern: Date Priority [Category] Message\n -->
<param name="ConversionPattern" value="%d %-5p [%c] (%t) %m%n" />
<!--
The full pattern: Date MS Priority [Category]
(Thread:NDC) Message\n <param name="ConversionPattern"
value="%d %-5r %-5p [%c] (%t:%x) %m%n"/>
-->
</layout>
</appender>
<appender name="ASYNCCOMPUTE" class="org.apache.log4j.AsyncAppender">
<appender-ref ref="COMPUTEFILE" />
</appender>
<appender name="ASYNCCHEF" class="org.apache.log4j.AsyncAppender">
<appender-ref ref="CHEFFILE" />
</appender>
<appender name="ASYNCSSH" class="org.apache.log4j.AsyncAppender">
<appender-ref ref="SSHFILE" />
</appender>
<appender name="ASYNC" class="org.apache.log4j.AsyncAppender">
<appender-ref ref="FILE" />
</appender>
<appender name="ASYNCWIRE" class="org.apache.log4j.AsyncAppender">
<appender-ref ref="WIREFILE" />
</appender>
<!-- ================ -->
<!-- Limit categories -->
<!-- ================ -->
<category name="org.jclouds">
<priority value="DEBUG" />
<appender-ref ref="ASYNC" />
</category>
<category name="jclouds.headers">
<priority value="DEBUG" />
<appender-ref ref="ASYNCWIRE" />
</category>
<category name="jclouds.wire">
<priority value="DEBUG" />
<appender-ref ref="ASYNCWIRE" />
</category>
<category name="jclouds.chef">
<priority value="TRACE" />
<appender-ref ref="ASYNCCHEF" />
</category>
<category name="jclouds.ssh">
<priority value="DEBUG" />
<appender-ref ref="ASYNCSSH" />
</category>
<category name="jclouds.compute">
<priority value="TRACE" />
<appender-ref ref="ASYNCCOMPUTE" />
</category>
<!--
<category name="jclouds.wire"> <priority value="DEBUG" />
<appender-ref ref="ASYNCWIRE" /> </category> <category
name="jclouds.signature"> <priority value="DEBUG" />
<appender-ref ref="ASYNCWIRE" /> </category>
-->
<!-- ======================= -->
<!-- Setup the Root category -->
<!-- ======================= -->
<root>
<priority value="WARN" />
</root>
</log4j:configuration>

View File

@ -1,120 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (C) 2010 Cloud Conscious, LLC
<info@cloudconscious.com>
====================================================================
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.html 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.jclouds</groupId>
<artifactId>jclouds-chef-project</artifactId>
<version>1.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>org.jclouds</groupId>
<artifactId>jclouds-chef</artifactId>
<name>jclouds Chef core</name>
<description>jclouds components to access Chef</description>
<scm>
<connection>scm:svn:http://jclouds.googlecode.com/svn/trunk/chef</connection>
<developerConnection>scm:svn:https://jclouds.googlecode.com/svn/trunk/chef</developerConnection>
<url>http://jclouds.googlecode.com/svn/trunk/chef</url>
</scm>
<!-- bootstrapping: need to fetch the project POM -->
<repositories>
<repository>
<id>jclouds-googlecode-deploy</id>
<url>http://jclouds.googlecode.com/svn/repo</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>jclouds-rimu-snapshots-nexus</id>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
<properties>
<jclouds.chef.identity>chef-validator</jclouds.chef.identity>
<jclouds.chef.rsa-key>/etc/chef/validation.pem</jclouds.chef.rsa-key>
<jclouds.chef.endpoint>http://localhost:4000</jclouds.chef.endpoint>
<jclouds.test.identity>${jclouds.chef.identity}</jclouds.test.identity>
<jclouds.test.credential>${jclouds.chef.rsa-key}</jclouds.test.credential>
<jclouds.test.endpoint>${jclouds.chef.endpoint}</jclouds.test.endpoint>
</properties>
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>jclouds-core</artifactId>
<version>${project.version}</version>
</dependency>
<!-- only required for Pems.java and only writing a private key file -->
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15</artifactId>
<version>1.44</version>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>jclouds-scriptbuilder</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>jclouds-core</artifactId>
<version>${project.version}</version>
<type>test-jar</type>
<scope>test</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.14</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>jclouds-log4j</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.danlarkin</groupId>
<artifactId>clojure-json</artifactId>
<version>1.1</version>
<optional>true</optional>
</dependency>
<!-- for transient chef provider -->
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>jclouds-blobstore</artifactId>
<version>${project.version}</version>
<optional>true</optional>
</dependency>
</dependencies>
</project>

View File

@ -1,261 +0,0 @@
;
;
; Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
;
; ====================================================================
; Licensed 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.chef ChefClient
ChefService ChefContext ChefContextFactory]
[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))]
(.. (ChefContextFactory.)
(createContext provider identity credential
(apply modules (concat ext-modules (opts :extensions)))
(reduce #(do (.put %1 (name (first %2)) (second %2)) %1)
(Properties.) (dissoc opts :extensions)))
(getChefService)))))
(defn chef-context
"Returns a chef context from a chef service."
[#^ChefService chef]
(.getContext chef))
(defn chef-service?
[object]
(instance? ChefService object))
(defn chef-context?
[object]
(instance? ChefContext object))
(defn as-chef-service
"Tries hard to produce a chef service from its input arguments"
[& args]
(cond
(chef-service? (first args)) (first args)
(chef-context? (first args)) (.getChefService (first args))
:else (apply chef-service args)))
(defn as-chef-api
"Tries hard to produce a chef client from its input arguments"
[& args]
(cond
(chef-service? (first args)) (.getApi (.getContext (first args)))
(chef-context? (first args)) (.getApi (first args))
:else (.getApi (.getContext (apply chef-service args)))))
(def *chef*)
(defmacro with-chef-service
"Specify the default chef service"
[[& chef-or-args] & body]
`(binding [*chef* (as-chef-service ~@chef-or-args)]
~@body))
(defn nodes
"Retrieve the names of the existing nodes in your chef server."
([] (nodes *chef*))
([#^ChefService chef]
(seq (.listNodes (as-chef-api chef)))))
(defn nodes-with-details
"Retrieve the existing nodes in your chef server including all details."
([] (nodes *chef*))
([#^ChefService chef]
(seq (.listNodes chef))))
(defn clients
"Retrieve the names of the existing clients in your chef server."
([] (clients *chef*))
([#^ChefService chef]
(seq (.listClients (as-chef-api chef)))))
(defn clients-with-details
"Retrieve the existing clients in your chef server including all details."
([] (clients *chef*))
([#^ChefService chef]
(seq (.listClients chef))))
(defn cookbooks
"Retrieve the names of the existing cookbooks in your chef server."
([] (cookbooks *chef*))
([#^ChefService chef]
(seq (.listCookbooks (as-chef-api chef)))))
(defn cookbook-versions
"Retrieve the versions of an existing cookbook in your chef server."
([name] (cookbook-versions *chef*))
([#^ChefService name chef]
(seq (.getVersionsOfCookbook (as-chef-api chef) name))))
(defn cookbook-versions-with-details
"Retrieve the existing cookbook versions in your chef server including all details."
([] (cookbook-versions *chef*))
([#^ChefService chef]
(seq (.listCookbookVersions chef))))
(defn update-run-list
"Updates the run-list associated with a tag"
([run-list tag] (update-run-list run-list tag *chef*))
([run-list tag #^ChefService chef]
(.updateRunListForTag chef run-list tag)))
(defn run-list
"Retrieves the run-list associated with a tag"
([tag] (run-list tag *chef*))
([tag #^ChefService chef]
(seq (.getRunListForTag chef tag))))
(defn create-bootstrap
"creates a client and bootstrap script associated with a tag"
([tag] (create-bootstrap tag *chef*))
([tag #^ChefService chef]
(.createClientAndBootstrapScriptForTag chef tag)))
(defn databags
"Retrieve the names of the existing data bags in your chef server."
([] (databags *chef*))
([#^ChefService chef]
(seq (.listDatabags (as-chef-api chef)))))
(defn databag-exists?
"Predicate to check presence of a databag"
([databag-name]
(databag-exists? databag-name *chef*))
([databag-name #^ChefService chef]
(.databagExists (as-chef-api chef) databag-name)))
(defn delete-databag
"Delete a data bag, including its items"
([databag]
(delete-databag databag *chef*))
([databag chef]
(.deleteDatabag (as-chef-api chef) databag)))
(defn create-databag
"create a data bag"
([databag]
(create-databag databag *chef*))
([databag chef]
(.createDatabag (as-chef-api chef) databag)))
(defn databag-items
"Retrieve the names of the existing items in a data bag in your chef server."
([databag]
(databag-items databag *chef*))
([databag chef]
(seq (.listDatabagItems (as-chef-api chef) databag))))
(defn databag-item-exists?
"Predicate to check presence of a databag item"
([databag-name item-id]
(databag-item-exists? databag-name item-id *chef*))
([databag-name item-id #^ChefService chef]
(.databagExists (as-chef-api chef) databag-name item-id)))
(defn databag-item
"Get an item from the data bag"
([databag item-id]
(databag-item databag item-id *chef*))
([databag item-id chef]
(json/decode-from-str (str (.getDatabagItem (as-chef-api chef) databag item-id)))))
(defn delete-databag-item
"delete an item from the data bag"
([databag item-id]
(delete-databag-item databag item-id *chef*))
([databag item-id chef]
(.deleteDatabagItem (as-chef-api chef) databag item-id)))
(defn create-databag-item
"put a new item in the data bag. Note the Map you pass must have an :id key:
ex.
(create-databag-item \"cluster-config\" {:id \"master\" :name \"myhost.com\"}))"
([databag value]
(create-databag-item databag value *chef*))
([databag value chef]
(let [value-str (json/encode-to-str value)]
(let [value-json (json/decode-from-str value-str)]
(.createDatabagItem (as-chef-api chef) databag
(DatabagItem. (get value-json :id) value-str))))))
(defn update-databag-item
"updates an existing item in the data bag. Note the Map you pass must have an :id key:
ex.
(update-databag-item \"cluster-config\" {:id \"master\" :name \"myhost.com\"}))"
([databag value]
(update-databag-item databag value *chef*))
([databag value chef]
(let [value-str (json/encode-to-str value)]
(let [value-json (json/decode-from-str value-str)]
(.updateDatabagItem (as-chef-api chef) databag
(DatabagItem. (get value-json :id) value-str))))))

View File

@ -1,420 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.util.List;
import java.util.Set;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.HEAD;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.core.MediaType;
import org.jclouds.chef.binders.BindChecksumsToJsonPayload;
import org.jclouds.chef.binders.BindClientnameToJsonPayload;
import org.jclouds.chef.binders.BindGenerateKeyForClientToJsonPayload;
import org.jclouds.chef.binders.BindIsCompletedToJsonPayload;
import org.jclouds.chef.binders.BindNameToJsonPayload;
import org.jclouds.chef.binders.DatabagItemId;
import org.jclouds.chef.binders.NodeName;
import org.jclouds.chef.binders.RoleName;
import org.jclouds.chef.domain.Client;
import org.jclouds.chef.domain.CookbookVersion;
import org.jclouds.chef.domain.DatabagItem;
import org.jclouds.chef.domain.Node;
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.ParseKeySetFromJson;
import org.jclouds.chef.functions.ParseSearchClientsFromJson;
import org.jclouds.chef.functions.ParseSearchDatabagFromJson;
import org.jclouds.chef.functions.ParseSearchNodesFromJson;
import org.jclouds.chef.functions.ParseSearchRolesFromJson;
import org.jclouds.rest.annotations.BinderParam;
import org.jclouds.rest.annotations.ExceptionParser;
import org.jclouds.rest.annotations.Headers;
import org.jclouds.rest.annotations.ParamParser;
import org.jclouds.rest.annotations.RequestFilters;
import org.jclouds.rest.annotations.ResponseParser;
import org.jclouds.rest.annotations.Unwrap;
import org.jclouds.rest.binders.BindToJsonPayload;
import org.jclouds.rest.functions.ReturnEmptySetOnNotFoundOr404;
import org.jclouds.rest.functions.ReturnFalseOnNotFoundOr404;
import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
import org.jclouds.rest.functions.ReturnVoidOnNotFoundOr404;
import com.google.common.util.concurrent.ListenableFuture;
/**
* Provides asynchronous access to Chef via their REST API.
* <p/>
*
* @see ChefClient
* @see <a href="TODO: insert URL of provider documentation" />
* @author Adrian Cole
*/
@RequestFilters(SignedHeaderAuth.class)
@Headers(keys = "X-Chef-Version", values = ChefAsyncClient.VERSION)
@Consumes(MediaType.APPLICATION_JSON)
public interface ChefAsyncClient {
public static final String VERSION = "0.9.8";
/**
* @see ChefClient#getUploadSandboxForChecksums
*/
@POST
@Path("/sandboxes")
ListenableFuture<UploadSandbox> getUploadSandboxForChecksums(
@BinderParam(BindChecksumsToJsonPayload.class) Set<List<Byte>> md5s);
@PUT
@Path("")
ListenableFuture<Void> uploadContent(@BinderParam(BindChecksumsToJsonPayload.class) Set<List<Byte>> md5s);
/**
* @see ChefClient#commitSandbox
*/
@PUT
@Path("/sandboxes/{id}")
ListenableFuture<Sandbox> commitSandbox(@PathParam("id") String id,
@BinderParam(BindIsCompletedToJsonPayload.class) boolean isCompleted);
/**
* @see ChefCookbooks#listCookbooks
*/
@GET
@Path("/cookbooks")
@ResponseParser(ParseKeySetFromJson.class)
@ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
ListenableFuture<Set<String>> listCookbooks();
/**
* @see ChefClient#updateCookbook
*/
@PUT
@Path("/cookbooks/{cookbookname}/{version}")
ListenableFuture<CookbookVersion> updateCookbook(@PathParam("cookbookname") String cookbookName,
@PathParam("version") String version, @BinderParam(BindToJsonPayload.class) CookbookVersion cookbook);
/**
* @see ChefCookbook#deleteCookbook(String)
*/
@DELETE
@Path("/cookbooks/{cookbookname}/{version}")
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
ListenableFuture<CookbookVersion> deleteCookbook(@PathParam("cookbookname") String cookbookName,
@PathParam("version") String version);
/**
* @see ChefCookbook#getVersionsOfCookbook
*/
@GET
@Path("/cookbooks/{cookbookname}")
@Unwrap
@ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
ListenableFuture<Set<String>> getVersionsOfCookbook(@PathParam("cookbookname") String cookbookName);
/**
* @see ChefCookbook#getCookbook
*/
@GET
@Path("/cookbooks/{cookbookname}/{version}")
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
ListenableFuture<CookbookVersion> getCookbook(@PathParam("cookbookname") String cookbookName,
@PathParam("version") String version);
/**
* @see ChefClient#createClient
*/
@POST
@Path("/clients")
ListenableFuture<Client> createClient(@BinderParam(BindClientnameToJsonPayload.class) String clientname);
/**
* @see ChefClient#generateKeyForClient
*/
@PUT
@Path("/clients/{clientname}")
ListenableFuture<Client> generateKeyForClient(
@PathParam("clientname") @BinderParam(BindGenerateKeyForClientToJsonPayload.class) String clientname);
/**
* @see ChefClient#clientExists
*/
@HEAD
@Path("/clients/{clientname}")
@ExceptionParser(ReturnFalseOnNotFoundOr404.class)
ListenableFuture<Boolean> clientExists(@PathParam("clientname") String clientname);
/**
* @see ChefClient#getClient
*/
@GET
@Path("/clients/{clientname}")
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
ListenableFuture<Client> getClient(@PathParam("clientname") String clientname);
/**
* @see ChefClient#deleteClient
*/
@DELETE
@Path("/clients/{clientname}")
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
ListenableFuture<Client> deleteClient(@PathParam("clientname") String clientname);
/**
* @see ChefClient#listClients
*/
@GET
@Path("/clients")
@ResponseParser(ParseKeySetFromJson.class)
@ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
ListenableFuture<Set<String>> listClients();
/**
* @see ChefClient#createNode
*/
@POST
@Path("/nodes")
ListenableFuture<Void> createNode(@BinderParam(BindToJsonPayload.class) Node node);
/**
* @see ChefClient#updateNode
*/
@PUT
@Path("/nodes/{nodename}")
ListenableFuture<Node> updateNode(
@PathParam("nodename") @ParamParser(NodeName.class) @BinderParam(BindToJsonPayload.class) Node node);
/**
* @see ChefNode#nodeExists
*/
@HEAD
@Path("/nodes/{nodename}")
@ExceptionParser(ReturnFalseOnNotFoundOr404.class)
ListenableFuture<Boolean> nodeExists(@PathParam("nodename") String nodename);
/**
* @see ChefNode#getNode
*/
@GET
@Path("/nodes/{nodename}")
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
ListenableFuture<Node> getNode(@PathParam("nodename") String nodename);
/**
* @see ChefNode#deleteNode
*/
@DELETE
@Path("/nodes/{nodename}")
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
ListenableFuture<Node> deleteNode(@PathParam("nodename") String nodename);
/**
* @see ChefNode#listNodes
*/
@GET
@Path("/nodes")
@ResponseParser(ParseKeySetFromJson.class)
@ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
ListenableFuture<Set<String>> listNodes();
/**
* @see ChefClient#createRole
*/
@POST
@Path("/roles")
ListenableFuture<Void> createRole(@BinderParam(BindToJsonPayload.class) Role role);
/**
* @see ChefClient#updateRole
*/
@PUT
@Path("/roles/{rolename}")
ListenableFuture<Role> updateRole(
@PathParam("rolename") @ParamParser(RoleName.class) @BinderParam(BindToJsonPayload.class) Role role);
/**
* @see ChefRole#roleExists
*/
@HEAD
@Path("/roles/{rolename}")
@ExceptionParser(ReturnFalseOnNotFoundOr404.class)
ListenableFuture<Boolean> roleExists(@PathParam("rolename") String rolename);
/**
* @see ChefRole#getRole
*/
@GET
@Path("/roles/{rolename}")
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
ListenableFuture<Role> getRole(@PathParam("rolename") String rolename);
/**
* @see ChefRole#deleteRole
*/
@DELETE
@Path("/roles/{rolename}")
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
ListenableFuture<Role> deleteRole(@PathParam("rolename") String rolename);
/**
* @see ChefRole#listRoles
*/
@GET
@Path("/roles")
@ResponseParser(ParseKeySetFromJson.class)
@ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
ListenableFuture<Set<String>> listRoles();
/**
* @see ChefClient#listDatabags
*/
@GET
@Path("/data")
@ResponseParser(ParseKeySetFromJson.class)
@ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
ListenableFuture<Set<String>> listDatabags();
/**
* @see ChefClient#createDatabag
*/
@POST
@Path("/data")
ListenableFuture<Void> createDatabag(@BinderParam(BindNameToJsonPayload.class) String databagName);
/**
* @see ChefClient#databagExists
*/
@HEAD
@Path("/data/{name}")
@ExceptionParser(ReturnFalseOnNotFoundOr404.class)
ListenableFuture<Boolean> databagExists(@PathParam("name") String databagName);
/**
* @see ChefClient#deleteDatabag
*/
@DELETE
@Path("/data/{name}")
@ExceptionParser(ReturnVoidOnNotFoundOr404.class)
ListenableFuture<Void> deleteDatabag(@PathParam("name") String databagName);
/**
* @see ChefClient#listDatabagItems
*/
@GET
@Path("/data/{name}")
@ResponseParser(ParseKeySetFromJson.class)
@ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
ListenableFuture<Set<String>> listDatabagItems(@PathParam("name") String databagName);
/**
* @see ChefClient#createDatabagItem
*/
@POST
@Path("/data/{databagName}")
ListenableFuture<DatabagItem> createDatabagItem(@PathParam("databagName") String databagName,
@BinderParam(BindToJsonPayload.class) DatabagItem databagItem);
/**
* @see ChefClient#updateDatabagItem
*/
@PUT
@Path("/data/{databagName}/{databagItemId}")
ListenableFuture<DatabagItem> updateDatabagItem(
@PathParam("databagName") String databagName,
@PathParam("databagItemId") @ParamParser(DatabagItemId.class) @BinderParam(BindToJsonPayload.class) DatabagItem item);
/**
* @see ChefClient#databagItemExists
*/
@HEAD
@Path("/data/{databagName}/{databagItemId}")
@ExceptionParser(ReturnFalseOnNotFoundOr404.class)
ListenableFuture<Boolean> databagItemExists(@PathParam("databagName") String databagName,
@PathParam("databagItemId") String databagItemId);
/**
* @see ChefClient#getDatabagItem
*/
@GET
@Path("/data/{databagName}/{databagItemId}")
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
ListenableFuture<DatabagItem> getDatabagItem(@PathParam("databagName") String databagName,
@PathParam("databagItemId") String databagItemId);
/**
* @see ChefClient#deleteDatabagItem
*/
@DELETE
@Path("/data/{databagName}/{databagItemId}")
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
ListenableFuture<DatabagItem> deleteDatabagItem(@PathParam("databagName") String databagName,
@PathParam("databagItemId") String databagItemId);
/**
* @see ChefClient#listSearchIndexes
*/
@GET
@Path("/search")
@ResponseParser(ParseKeySetFromJson.class)
@ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
ListenableFuture<Set<String>> listSearchIndexes();
/**
* @see ChefClient#searchRoles
*/
@GET
@Path("/search/role")
@ResponseParser(ParseSearchRolesFromJson.class)
ListenableFuture<? extends SearchResult<? extends Role>> searchRoles();
/**
* @see ChefClient#searchClients
*/
@GET
@Path("/search/client")
@ResponseParser(ParseSearchClientsFromJson.class)
ListenableFuture<? extends SearchResult<? extends Client>> searchClients();
/**
* @see ChefClient#searchNodes
*/
@GET
@Path("/search/node")
@ResponseParser(ParseSearchNodesFromJson.class)
ListenableFuture<? extends SearchResult<? extends Node>> searchNodes();
/**
* @see ChefClient#searchDatabag
*/
@GET
@Path("/search/{databagName}")
@ResponseParser(ParseSearchDatabagFromJson.class)
ListenableFuture<? extends SearchResult<? extends DatabagItem>> searchDatabag(
@PathParam("databagName") String databagName);
}

View File

@ -1,533 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import org.jclouds.chef.domain.Client;
import org.jclouds.chef.domain.CookbookVersion;
import org.jclouds.chef.domain.DatabagItem;
import org.jclouds.chef.domain.Node;
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.concurrent.Timeout;
import org.jclouds.http.HttpResponseException;
import org.jclouds.rest.AuthorizationException;
import org.jclouds.rest.annotations.BinderParam;
import org.jclouds.rest.binders.BindToJsonPayload;
/**
* Provides synchronous access to Chef.
* <p/>
*
* @see ChefAsyncClient
* @see <a href="TODO: insert URL of Chef documentation" />
* @author Adrian Cole
*/
@Timeout(duration = 30, timeUnit = TimeUnit.SECONDS)
public interface ChefClient {
/**
*
* FIXME Comment this
*
* @param md5s
* raw md5s; uses {@code Bytes.asList()} and {@code
* Bytes.toByteArray()} as necessary
* @return
*/
UploadSandbox getUploadSandboxForChecksums(Set<List<Byte>> md5s);
Sandbox commitSandbox(String id, boolean isCompleted);
/**
*
* @return a list of all the cookbook names
* @throws AuthorizationException
* <p/>
* "401 Unauthorized" if the caller is not a recognized user.
* <p/>
* "403 Forbidden" if you do not have permission to see the
* cookbook list.
*/
Set<String> listCookbooks();
/**
* Creates or updates (uploads) a cookbook //TODO document
*
* @param cookbookName
* @throws HttpResponseException
* "409 Conflict" if the cookbook already exists
*/
@Timeout(duration = 10, timeUnit = TimeUnit.MINUTES)
CookbookVersion updateCookbook(String cookbookName, String version, CookbookVersion cookbook);
/**
* deletes an existing cookbook.
*
* @return last state of the client you deleted or null, if not found
* @throws AuthorizationException
* <p/>
* "401 Unauthorized" if you are not a recognized user.
* <p/>
* "403 Forbidden" if you do not have Delete rights on the
* cookbook.
*/
CookbookVersion deleteCookbook(String cookbookName, String version);
/**
*
* @return the versions of a cookbook or null, if not found
*
* @throws AuthorizationException
* <p/>
* "401 Unauthorized" if the caller is not a recognized user.
* <p/>
* "403 Forbidden" if the caller is not authorized to view the
* cookbook.
*/
Set<String> getVersionsOfCookbook(String cookbookName);
/**
* Returns a description of the cookbook, with links to all of its component
* parts, and the metadata.
*
* @return the cookbook or null, if not found
*
* @throws AuthorizationException
* <p/>
* "401 Unauthorized" if the caller is not a recognized user.
* <p/>
* "403 Forbidden" if the caller is not authorized to view the
* cookbook.
*/
CookbookVersion getCookbook(String cookbookName, String version);
/**
* creates a new client
*
* @return the private key of the client. You can then use this client name
* and private key to access the Opscode API.
* @throws AuthorizationException
* <p/>
* "401 Unauthorized" if the caller is not a recognized user.
* <p/>
* "403 Forbidden" if the caller is not authorized to create a
* client.
* @throws HttpResponseException
* "409 Conflict" if the client already exists
*/
@Timeout(duration = 120, timeUnit = TimeUnit.SECONDS)
Client createClient(String name);
/**
* generate a new key-pair for this client, and return the new private key in
* the response body.
*
* @return the new private key
*
* @throws AuthorizationException
* <p/>
* "401 Unauthorized" if the caller is not a recognized user.
* <p/>
* "403 Forbidden" if the caller is not authorized to modify the
* client.
*/
@Timeout(duration = 120, timeUnit = TimeUnit.SECONDS)
Client generateKeyForClient(String name);
/**
* @return list of client names.
*
* @throws AuthorizationException
* <p/>
* "401 Unauthorized" if you are not a recognized user.
* <p/>
* "403 Forbidden" if you do not have rights to list clients.
*/
Set<String> listClients();
/**
*
* @return true if the specified client name exists.
*
* @throws AuthorizationException
* <p/>
* "401 Unauthorized" if you are not a recognized user.
* <p/>
* "403 Forbidden" if you do not have rights to view the client.
*/
boolean clientExists(String name);
/**
* deletes an existing client.
*
* @return last state of the client you deleted or null, if not found
*
* @throws AuthorizationException
* <p/>
* "401 Unauthorized" if you are not a recognized user.
* <p/>
* "403 Forbidden" if you do not have Delete rights on the client.
*/
Client deleteClient(String name);
/**
* gets an existing client.
*
* @throws AuthorizationException
* <p/>
* "401 Unauthorized" if you are not a recognized user.
* <p/>
* "403 Forbidden" if you do not have view rights on the client.
*/
Client getClient(String name);
/**
* creates a new node
*
* @return //TODO
* @throws AuthorizationException
* <p/>
* "401 Unauthorized" if the caller is not a recognized user.
* <p/>
* "403 Forbidden" if the caller is not authorized to create a
* node.
* @throws HttpResponseException
* "409 Conflict" if the node already exists
*/
@Timeout(duration = 120, timeUnit = TimeUnit.SECONDS)
void createNode(Node node);
/**
* Creates or updates (uploads) a node //TODO document
*
* @param nodeName
* @throws HttpResponseException
* "409 Conflict" if the node already exists
*/
@Timeout(duration = 10, timeUnit = TimeUnit.MINUTES)
Node updateNode(Node node);
/**
* @return list of node names.
*
* @throws AuthorizationException
* <p/>
* "401 Unauthorized" if you are not a recognized user.
* <p/>
* "403 Forbidden" if you do not have rights to list nodes.
*/
Set<String> listNodes();
/**
*
* @return true if the specified node name exists.
*
* @throws AuthorizationException
* <p/>
* "401 Unauthorized" if you are not a recognized user.
* <p/>
* "403 Forbidden" if you do not have rights to view the node.
*/
boolean nodeExists(String name);
/**
* deletes an existing node.
*
* @return last state of the node you deleted or null, if not found
*
* @throws AuthorizationException
* <p/>
* "401 Unauthorized" if you are not a recognized user.
* <p/>
* "403 Forbidden" if you do not have Delete rights on the node.
*/
Node deleteNode(String name);
/**
* gets an existing node.
*
* @throws AuthorizationException
* <p/>
* "401 Unauthorized" if you are not a recognized user.
* <p/>
* "403 Forbidden" if you do not have view rights on the node.
*/
Node getNode(String name);
/**
* creates a new role
*
* @return //TODO
* @throws AuthorizationException
* <p/>
* "401 Unauthorized" if the caller is not a recognized user.
* <p/>
* "403 Forbidden" if the caller is not authorized to create a
* role.
* @throws HttpResponseException
* "409 Conflict" if the role already exists
*/
@Timeout(duration = 120, timeUnit = TimeUnit.SECONDS)
void createRole(Role role);
/**
* Creates or updates (uploads) a role //TODO document
*
* @param roleName
* @throws HttpResponseException
* "409 Conflict" if the role already exists
*/
@Timeout(duration = 10, timeUnit = TimeUnit.MINUTES)
Role updateRole(Role role);
/**
* @return list of role names.
*
* @throws AuthorizationException
* <p/>
* "401 Unauthorized" if you are not a recognized user.
* <p/>
* "403 Forbidden" if you do not have rights to list roles.
*/
Set<String> listRoles();
/**
*
* @return true if the specified role name exists.
*
* @throws AuthorizationException
* <p/>
* "401 Unauthorized" if you are not a recognized user.
* <p/>
* "403 Forbidden" if you do not have rights to view the role.
*/
boolean roleExists(String name);
/**
* deletes an existing role.
*
* @return last state of the role you deleted or null, if not found
*
* @throws AuthorizationException
* <p/>
* "401 Unauthorized" if you are not a recognized user.
* <p/>
* "403 Forbidden" if you do not have Delete rights on the role.
*/
Role deleteRole(String name);
/**
* gets an existing role.
*
* @throws AuthorizationException
* <p/>
* "401 Unauthorized" if you are not a recognized user.
* <p/>
* "403 Forbidden" if you do not have view rights on the role.
*/
Role getRole(String name);
/**
* lists databags available to the client
*
* @throws AuthorizationException
* <p/>
* "401 Unauthorized" if you are not a recognized user.
* <p/>
* "403 Forbidden" if you do not have view rights on the databag.
*/
Set<String> listDatabags();
/**
* creates a databag.
*
* @throws AuthorizationException
* <p/>
* "401 Unauthorized" if you are not a recognized user.
* <p/>
* "403 Forbidden" if you do not have view rights on the databag.
*/
void createDatabag(String databagName);
/**
* true is a databag exists
*
* @throws AuthorizationException
* <p/>
* "401 Unauthorized" if you are not a recognized user.
* <p/>
* "403 Forbidden" if you do not have view rights on the databag.
*/
boolean databagExists(String databagName);
/**
* Delete a data bag, including its items
*
* @throws AuthorizationException
* <p/>
* "401 Unauthorized" if you are not a recognized user.
* <p/>
* "403 Forbidden" if you do not have view rights on the databag.
*/
void deleteDatabag(String databagName);
/**
* Show the items in a data bag.
*
* @throws AuthorizationException
* <p/>
* "401 Unauthorized" if you are not a recognized user.
* <p/>
* "403 Forbidden" if you do not have view rights on the databag.
*/
Set<String> listDatabagItems(String databagName);
/**
* Create a data bag item in the data bag
*
* @throws AuthorizationException
* <p/>
* "401 Unauthorized" if you are not a recognized user.
* <p/>
* "403 Forbidden" if you do not have view rights on the databag.
* <p/>
* @throws IllegalStateException
* if the item already exists
*
*/
DatabagItem createDatabagItem(String databagName, @BinderParam(BindToJsonPayload.class) DatabagItem node);
/**
* Update (or create if not exists) a data bag item
*
* @throws AuthorizationException
* <p/>
* "401 Unauthorized" if you are not a recognized user.
* <p/>
* "403 Forbidden" if you do not have view rights on the databag.
*/
DatabagItem updateDatabagItem(String databagName, DatabagItem item);
/**
* determines if a databag item exists
*
* @throws AuthorizationException
* <p/>
* "401 Unauthorized" if you are not a recognized user.
* <p/>
* "403 Forbidden" if you do not have view rights on the databag.
*/
boolean databagItemExists(String databagName, String databagItemId);
/**
* gets an existing databag item.
*
* @throws AuthorizationException
* <p/>
* "401 Unauthorized" if you are not a recognized user.
* <p/>
* "403 Forbidden" if you do not have view rights on the databag.
*/
DatabagItem getDatabagItem(String databagName, String databagItemId);
/**
* Delete a data bag item
*
* @throws AuthorizationException
* <p/>
* "401 Unauthorized" if you are not a recognized user.
* <p/>
* "403 Forbidden" if you do not have view rights on the databag.
*/
DatabagItem deleteDatabagItem(String databagName, String databagItemId);
/**
* Show indexes you can search on
* <p/>
* By default, the "role", "node" and "client" 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.)
*
* @throws AuthorizationException
* <p/>
* "401 Unauthorized" if you are not a recognized user.
* <p/>
* "403 Forbidden" if you do not have view rights on the databag.
*/
Set<String> listSearchIndexes();
/**
* search 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 your
* request, the position this result set returns (useful for paging)
* and the rows themselves.
*/
SearchResult<? extends Role> searchRoles();
/**
* search 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 your
* request, the position this result set returns (useful for paging)
* and the rows themselves.
*/
SearchResult<? extends Client> searchClients();
/**
* search 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 your
* request, the position this result set returns (useful for paging)
* and the rows themselves.
*/
SearchResult<? extends Node> searchNodes();
/**
* search all items in a databag.
* <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 your
* request, the position this result set returns (useful for paging)
* and the rows themselves.
*/
SearchResult<? extends DatabagItem> searchDatabag(String databagName);
}

View File

@ -1,38 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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 org.jclouds.chef.internal.ChefContextImpl;
import org.jclouds.rest.RestContext;
import com.google.inject.ImplementedBy;
/**
*
*
* @author Adrian Cole
*
*/
@ImplementedBy(ChefContextImpl.class)
public interface ChefContext extends RestContext<ChefClient, ChefAsyncClient>{
ChefService getChefService();
}

View File

@ -1,65 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.util.List;
import java.util.Properties;
import org.jclouds.chef.config.ChefRestClientModule;
import org.jclouds.ohai.OhaiContextBuilder;
import com.google.inject.Injector;
import com.google.inject.Module;
/**
* @author Adrian Cole
*/
public class ChefContextBuilder extends OhaiContextBuilder<ChefClient, ChefAsyncClient> {
public ChefContextBuilder(Properties props) {
super(ChefClient.class, ChefAsyncClient.class, props);
}
@Override
protected void addClientModule(List<Module> modules) {
modules.add(new ChefRestClientModule());
}
@Override
public Injector buildInjector() {
addOhaiModuleIfNotPresent();
return super.buildInjector();
}
/**
* {@inheritDoc}
*/
@Override
public ChefContextBuilder withModules(Iterable<Module> modules) {
return (ChefContextBuilder) super.withModules(modules);
}
@SuppressWarnings("unchecked")
@Override
public ChefContext buildContext() {
Injector injector = buildInjector();
return injector.getInstance(ChefContext.class);
}
}

View File

@ -1,180 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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 org.jclouds.rest.RestContextFactory.createContextBuilder;
import static org.jclouds.util.Utils.propagateAuthorizationOrOriginalException;
import java.util.Properties;
import javax.annotation.Nullable;
import org.jclouds.rest.RestContextBuilder;
import org.jclouds.rest.RestContextFactory;
import org.jclouds.rest.RestContextFactory.ContextSpec;
import com.google.inject.Module;
/**
* Helper class to instantiate {@code ChefContext} instances.
*
* @author Adrian Cole
*/
public class ChefContextFactory {
private final RestContextFactory contextFactory;
/**
* Initializes with the default properties built-in to jclouds. This is
* typically stored in the classpath resource {@code rest.properties}
*
* @see RestContextFactory#getPropertiesFromResource
*/
public ChefContextFactory() {
this(new RestContextFactory());
}
/**
* Finds definitions in the specified properties.
*/
public ChefContextFactory(Properties properties) {
this(new RestContextFactory(properties));
}
/**
*
* Uses the supplied RestContextFactory to create {@link ChefContext}s
*/
public ChefContextFactory(RestContextFactory restContextFactory) {
this.contextFactory = restContextFactory;
}
public static <S, A> ChefContext buildContextUnwrappingExceptions(RestContextBuilder<S, A> builder) {
try {
return (ChefContext) builder.buildContext();
} catch (Exception e) {
return propagateAuthorizationOrOriginalException(e);
}
}
/**
* @see #createContext(String, String, String)
*/
public ChefContext createContext(String identity, String credential) {
return createContext("chef", identity, credential);
}
/**
* @see RestContextFactory#createContextBuilder(String, String, String)
*/
public ChefContext createContext(String provider, String identity, String credential) {
RestContextBuilder<?, ?> builder = RestContextBuilder.class.cast(contextFactory.createContextBuilder(provider,
identity, credential));
return buildContextUnwrappingExceptions(builder);
}
/**
* @see #createContext(String, Properties)
*/
public ChefContext createContext(Properties overrides) {
return createContext("chef", overrides);
}
/**
* @see RestContextFactory#createContextBuilder(String, Properties)
*/
public ChefContext createContext(String provider, Properties overrides) {
RestContextBuilder<?, ?> builder = RestContextBuilder.class.cast(contextFactory.createContextBuilder(provider,
overrides));
return buildContextUnwrappingExceptions(builder);
}
/**
* @see #createContext(String, Iterable, Properties)
*/
public ChefContext createContext(Iterable<? extends Module> modules, Properties overrides) {
return createContext("chef", modules, overrides);
}
/**
* @see RestContextFactory#createContextBuilder(String, Iterable, Properties)
*/
public ChefContext createContext(String provider, Iterable<? extends Module> modules, Properties overrides) {
RestContextBuilder<?, ?> builder = RestContextBuilder.class.cast(contextFactory.createContextBuilder(provider,
modules, overrides));
return buildContextUnwrappingExceptions(builder);
}
/**
* @see #createContext(String,String,String,Iterable)
*/
public ChefContext createContext(@Nullable String identity, @Nullable String credential,
Iterable<? extends Module> modules) {
return createContext("chef", identity, credential, modules);
}
/**
* @see RestContextFactory#createContextBuilder(String,String String,
* Iterable)
*/
public ChefContext createContext(String provider, @Nullable String identity, @Nullable String credential,
Iterable<? extends Module> modules) {
RestContextBuilder<?, ?> builder = RestContextBuilder.class.cast(contextFactory.createContextBuilder(provider,
identity, credential, modules));
return buildContextUnwrappingExceptions(builder);
}
/**
* @see #createContext(String,String, String, Iterable, Properties)
*/
public ChefContext createContext(@Nullable String identity, @Nullable String credential,
Iterable<? extends Module> modules, Properties overrides) {
return createContext("chef", identity, credential, modules, overrides);
}
/**
* @see RestContextFactory#createContextBuilder(String,String,String,
* Iterable, Properties)
*/
public ChefContext createContext(String provider, @Nullable String identity, @Nullable String credential,
Iterable<? extends Module> modules, Properties overrides) {
RestContextBuilder<?, ?> builder = RestContextBuilder.class.cast(contextFactory.createContextBuilder(provider,
identity, credential, modules, overrides));
return buildContextUnwrappingExceptions(builder);
}
/**
* @see RestContextFactory#createContextBuilder(ContextSpec)
*/
public <S, A> ChefContext createContext(ContextSpec<S, A> contextSpec) {
RestContextBuilder<?, ?> builder = RestContextBuilder.class.cast(createContextBuilder(contextSpec));
return buildContextUnwrappingExceptions(builder);
}
/**
* @see RestContextFactory#createContextBuilder(ContextSpec, Properties)
*/
public <S, A> ChefContext createContext(ContextSpec<S, A> contextSpec, Properties overrides) {
RestContextBuilder<?, ?> builder = RestContextBuilder.class.cast(createContextBuilder(contextSpec, overrides));
return buildContextUnwrappingExceptions(builder);
}
}

View File

@ -1,45 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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 org.jclouds.Constants.PROPERTY_ENDPOINT;
import java.util.Properties;
import org.jclouds.chef.internal.BaseChefPropertiesBuilder;
/**
* Builds properties used in Chef Clients
*
* @author Adrian Cole
*/
public class ChefPropertiesBuilder extends BaseChefPropertiesBuilder {
@Override
protected Properties defaultProperties() {
Properties properties = super.defaultProperties();
properties.setProperty(PROPERTY_ENDPOINT, "http://localhost:4000");
return properties;
}
public ChefPropertiesBuilder(Properties properties) {
super(properties);
}
}

View File

@ -1,122 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.IOException;
import java.io.InputStream;
import java.util.List;
import org.jclouds.chef.domain.Client;
import org.jclouds.chef.domain.CookbookVersion;
import org.jclouds.chef.domain.Node;
import org.jclouds.chef.internal.BaseChefService;
import org.jclouds.io.Payload;
import com.google.common.base.Predicate;
import com.google.common.io.InputSupplier;
import com.google.inject.ImplementedBy;
/**
* Provides high level chef operations
*
* @author Adrian Cole
*/
@ImplementedBy(BaseChefService.class)
public interface ChefService {
/**
* @return a reference to the context that created this.
*/
ChefContext getContext();
byte[] encrypt(InputSupplier<? extends InputStream> supplier) throws IOException;
byte[] decrypt(InputSupplier<? extends InputStream> supplier) throws IOException;
void cleanupStaleNodesAndClients(String prefix, int secondsStale);
/**
*
* @param nodeName
* @param runList
* @return node sent to the server containing the automatic attributes
*/
Node createNodeAndPopulateAutomaticAttributes(String nodeName, Iterable<String> runList);
/**
* Creates all steps necessary to bootstrap and run the chef client.
*
* @param tag
* corresponds to a configured
* {@link org.jclouds.chef.reference.ChefConstants#CHEF_BOOTSTRAP_DATABAG databag}
* where run_list and other information are stored
* @return boot script
* @see #updateRunListForTag
*/
Payload createClientAndBootstrapScriptForTag(String tag);
/**
* assigns a run list to all nodes bootstrapped with a certain tag
*
* @param runList
* list of recipes or roles to assign. syntax is {@code recipe[name]} and {@code
* role[name]}
*
* @param tag
* corresponds to a configured
* {@link org.jclouds.chef.reference.ChefConstants#CHEF_BOOTSTRAP_DATABAG databag}
* where run_list and other information are stored
* @see #makeChefClientBootstrapScriptForTag
*/
void updateRunListForTag(Iterable<String> runList, String tag);
/**
* @param tag
* corresponds to a configured
* {@link org.jclouds.chef.reference.ChefConstants#CHEF_BOOTSTRAP_DATABAG databag}
* where run_list and other information are stored
* @return run list for all nodes bootstrapped with a certain tag
* @see #updateRunListForTag
*/
List<String> getRunListForTag(String tag);
void deleteAllNodesInList(Iterable<String> names);
Iterable<? extends Node> listNodes();
Iterable<? extends Node> listNodesMatching(Predicate<String> nodeNameSelector);
Iterable<? extends Node> listNodesNamed(Iterable<String> names);
void deleteAllClientsInList(Iterable<String> names);
Iterable<? extends Client> listClientsDetails();
Iterable<? extends Client> listClientsDetailsMatching(Predicate<String> clientNameSelector);
Iterable<? extends Client> listClientsNamed(Iterable<String> names);
Iterable<? extends CookbookVersion> listCookbookVersions();
Iterable<? extends CookbookVersion> listCookbookVersionsMatching(Predicate<String> cookbookNameSelector);
Iterable<? extends CookbookVersion> listCookbookVersionsNamed(Iterable<String> cookbookNames);
void updateAutomaticAttributesOnNode(String nodeName);
}

View File

@ -1,62 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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 java.util.List;
import java.util.Set;
import javax.inject.Singleton;
import javax.ws.rs.core.MediaType;
import org.jclouds.crypto.CryptoStreams;
import org.jclouds.http.HttpRequest;
import org.jclouds.rest.binders.BindToStringPayload;
import com.google.common.primitives.Bytes;
/**
*
*
* @author Adrian Cole
*/
@Singleton
public class BindChecksumsToJsonPayload extends BindToStringPayload {
@SuppressWarnings("unchecked")
public void 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,", CryptoStreams.hex(Bytes.toArray(md5))));
builder.deleteCharAt(builder.length() - 1);
builder.append("}}");
super.bindToRequest(request, builder.toString());
request.getPayload().setContentType(MediaType.APPLICATION_JSON);
}
}

View File

@ -1,42 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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;
/**
*
* @author Adrian Cole
*
*/
@Singleton
public class BindClientnameToJsonPayload extends BindToStringPayload {
@Override
public void bindToRequest(HttpRequest request, Object payload) {
super.bindToRequest(request, String.format("{\"clientname\":\"%s\"}", payload));
request.getPayload().setContentType(MediaType.APPLICATION_JSON);
}
}

View File

@ -1,43 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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;
/**
*
* @author Adrian Cole
*
*/
@Singleton
public class BindGenerateKeyForClientToJsonPayload extends BindToStringPayload {
@Override
public void bindToRequest(HttpRequest request, Object payload) {
super.bindToRequest(request, String.format("{\"clientname\":\"%s\", \"private_key\": true}",
payload));
request.getPayload().setContentType(MediaType.APPLICATION_JSON);
}
}

View File

@ -1,42 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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;
/**
*
* @author Adrian Cole
*
*/
@Singleton
public class BindIsCompletedToJsonPayload extends BindToStringPayload {
@Override
public void bindToRequest(HttpRequest request, Object value) {
super.bindToRequest(request, String.format("{\"is_completed\":\"%s\"}", value));
request.getPayload().setContentType(MediaType.APPLICATION_JSON);
}
}

View File

@ -1,42 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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;
/**
*
* @author Adrian Cole
*
*/
@Singleton
public class BindNameToJsonPayload extends BindToStringPayload {
@Override
public void bindToRequest(HttpRequest request, Object payload) {
super.bindToRequest(request, String.format("{\"name\":\"%s\"}", payload));
request.getPayload().setContentType(MediaType.APPLICATION_JSON);
}
}

View File

@ -1,39 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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;
/**
*
* @author Adrian Cole
*/
@Singleton
public class DatabagItemId implements Function<Object, String> {
public String apply(Object from) {
return ((DatabagItem) from).getId();
}
}

View File

@ -1,39 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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;
/**
*
* @author Adrian Cole
*/
@Singleton
public class NodeName implements Function<Object, String> {
public String apply(Object from) {
return ((Node) from).getName();
}
}

View File

@ -1,39 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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;
/**
*
* @author Adrian Cole
*/
@Singleton
public class RoleName implements Function<Object, String> {
public String apply(Object from) {
return ((Role) from).getName();
}
}

View File

@ -1,116 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.Constants.PROPERTY_CREDENTIAL;
import static org.jclouds.Constants.PROPERTY_SESSION_INTERVAL;
import java.io.IOException;
import java.security.PrivateKey;
import java.security.spec.InvalidKeySpecException;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import javax.inject.Named;
import javax.inject.Singleton;
import org.jclouds.chef.handlers.ChefClientErrorRetryHandler;
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.http.HttpErrorHandler;
import org.jclouds.http.HttpRetryHandler;
import org.jclouds.http.RequiresHttp;
import org.jclouds.http.annotation.ClientError;
import org.jclouds.http.annotation.Redirection;
import org.jclouds.http.annotation.ServerError;
import org.jclouds.io.InputSuppliers;
import org.jclouds.rest.ConfiguresRestClient;
import org.jclouds.rest.config.RestClientModule;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
import com.google.inject.Provides;
/**
* Configures the Chef connection.
*
* @author Adrian Cole
*/
@RequiresHttp
@ConfiguresRestClient
public class BaseChefRestClientModule<S, A> extends RestClientModule<S, A> {
protected BaseChefRestClientModule(Class<S> syncClientType, Class<A> asyncClientType) {
super(syncClientType, asyncClientType);
}
protected BaseChefRestClientModule(Class<S> syncClientType, Class<A> asyncClientType,
Map<Class<?>, Class<?>> delegates) {
super(syncClientType, asyncClientType, delegates);
}
@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 Suppliers.memoizeWithExpiration(new Supplier<String>() {
public String get() {
return dateService.iso8601SecondsDateFormat();
}
}, seconds, TimeUnit.SECONDS);
}
@Provides
@Singleton
public PrivateKey provideKey(Crypto crypto, @Named(PROPERTY_CREDENTIAL) String pem) throws InvalidKeySpecException,
IOException {
return crypto.rsaKeyFactory().generatePrivate(Pems.privateKeySpec(InputSuppliers.of(pem)));
}
@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(ChefClientErrorRetryHandler.class);
}
@Override
protected void configure() {
install(new ChefParserModule());
super.configure();
}
}

View File

@ -1,226 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.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 javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import org.jclouds.Constants;
import org.jclouds.chef.domain.DatabagItem;
import org.jclouds.crypto.Crypto;
import org.jclouds.crypto.Pems;
import org.jclouds.io.InputSuppliers;
import org.jclouds.json.Json;
import org.jclouds.json.config.GsonModule.DateAdapter;
import org.jclouds.json.config.GsonModule.Iso8601DateAdapter;
import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableMap;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonLiteral;
import com.google.gson.JsonParseException;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
import com.google.inject.AbstractModule;
import com.google.inject.ImplementedBy;
import com.google.inject.Provides;
/**
*
*
* @author Adrian Cole
*/
public class ChefParserModule extends AbstractModule {
@ImplementedBy(PrivateKeyAdapterImpl.class)
public static 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(InputSuppliers.of(keyText)));
} 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 static 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(InputSuppliers.of(keyText)));
} 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 static 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(InputSuppliers.of(keyText), 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;
}
}
}
@ImplementedBy(DataBagItemAdapterImpl.class)
public static interface DataBagItemAdapter extends JsonSerializer<DatabagItem>, JsonDeserializer<DatabagItem> {
}
@Singleton
public static class DataBagItemAdapterImpl implements DataBagItemAdapter {
private final Json json;
@Inject
DataBagItemAdapterImpl(Json json) {
this.json = json;
}
@Override
public JsonElement serialize(DatabagItem src, Type typeOfSrc, JsonSerializationContext context) {
String text = src.toString();
try {
IdHolder idHolder = json.fromJson(text, IdHolder.class);
if (idHolder.id == null)
text = text.replaceFirst("\\{", String.format("{\"id\":\"%s\",", src.getId()));
else
checkArgument(src.getId().equals(idHolder.id), "incorrect id in databagItem text, should be %s: was %s",
src.getId(), idHolder.id);
return new JsonLiteral(text);
} catch (JsonParseException e) {
throw new IllegalArgumentException(String.format(
"databag item must be a json hash ex. {\"id\":\"item1\",\"my_key\":\"my_data\"}; was %s", text), e);
}
}
@Override
public DatabagItem deserialize(JsonElement jsonElement, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
String text = jsonElement.toString();
IdHolder idHolder = json.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);
}
}
private static class IdHolder {
private String id;
}
@Provides
@Singleton
@Named(Constants.PROPERTY_GSON_ADAPTERS)
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);
}
@Override
protected void configure() {
bind(DateAdapter.class).to(Iso8601DateAdapter.class);
}
}

View File

@ -1,72 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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 java.util.List;
import java.util.Map;
import javax.inject.Singleton;
import org.jclouds.chef.ChefAsyncClient;
import org.jclouds.chef.ChefClient;
import org.jclouds.chef.domain.Client;
import org.jclouds.chef.functions.ClientForTag;
import org.jclouds.chef.functions.RunListForTag;
import org.jclouds.chef.statements.InstallChefGems;
import org.jclouds.http.RequiresHttp;
import org.jclouds.rest.ConfiguresRestClient;
import org.jclouds.scriptbuilder.domain.Statement;
import com.google.common.collect.MapMaker;
import com.google.inject.Provides;
import com.google.inject.name.Names;
/**
* Configures the Chef connection.
*
* @author Adrian Cole
*/
@RequiresHttp
@ConfiguresRestClient
public class ChefRestClientModule extends BaseChefRestClientModule<ChefClient, ChefAsyncClient> {
public ChefRestClientModule() {
super(ChefClient.class, ChefAsyncClient.class);
}
@Provides
@Singleton
Map<String, List<String>> runListForTag(RunListForTag runListForTag) {
return new MapMaker().makeComputingMap(runListForTag);
}
@Provides
@Singleton
Map<String, Client> tagToClient(ClientForTag tagToClient) {
return new MapMaker().makeComputingMap(tagToClient);
}
@Override
protected void configure() {
bind(Statement.class).annotatedWith(Names.named("installChefGems")).to(InstallChefGems.class);
super.configure();
}
}

View File

@ -1,167 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.List;
import java.util.Set;
import org.jclouds.domain.JsonBall;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.gson.annotations.SerializedName;
/**
* Cookbook object.
*
* @author Adrian Cole
*/
public class Attribute {
private String required;
private boolean calculated;
private List<String> choice = Lists.newArrayList();
@SerializedName("default")
private JsonBall defaultValue;
private String type;
private List<String> recipes = Lists.newArrayList();
@SerializedName("display_name")
private String displayName;
private String description;
public Attribute(String required, boolean calculated, Set<String> choice, JsonBall defaultValue, String type,
List<String> recipes, String displayName, String description) {
this.required = required;
this.calculated = calculated;
Iterables.addAll(this.choice, choice);
this.defaultValue = defaultValue;
this.type = type;
Iterables.addAll(this.recipes, recipes);
this.displayName = displayName;
this.description = description;
}
public Attribute() {
}
public String getRequired() {
return required;
}
public boolean isCalculated() {
return calculated;
}
public List<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

@ -1,84 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.net.URI;
import com.google.gson.annotations.SerializedName;
/**
*
* @author Adrian Cole
*/
public class ChecksumStatus {
private URI url;
@SerializedName("needs_upload")
private boolean needsUpload;
public ChecksumStatus(URI url, boolean needsUpload) {
this.url = url;
this.needsUpload = needsUpload;
}
public ChecksumStatus() {
}
public URI getUrl() {
return url;
}
public boolean needsUpload() {
return needsUpload;
}
@Override
public String toString() {
return "ChecksumStatus [needsUpload=" + needsUpload + ", url=" + url + "]";
}
@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;
}
}

View File

@ -1,140 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.security.PrivateKey;
import java.security.cert.X509Certificate;
import javax.annotation.Nullable;
import com.google.gson.annotations.SerializedName;
/**
* Client object.
*
* @author Adrian Cole
*/
public class Client {
private X509Certificate certificate;
@SerializedName("private_key")
private PrivateKey privateKey;
private String orgname;
private String clientname;
private String name;
private boolean validator;
// only for deserialization
Client() {
}
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 String toString() {
return "[name=" + name + ", clientname=" + clientname + ", orgname=" + orgname + ", isValidator=" + validator
+ ", certificate=" + certificate + ", privateKey=" + (privateKey != null) + "]";
}
@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;
}
public Client(X509Certificate certificate, String orgname, String clientname, String name, boolean isValidator,
@Nullable PrivateKey privateKey) {
this.certificate = certificate;
this.orgname = orgname;
this.clientname = clientname;
this.name = name;
this.validator = isValidator;
this.privateKey = privateKey;
}
}

View File

@ -1,246 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.Set;
import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;
import com.google.gson.annotations.SerializedName;
/**
* Cookbook object.
*
* @author Adrian Cole
*/
public class CookbookVersion {
private String name;
private Set<Resource> definitions = Sets.newLinkedHashSet();
private Set<Attribute> attributes = Sets.newLinkedHashSet();
private Set<Resource> files = Sets.newLinkedHashSet();
private Metadata metadata = new Metadata();
private Set<Resource> providers = Sets.newLinkedHashSet();
@SerializedName("cookbook_name")
private String cookbookName;
private Set<Resource> resources = Sets.newLinkedHashSet();
private Set<Resource> templates = Sets.newLinkedHashSet();
private Set<Resource> libraries = Sets.newLinkedHashSet();
private String version;
private Set<Resource> recipes = Sets.newLinkedHashSet();
@SerializedName("root_files")
private Set<Resource> rootFiles = Sets.newLinkedHashSet();
// internal
@SuppressWarnings("unused")
@SerializedName("json_class")
private String _jsonClass = "Chef::CookbookVersion";
@SerializedName("chef_type")
@SuppressWarnings("unused")
private String _chefType = "cookbook_version";
public CookbookVersion(String cookbookName, String version) {
this.cookbookName = cookbookName;
this.version = version;
this.name = cookbookName + "-" + version;
}
public CookbookVersion(String name, Set<Resource> definitions, Set<Attribute> attributes, Set<Resource> files,
Metadata metadata, Set<Resource> providers, String cookbookName, Set<Resource> resources,
Set<Resource> templates, Set<Resource> libraries, String version, Set<Resource> recipes,
Set<Resource> rootFiles) {
this.name = name;
Iterables.addAll(this.definitions, definitions);
Iterables.addAll(this.attributes, attributes);
Iterables.addAll(this.files, files);
this.metadata = metadata;
Iterables.addAll(this.providers, providers);
this.cookbookName = cookbookName;
Iterables.addAll(this.resources, resources);
Iterables.addAll(this.templates, templates);
Iterables.addAll(this.libraries, libraries);
this.version = version;
Iterables.addAll(this.recipes, recipes);
Iterables.addAll(this.rootFiles, rootFiles);
}
// hidden but needs to be here for json deserialization to work
CookbookVersion() {
}
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

@ -1,68 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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;
/**
*
* @author Adrian Cole
*/
public class DatabagItem extends JsonBall {
private static final long serialVersionUID = 7905637919304343493L;
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

@ -1,281 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.Map;
import java.util.Set;
import com.google.common.collect.Maps;
import com.google.gson.annotations.SerializedName;
/**
* Cookbook object.
*
* @author Adrian Cole
*/
public class Metadata {
private String license;
private String maintainer;
private Map<String, String> suggestions = Maps.newLinkedHashMap();
private Map<String, Set<String>> dependencies = Maps.newLinkedHashMap();
@SerializedName("maintainer_email")
private String maintainerEmail;
private Map<String, Set<String>> conflicting = Maps.newLinkedHashMap();
private String description;
private Map<String, Set<String>> providing = Maps.newLinkedHashMap();
private Map<String, Set<String>> platforms = Maps.newLinkedHashMap();
private String version;
private Map<String, String> recipes = Maps.newLinkedHashMap();
private Map<String, Set<String>> replacing = Maps.newLinkedHashMap();
private String name;
private Map<String, String> groupings = Maps.newLinkedHashMap();
@SerializedName("long_description")
private String longDescription;
private Map<String, Attribute> attributes = Maps.newLinkedHashMap();
private Map<String, String> recommendations = Maps.newLinkedHashMap();
public Metadata(String license, String maintainer, Map<String, String> suggestions,
Map<String, Set<String>> dependencies, String maintainerEmail, Map<String, Set<String>> conflicting,
String description, Map<String, Set<String>> providing, Map<String, Set<String>> platforms, String version,
Map<String, String> recipes, Map<String, Set<String>> replacing, String name, Map<String, String> groupings,
String longDescription, Map<String, Attribute> attributes, Map<String, String> recommendations) {
this.license = license;
this.maintainer = maintainer;
this.suggestions.putAll(suggestions);
this.dependencies.putAll(dependencies);
this.maintainerEmail = maintainerEmail;
this.conflicting.putAll(conflicting);
this.description = description;
this.providing.putAll(providing);
this.platforms.putAll(platforms);
this.version = version;
this.recipes.putAll(recipes);
this.replacing.putAll(replacing);
this.name = name;
this.groupings.putAll(groupings);
this.longDescription = longDescription;
this.attributes.putAll(attributes);
this.recommendations.putAll(recommendations);
}
public Metadata() {
}
public String getLicense() {
return license;
}
public String getMaintainer() {
return maintainer;
}
public Map<String, String> getSuggestions() {
return suggestions;
}
public Map<String, Set<String>> getDependencies() {
return dependencies;
}
public String getMaintainerEmail() {
return maintainerEmail;
}
public Map<String, Set<String>> getConflicting() {
return conflicting;
}
public String getDescription() {
return description;
}
public Map<String, Set<String>> getProviding() {
return providing;
}
public Map<String, Set<String>> getPlatforms() {
return platforms;
}
public String getVersion() {
return version;
}
public Map<String, String> getRecipes() {
return recipes;
}
public Map<String, Set<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

@ -1,172 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.List;
import java.util.Map;
import org.jclouds.domain.JsonBall;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.gson.annotations.SerializedName;
/**
* Sandbox object.
*
* @author Adrian Cole
*/
public class Node {
private String name;
private Map<String, JsonBall> normal = Maps.newLinkedHashMap();
private Map<String, JsonBall> override = Maps.newLinkedHashMap();
@SerializedName("default")
private Map<String, JsonBall> defaultA = Maps.newLinkedHashMap();
private Map<String, JsonBall> automatic = Maps.newLinkedHashMap();
@SerializedName("run_list")
private List<String> runList = Lists.newArrayList();
// internal
@SerializedName("json_class")
private String _jsonClass = "Chef::Node";
public Node(String name, Map<String, JsonBall> normal, Map<String, JsonBall> override,
Map<String, JsonBall> defaultA, Map<String, JsonBall> automatic, Iterable<String> runList) {
this.name = name;
this.normal.putAll(normal);
this.override.putAll(override);
this.defaultA.putAll(defaultA);
this.automatic.putAll(automatic);
Iterables.addAll(this.runList, runList);
}
@Override
public String toString() {
return "Node [name=" + name + ", runList=" + runList + ", normal=" + normal + ", default=" + defaultA
+ ", override=" + override + ", automatic=" + automatic + "]";
}
public Node(String name, Iterable<String> runList) {
this.name = name;
Iterables.addAll(this.runList, runList);
}
// hidden but needs to be here for json deserialization to work
Node() {
}
public String getName() {
return name;
}
public Map<String, JsonBall> getNormal() {
return normal;
}
public Map<String, JsonBall> getOverride() {
return override;
}
public Map<String, JsonBall> getDefault() {
return defaultA;
}
public Map<String, JsonBall> getAutomatic() {
return automatic;
}
public List<String> getRunList() {
return runList;
}
@SerializedName("chef_type")
private String _chefType = "node";
@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 + ((automatic == null) ? 0 : automatic.hashCode());
result = prime * result + ((defaultA == null) ? 0 : defaultA.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + ((normal == null) ? 0 : normal.hashCode());
result = prime * result + ((override == null) ? 0 : override.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;
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 (automatic == null) {
if (other.automatic != null)
return false;
} else if (!automatic.equals(other.automatic))
return false;
if (defaultA == null) {
if (other.defaultA != null)
return false;
} else if (!defaultA.equals(other.defaultA))
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (normal == null) {
if (other.normal != null)
return false;
} else if (!normal.equals(other.normal))
return false;
if (override == null) {
if (other.override != null)
return false;
} else if (!override.equals(other.override))
return false;
if (runList == null) {
if (other.runList != null)
return false;
} else if (!runList.equals(other.runList))
return false;
return true;
}
}

View File

@ -1,135 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.net.URI;
import java.util.Arrays;
import org.jclouds.io.payloads.FilePayload;
import com.google.common.primitives.Bytes;
/**
* Cookbook object.
*
* @author Adrian Cole
*/
public class Resource {
private String name;
private URI url;
private byte[] checksum;
private String path;
private String specificity;
public Resource(FilePayload payload) {
this(payload.getRawContent().getName(), null, payload.getContentMD5(), payload
.getRawContent().getPath(), "default");
}
public Resource(String name, byte[] checksum, String path) {
this(name, null, checksum, path, "default");
}
public 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;
}
// hidden but needs to be here for json deserialization to work
Resource() {
}
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

@ -1,160 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.List;
import java.util.Map;
import org.jclouds.domain.JsonBall;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.gson.annotations.SerializedName;
/**
* Sandbox object.
*
* @author Adrian Cole
*/
public class Role {
private String name;
private String description;
@SerializedName("override_attributes")
private Map<String, JsonBall> override = Maps.newLinkedHashMap();
@SerializedName("default_attributes")
private Map<String, JsonBall> defaultA = Maps.newLinkedHashMap();
@SerializedName("run_list")
private List<String> runList = Lists.newArrayList();
// internal
@SerializedName("json_class")
private String _jsonClass = "Chef::Role";
@SerializedName("chef_type")
private String _chefType = "role";
public Role(String name, String description, Map<String, JsonBall> defaultA, List<String> runList,
Map<String, JsonBall> override) {
this.name = name;
this.description = description;
this.defaultA = defaultA;
this.runList = runList;
this.override = override;
}
public Role(String name, Iterable<String> runList) {
this.name = name;
Iterables.addAll(this.runList, runList);
}
// hidden but needs to be here for json deserialization to work
Role() {
}
public String getName() {
return name;
}
public String getDescription() {
return description;
}
public Map<String, JsonBall> getOverride() {
return override;
}
public Map<String, JsonBall> getDefault() {
return defaultA;
}
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 + ((defaultA == null) ? 0 : defaultA.hashCode());
result = prime * result + ((description == null) ? 0 : description.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + ((override == null) ? 0 : override.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 (defaultA == null) {
if (other.defaultA != null)
return false;
} else if (!defaultA.equals(other.defaultA))
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 (override == null) {
if (other.override != null)
return false;
} else if (!override.equals(other.override))
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 "[name=" + name + ", description=" + description + ", defaultA=" + defaultA + ", override=" + override
+ ", runList=" + runList + "]";
}
}

View File

@ -1,148 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.Date;
import java.util.Set;
import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;
import com.google.gson.annotations.SerializedName;
/**
* Sandbox object.
*
* @author Adrian Cole
*/
public class Sandbox {
@SerializedName("_rev")
private String rev;
@SerializedName("is_completed")
private boolean isCompleted;
@SerializedName("create_time")
private Date createTime;
private Set<String> checksums = Sets.newLinkedHashSet();
private String name;
private String guid;
// internal
@SuppressWarnings("unused")
@SerializedName("json_class")
private String _jsonClass = "Chef::Sandbox";
@SerializedName("chef_type")
@SuppressWarnings("unused")
private String _chefType = "sandbox";
public Sandbox(String rev, boolean isCompleted, Date createTime, Iterable<String> checksums, String name, String guid) {
this.rev = rev;
this.isCompleted = isCompleted;
this.createTime = createTime;
Iterables.addAll(this.checksums, checksums);
this.name = name;
this.guid = guid;
}
public Sandbox() {
}
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

@ -1,52 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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;
/**
*
* @author Adrian Cole
*
*/
public class SearchResult<T> extends LinkedHashSet<T> {
private long start;
SearchResult() {
}
public SearchResult(long start, Iterable<T> results) {
this.start = start;
Iterables.addAll(this, results);
}
private static final long serialVersionUID = 4000610660948065287L;
/**
*
* @return the result position this started from from
*/
long getStart() {
return start;
}
}

View File

@ -1,103 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.net.URI;
import java.util.List;
import java.util.Map;
import com.google.common.collect.Maps;
import com.google.gson.annotations.SerializedName;
/**
*
* @author Adrian Cole
*/
public class UploadSandbox {
private URI uri;
private Map<List<Byte>, ChecksumStatus> checksums = Maps.newLinkedHashMap();
@SerializedName("sandbox_id")
private String sandboxId;
public UploadSandbox(URI uri, Map<List<Byte>, ChecksumStatus> checksums, String sandboxId) {
this.uri = uri;
this.checksums.putAll(checksums);
this.sandboxId = sandboxId;
}
public UploadSandbox() {
}
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 "UploadSite [checksums=" + checksums + ", id=" + sandboxId + ", uri=" + uri + "]";
}
}

View File

@ -1,193 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.Preconditions.checkArgument;
import static org.jclouds.Constants.PROPERTY_IDENTITY;
import java.security.PrivateKey;
import java.util.Collections;
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.crypto.CryptoStreams;
import org.jclouds.date.TimeStamp;
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.InputSuppliers;
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.Utils;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Predicate;
import com.google.common.base.Splitter;
import com.google.common.base.Throwables;
import com.google.common.collect.Iterables;
import com.google.common.io.ByteStreams;
/**
* Ported from mixlib-authentication in order to sign Chef requests.
*
* @see <a href= "http://github.com/opscode/mixlib-authentication" />
* @author Adrian Cole
*
*/
@Singleton
public class SignedHeaderAuth implements HttpRequestFilter {
public static final String SIGNING_DESCRIPTION = "version=1.0";
private final SignatureWire signatureWire;
private final String userId;
private final PrivateKey privateKey;
private final Provider<String> timeStampProvider;
private final Crypto crypto;
private final String emptyStringHash;
private final HttpUtils utils;
@Resource
@Named(Constants.LOGGER_SIGNATURE)
Logger signatureLog = Logger.NULL;
@Inject
public SignedHeaderAuth(SignatureWire signatureWire, @Named(PROPERTY_IDENTITY) String userId, PrivateKey privateKey,
@TimeStamp Provider<String> timeStampProvider, Crypto crypto, HttpUtils utils) {
this.signatureWire = signatureWire;
this.userId = userId;
this.privateKey = privateKey;
this.timeStampProvider = timeStampProvider;
this.crypto = crypto;
this.emptyStringHash = hashBody(Payloads.newStringPayload(""));
this.utils = utils;
}
public void filter(HttpRequest request) throws HttpException {
String contentHash = hashBody(request.getPayload());
request.getHeaders().replaceValues("X-Ops-Content-Hash", Collections.singletonList(contentHash));
String timestamp = timeStampProvider.get();
String toSign = createStringToSign(request.getMethod(), hashPath(request.getEndpoint().getPath()), contentHash,
timestamp);
request.getHeaders().replaceValues("X-Ops-Userid", Collections.singletonList(userId));
request.getHeaders().replaceValues("X-Ops-Sign", Collections.singletonList(SIGNING_DESCRIPTION));
calculateAndReplaceAuthorizationHeaders(request, toSign);
request.getHeaders().replaceValues("X-Ops-Timestamp", Collections.singletonList(timestamp));
utils.logRequest(signatureLog, request, "<<");
}
@VisibleForTesting
void calculateAndReplaceAuthorizationHeaders(HttpRequest request, String toSign) throws HttpException {
String signature = sign(toSign);
if (signatureWire.enabled())
signatureWire.input(Utils.toInputStream(signature));
String[] signatureLines = Iterables.toArray(Splitter.fixedLength(60).split(signature), String.class);
for (int i = 0; i < signatureLines.length; i++) {
request.getHeaders().replaceValues("X-Ops-Authorization-" + (i + 1),
Collections.singletonList(signatureLines[i]));
}
}
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(userId).toString();
}
@VisibleForTesting
String hashPath(String path) {
try {
return CryptoStreams.base64(CryptoStreams.digest(InputSuppliers.of(canonicalPath(path)), crypto.sha1()));
} 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 CryptoStreams.base64(CryptoStreams.digest(payload, crypto.sha1()));
} 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 = ByteStreams.toByteArray(new RSAEncryptingPayload(Payloads.newStringPayload(toSign),
privateKey));
return CryptoStreams.base64(encrypted);
} catch (Exception e) {
throw new HttpException("error signing request", e);
}
}
}

View File

@ -1,69 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.ChefClient;
import org.jclouds.chef.domain.Client;
import com.google.common.base.Function;
/**
*
* Generates a client relevant for a particular tag
*
* @author Adrian Cole
*/
@Singleton
public class ClientForTag implements Function<String, Client> {
private final ChefClient chefClient;
@Inject
public ClientForTag(ChefClient chefClient) {
this.chefClient = checkNotNull(chefClient, "chefClient");
}
@Override
public Client apply(String from) {
String clientName = findNextClientName(chefClient.listClients(), from + "-validator-%02d");
Client client = chefClient.createClient(clientName);
// response from create only includes the key
return new Client(null, null, clientName, clientName, false, client.getPrivateKey());
}
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

@ -1,63 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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;
/**
*
*
* @author Adrian Cole
*/
@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

@ -1,51 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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;
/**
* @author Adrian Cole
*/
@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 arg0) {
return json.apply(arg0).keySet();
}
}

View File

@ -1,42 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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;
/**
*
* @author Adrian Cole
*/
@Singleton
public class ParseSearchClientsFromJson extends ParseSearchResultFromJson<Client> {
// TODO add generic json parser detector
@Inject
ParseSearchClientsFromJson(ParseJson<Response<Client>> json) {
super(json);
}
}

View File

@ -1,42 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.DatabagItem;
import org.jclouds.http.functions.ParseJson;
/**
*
* @author Adrian Cole
*/
@Singleton
public class ParseSearchDatabagFromJson extends ParseSearchResultFromJson<DatabagItem> {
// TODO add generic json parser detector
@Inject
ParseSearchDatabagFromJson(ParseJson<Response<DatabagItem>> json) {
super(json);
}
}

View File

@ -1,42 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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;
/**
*
* @author Adrian Cole
*/
@Singleton
public class ParseSearchNodesFromJson extends ParseSearchResultFromJson<Node> {
// TODO add generic json parser detector
@Inject
ParseSearchNodesFromJson(ParseJson<Response<Node>> json) {
super(json);
}
}

View File

@ -1,56 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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;
/**
* @author Adrian Cole
*/
@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 arg0) {
Response<T> returnVal = json.apply(arg0);
return new SearchResult<T>(returnVal.start, returnVal.rows);
}
}

View File

@ -1,42 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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;
/**
*
* @author Adrian Cole
*/
@Singleton
public class ParseSearchRolesFromJson extends ParseSearchResultFromJson<Role> {
// TODO add generic json parser detector
@Inject
ParseSearchRolesFromJson(ParseJson<Response<Role>> json) {
super(json);
}
}

View File

@ -1,71 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.reference.ChefConstants.CHEF_BOOTSTRAP_DATABAG;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import org.jclouds.chef.ChefClient;
import org.jclouds.chef.domain.DatabagItem;
import org.jclouds.json.Json;
import com.google.common.base.Function;
import com.google.inject.TypeLiteral;
/**
*
* Retrieves the run-list for a specific tag
*
*
* @author Adrian Cole
*/
@Singleton
public class RunListForTag implements Function<String, List<String>> {
public static final Type RUN_LIST_TYPE = new TypeLiteral<Map<String, List<String>>>() {
}.getType();
private final ChefClient client;
private final Json json;
private final String databag;
@Inject
public RunListForTag(@Named(CHEF_BOOTSTRAP_DATABAG) String databag, ChefClient client, Json json) {
this.databag = checkNotNull(databag, "databag");
this.client = checkNotNull(client, "client");
this.json = checkNotNull(json, "json");
}
@SuppressWarnings("unchecked")
@Override
public List<String> apply(String from) {
DatabagItem list = client.getDatabagItem(databag, from);
checkState(list != null, "databag item %s/%s not found", databag, from);
return ((Map<String, List<String>>) json.fromJson(list.toString(), RUN_LIST_TYPE)).get("run_list");
}
}

View File

@ -1,118 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.io.Payloads.newStringPayload;
import static org.jclouds.scriptbuilder.domain.Statements.createFile;
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.util.Collections;
import java.util.List;
import java.util.Map;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import org.jclouds.chef.domain.Client;
import org.jclouds.crypto.Pems;
import org.jclouds.io.Payload;
import org.jclouds.json.Json;
import org.jclouds.rest.annotations.Provider;
import org.jclouds.scriptbuilder.domain.OsFamily;
import org.jclouds.scriptbuilder.domain.Statement;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function;
import com.google.common.base.Splitter;
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 tag
*
* @author Adrian Cole
*/
@Singleton
public class TagToBootScript implements Function<String, Payload> {
@VisibleForTesting
static final Type RUN_LIST_TYPE = new TypeLiteral<Map<String, List<String>>>() {
}.getType();
private final URI endpoint;
private final Json json;
private final Map<String, Client> tagToClient;
private final Map<String, List<String>> runListForTag;
private final Statement installChefGems;
@Inject
public TagToBootScript(@Provider URI endpoint, Json json, Map<String, Client> tagToClient,
Map<String, List<String>> runListForTag, @Named("installChefGems") Statement installChefGems) {
this.endpoint = checkNotNull(endpoint, "endpoint");
this.json = checkNotNull(json, "json");
this.tagToClient = checkNotNull(tagToClient, "tagToClient");
this.runListForTag = checkNotNull(runListForTag, "runListForTag");
this.installChefGems = checkNotNull(installChefGems, "installChefGems");
}
public Payload apply(String tag) {
checkNotNull(tag, "tag");
Client client = tagToClient.get(tag);
checkState(client != null, "could not get a client for tag %s", tag);
checkState(client.getClientname() != null, "clientname null for %s", client);
checkState(client.getPrivateKey() != null, "privatekey null for %s", client);
List<String> runList = runListForTag.get(tag);
checkState(runList != null, "runList for %s was not found", tag);
checkState(runList.size() > 0, "runList for %s was empty", tag);
String chefConfigDir = "{root}etc{fs}chef";
Statement createChefConfigDir = exec("{md} " + chefConfigDir);
Statement createClientRb = createFile(chefConfigDir + "{fs}client.rb", ImmutableList.of("require 'rubygems'",
"require 'ohai'", "o = Ohai::System.new", "o.all_plugins", String.format(
"node_name \"%s-\" + o[:ipaddress]", tag), "log_level :info", "log_location STDOUT", String
.format("validation_client_name \"%s\"", client.getClientname()), String.format(
"chef_server_url \"%s\"", endpoint)));
Statement createValidationPem = createFile(chefConfigDir + "{fs}validation.pem", Splitter.on('\n').split(
Pems.pem(client.getPrivateKey())));
String chefBootFile = chefConfigDir + "{fs}first-boot.json";
Statement createFirstBoot = createFile(chefBootFile, Collections.singleton(json.toJson(ImmutableMap
.<String, List<String>> of("run_list", runList), RUN_LIST_TYPE)));
Statement runChef = exec("chef-client -j " + chefBootFile);
Statement bootstrapAndRunChef = newStatementList(installChefGems, createChefConfigDir, createClientRb,
createValidationPem, createFirstBoot, runChef);
String runScript = bootstrapAndRunChef.render(OsFamily.UNIX);
return newStringPayload(runScript);
}
}

View File

@ -1,72 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.
*
* @author Adrian Cole
*/
public class ChefClientErrorRetryHandler 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
ChefClientErrorRetryHandler(BackoffLimitedRetryHandler backoffLimitedRetryHandler) {
this.backoffLimitedRetryHandler = backoffLimitedRetryHandler;
}
public boolean shouldRetryRequest(HttpCommand command, HttpResponse response) {
if (command.getFailureCount() > retryCountLimit)
return false;
if (response.getStatusCode() == 400 && command.getRequest().getMethod().equals("PUT")
&& command.getRequest().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

@ -1,78 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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 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.
*
* @author Adrian Cole
*
*/
@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.getRequest()
.getRequestLine(), response.getStatusLine());
switch (response.getStatusCode()) {
case 401:
case 403:
exception = new AuthorizationException(message, exception);
break;
case 404:
if (!command.getRequest().getMethod().equals("DELETE")) {
exception = new ResourceNotFoundException(message, exception);
}
break;
}
} finally {
if (response.getPayload() != null)
Closeables.closeQuietly(response.getPayload().getInput());
command.setException(exception);
}
}
}

View File

@ -1,49 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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 org.jclouds.Constants.PROPERTY_API_VERSION;
import static org.jclouds.Constants.PROPERTY_SESSION_INTERVAL;
import static org.jclouds.chef.reference.ChefConstants.CHEF_BOOTSTRAP_DATABAG;
import java.util.Properties;
import org.jclouds.PropertiesBuilder;
import org.jclouds.chef.ChefAsyncClient;
/**
* Builds properties used in Chef Clients
*
* @author Adrian Cole
*/
public abstract class BaseChefPropertiesBuilder extends PropertiesBuilder {
@Override
protected Properties defaultProperties() {
Properties properties = super.defaultProperties();
properties.setProperty(PROPERTY_SESSION_INTERVAL, "1");
properties.setProperty(PROPERTY_API_VERSION, ChefAsyncClient.VERSION);
properties.setProperty(CHEF_BOOTSTRAP_DATABAG, "bootstrap");
return properties;
}
public BaseChefPropertiesBuilder(Properties properties) {
super(properties);
}
}

View File

@ -1,227 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.reference.ChefConstants.CHEF_BOOTSTRAP_DATABAG;
import java.io.IOException;
import java.io.InputStream;
import java.security.PrivateKey;
import java.util.List;
import javax.annotation.Resource;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Provider;
import javax.inject.Singleton;
import org.jclouds.chef.ChefContext;
import org.jclouds.chef.ChefService;
import org.jclouds.chef.domain.Client;
import org.jclouds.chef.domain.CookbookVersion;
import org.jclouds.chef.domain.DatabagItem;
import org.jclouds.chef.domain.Node;
import org.jclouds.chef.functions.RunListForTag;
import org.jclouds.chef.functions.TagToBootScript;
import org.jclouds.chef.reference.ChefConstants;
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.ListNodes;
import org.jclouds.chef.strategy.UpdateAutomaticAttributesOnNode;
import org.jclouds.io.Payload;
import org.jclouds.io.Payloads;
import org.jclouds.io.payloads.RSADecryptingPayload;
import org.jclouds.io.payloads.RSAEncryptingPayload;
import org.jclouds.logging.Logger;
import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.google.common.io.ByteStreams;
import com.google.common.io.InputSupplier;
/**
*
* @author Adrian Cole
*/
@Singleton
public class BaseChefService implements ChefService {
@Resource
@Named(ChefConstants.CHEF_LOGGER)
protected Logger logger = Logger.NULL;
private final ChefContext chefContext;
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 Provider<PrivateKey> privateKey;
private final TagToBootScript tagToBootScript;
private final String databag;
private final RunListForTag runListForTag;
private final ListCookbookVersions listCookbookVersions;
@Inject
protected BaseChefService(ChefContext chefContext, CleanupStaleNodesAndClients cleanupStaleNodesAndClients,
CreateNodeAndPopulateAutomaticAttributes createNodeAndPopulateAutomaticAttributes,
DeleteAllNodesInList deleteAllNodesInList, ListNodes listNodes,
DeleteAllClientsInList deleteAllClientsInList, ListClients listClients,
ListCookbookVersions listCookbookVersions, UpdateAutomaticAttributesOnNode updateAutomaticAttributesOnNode,
Provider<PrivateKey> privateKey, @Named(CHEF_BOOTSTRAP_DATABAG) String databag,
TagToBootScript tagToBootScript, RunListForTag runListForTag) {
this.chefContext = checkNotNull(chefContext, "chefContext");
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.tagToBootScript = checkNotNull(tagToBootScript, "tagToBootScript");
this.databag = checkNotNull(databag, "databag");
this.runListForTag = checkNotNull(runListForTag, "runListForTag");
}
@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 deleteAllNodesInList(Iterable<String> names) {
deleteAllNodesInList.execute(names);
}
@Override
public Iterable<? extends Node> listNodes() {
return listNodes.execute();
}
@Override
public Iterable<? extends Node> listNodesMatching(Predicate<String> nodeNameSelector) {
return listNodes.execute(nodeNameSelector);
}
@Override
public Iterable<? extends Node> listNodesNamed(Iterable<String> names) {
return listNodes.execute(names);
}
@Override
public void deleteAllClientsInList(Iterable<String> names) {
deleteAllClientsInList.execute(names);
}
@Override
public Iterable<? extends Client> listClientsDetails() {
return listClients.execute();
}
@Override
public Iterable<? extends Client> listClientsDetailsMatching(Predicate<String> clientNameSelector) {
return listClients.execute(clientNameSelector);
}
@Override
public Iterable<? extends Client> listClientsNamed(Iterable<String> names) {
return listClients.execute(names);
}
@Override
public Iterable<? extends CookbookVersion> listCookbookVersions() {
return listCookbookVersions.execute();
}
@Override
public Iterable<? extends CookbookVersion> listCookbookVersionsMatching(Predicate<String> cookbookNameSelector) {
return listCookbookVersions.execute(cookbookNameSelector);
}
@Override
public Iterable<? extends CookbookVersion> listCookbookVersionsNamed(Iterable<String> names) {
return listCookbookVersions.execute(names);
}
@Override
public void updateAutomaticAttributesOnNode(String nodeName) {
updateAutomaticAttributesOnNode.execute(nodeName);
}
@Override
public ChefContext getContext() {
return chefContext;
}
@Override
public Payload createClientAndBootstrapScriptForTag(String tag) {
return tagToBootScript.apply(tag);
}
@Override
public void updateRunListForTag(Iterable<String> runList, String tag) {
try {
chefContext.getApi().createDatabag(databag);
} catch (IllegalStateException e) {
}
chefContext.getApi().updateDatabagItem(
databag,
new DatabagItem(tag, chefContext.utils().json().toJson(
ImmutableMap.<String, List<String>> of("run_list", Lists.newArrayList(runList)),
RunListForTag.RUN_LIST_TYPE)));
}
@Override
public List<String> getRunListForTag(String tag) {
return runListForTag.apply(tag);
}
@Override
public byte[] decrypt(InputSupplier<? extends InputStream> supplier) throws IOException {
return ByteStreams.toByteArray(new RSADecryptingPayload(Payloads.newPayload(supplier.getInput()), privateKey
.get()));
}
@Override
public byte[] encrypt(InputSupplier<? extends InputStream> supplier) throws IOException {
return ByteStreams.toByteArray(new RSAEncryptingPayload(Payloads.newPayload(supplier.getInput()), privateKey
.get()));
}
}

View File

@ -1,61 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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 java.net.URI;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.chef.ChefAsyncClient;
import org.jclouds.chef.ChefClient;
import org.jclouds.chef.ChefContext;
import org.jclouds.chef.ChefService;
import org.jclouds.lifecycle.Closer;
import org.jclouds.rest.Utils;
import org.jclouds.rest.annotations.ApiVersion;
import org.jclouds.rest.annotations.Identity;
import org.jclouds.rest.annotations.Provider;
import org.jclouds.rest.internal.RestContextImpl;
import com.google.inject.Injector;
import com.google.inject.TypeLiteral;
/**
* @author Adrian Cole
*/
@Singleton
public class ChefContextImpl extends RestContextImpl<ChefClient, ChefAsyncClient> implements ChefContext {
private final ChefService chefService;
@Inject
protected ChefContextImpl(Closer closer, Utils utils, Injector injector, TypeLiteral<ChefClient> syncApi,
TypeLiteral<ChefAsyncClient> asyncApi, @Provider URI endpoint, @Provider String provider,
@Identity String identity, @ApiVersion String apiVersion, ChefService chefService) {
super(closer, utils, injector, syncApi, asyncApi, endpoint, provider, identity, apiVersion);
this.chefService = chefService;
}
@Override
public ChefService getChefService() {
return chefService;
}
}

View File

@ -1,97 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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}.
*
* @author Adrian Cole
*/
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

@ -1,58 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.reference;
/**
* Configuration properties and constants used in Chef connections.
*
* @author Adrian Cole
*/
public interface ChefConstants {
/**
* There are generally 3 types of identities
* <ul>
* <li>validator - used to create clients within an organization; {@code orgname}-validator</li>
* <li>client - scoped to an organization, used on nodes to run chef</li>
* <li>user - used to run commands like knife and access cookbook sites</li>
* </ul>
*
*/
/**
* The PEM-encoded key
*/
/**
* how often to refresh timestamps in seconds.
*/
public static final String CHEF_LOGGER = "jclouds.chef";
public static final String CHEF_SERVICE_CLIENT = "chef.service-client";
public static final String CHEF_NODE = "chef.node";
public static final String CHEF_NODE_PATTERN = "chef.node-pattern";
public static final String CHEF_RUN_LIST = "chef.run-list";
/**
* 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";
}

View File

@ -1,54 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.statements;
import java.io.IOException;
import java.util.Collections;
import javax.inject.Singleton;
import org.jclouds.scriptbuilder.domain.OsFamily;
import org.jclouds.scriptbuilder.domain.Statement;
import org.jclouds.util.Utils;
import com.google.common.base.Throwables;
/**
* @author Adrian Cole
*/
@Singleton
public class InstallChefGems implements Statement {
@Override
public String render(OsFamily family) {
try {
return Utils.toStringAndClose(InstallChefGems.class.getClassLoader().getResourceAsStream(
"install-chef-gems.sh"));
} catch (IOException e) {
Throwables.propagate(e);
return null;
}
}
@Override
public Iterable<String> functionDependecies(OsFamily family) {
return Collections.emptyList();
}
}

View File

@ -1,37 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.
*
* @author Adrian Cole
*/
@ImplementedBy(CleanupStaleNodesAndClientsImpl.class)
public interface CleanupStaleNodesAndClients {
void execute(String prefix, int secondsStale);
}

View File

@ -1,38 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.
*
* @author Adrian Cole
*/
@ImplementedBy(CreateNodeAndPopulateAutomaticAttributesImpl.class)
public interface CreateNodeAndPopulateAutomaticAttributes {
Node execute(Node node);
Node execute(String nodeName, Iterable<String> runList);
}

View File

@ -1,36 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.inject.ImplementedBy;
/**
*
*
* @author Adrian Cole
*/
@ImplementedBy(DeleteAllClientsInListImpl.class)
public interface DeleteAllClientsInList {
public void execute(Iterable<String> names);
}

View File

@ -1,36 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.inject.ImplementedBy;
/**
*
*
* @author Adrian Cole
*/
@ImplementedBy(DeleteAllNodesInListImpl.class)
public interface DeleteAllNodesInList {
public void execute(Iterable<String> names);
}

View File

@ -1,41 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.Client;
import org.jclouds.chef.strategy.internal.ListClientsImpl;
import com.google.common.base.Predicate;
import com.google.inject.ImplementedBy;
/**
*
*
* @author Adrian Cole
*/
@ImplementedBy(ListClientsImpl.class)
public interface ListClients {
Iterable<? extends Client> execute();
Iterable<? extends Client> execute(Predicate<String> clientNameSelector);
Iterable<? extends Client> execute(Iterable<String> toGet);
}

View File

@ -1,41 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.CookbookVersion;
import org.jclouds.chef.strategy.internal.ListCookbookVersionsImpl;
import com.google.common.base.Predicate;
import com.google.inject.ImplementedBy;
/**
*
*
* @author Adrian Cole
*/
@ImplementedBy(ListCookbookVersionsImpl.class)
public interface ListCookbookVersions {
Iterable<? extends CookbookVersion> execute();
Iterable<? extends CookbookVersion> execute(Predicate<String> cookbookNameSelector);
Iterable<? extends CookbookVersion> execute(Iterable<String> cookbookNames);
}

View File

@ -1,41 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.ListNodesImpl;
import com.google.common.base.Predicate;
import com.google.inject.ImplementedBy;
/**
*
*
* @author Adrian Cole
*/
@ImplementedBy(ListNodesImpl.class)
public interface ListNodes {
Iterable<? extends Node> execute();
Iterable<? extends Node> execute(Predicate<String> nodeNameSelector);
Iterable<? extends Node> execute(Iterable<String> toGet);
}

View File

@ -1,36 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.
*
* @author Adrian Cole
*/
@ImplementedBy(UpdateAutomaticAttributesOnNodeImpl.class)
public interface UpdateAutomaticAttributesOnNode {
public void execute(String nodeName);
}

View File

@ -1,108 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.domain.Node;
import org.jclouds.chef.reference.ChefConstants;
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 clients who have been hanging around too long.
*
* @author Adrian Cole
*/
@Singleton
public class CleanupStaleNodesAndClientsImpl implements CleanupStaleNodesAndClients {
@Resource
@Named(ChefConstants.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(new Predicate<String>() {
@Override
public boolean apply(String input) {
return input.startsWith(prefix);
}
}), and(notNull(), new Predicate<Node>() {
@Override
public boolean apply(Node input) {
JsonBall dateLong = input.getAutomatic().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

@ -1,77 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.ChefClient;
import org.jclouds.chef.domain.Node;
import org.jclouds.chef.reference.ChefConstants;
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.
*
* @author Adrian Cole
*/
@Singleton
public class CreateNodeAndPopulateAutomaticAttributesImpl implements CreateNodeAndPopulateAutomaticAttributes {
@Resource
@Named(ChefConstants.CHEF_LOGGER)
protected Logger logger = Logger.NULL;
private final ChefClient chef;
private final Supplier<Map<String, JsonBall>> automaticSupplier;
@Inject
public CreateNodeAndPopulateAutomaticAttributesImpl(ChefClient 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.getAutomatic().putAll(automaticSupplier.get());
chef.createNode(node);
logger.debug("created node %s", node.getName());
return node;
}
@Override
public Node execute(String nodeName, Iterable<String> runList) {
return execute(new Node(nodeName, runList));
}
}

View File

@ -1,81 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.Maps.newHashMap;
import static org.jclouds.concurrent.FutureIterables.awaitCompletion;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import javax.annotation.Resource;
import javax.inject.Named;
import javax.inject.Singleton;
import org.jclouds.Constants;
import org.jclouds.chef.ChefAsyncClient;
import org.jclouds.chef.ChefClient;
import org.jclouds.chef.reference.ChefConstants;
import org.jclouds.chef.strategy.DeleteAllClientsInList;
import org.jclouds.logging.Logger;
import com.google.inject.Inject;
/**
*
*
* @author Adrian Cole
*/
@Singleton
public class DeleteAllClientsInListImpl implements DeleteAllClientsInList {
protected final ChefClient chefClient;
protected final ChefAsyncClient chefAsyncClient;
protected final ExecutorService userExecutor;
@Resource
@Named(ChefConstants.CHEF_LOGGER)
protected Logger logger = Logger.NULL;
@Inject(optional = true)
@Named(Constants.PROPERTY_REQUEST_TIMEOUT)
protected Long maxTime;
@Inject
DeleteAllClientsInListImpl(@Named(Constants.PROPERTY_USER_THREADS) ExecutorService userExecutor,
ChefClient getAllClient, ChefAsyncClient ablobstore) {
this.userExecutor = userExecutor;
this.chefAsyncClient = ablobstore;
this.chefClient = getAllClient;
}
@Override
public void execute(Iterable<String> names) {
Map<String, Exception> exceptions = newHashMap();
Map<String, Future<?>> responses = newHashMap();
for (String name : names) {
responses.put(name, chefAsyncClient.deleteClient(name));
}
exceptions = awaitCompletion(responses, userExecutor, maxTime, logger, String.format(
"deleting clients: %s", names));
if (exceptions.size() > 0)
throw new RuntimeException(String.format("errors deleting clients: %s: %s", names, exceptions));
}
}

View File

@ -1,81 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.Maps.newHashMap;
import static org.jclouds.concurrent.FutureIterables.awaitCompletion;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import javax.annotation.Resource;
import javax.inject.Named;
import javax.inject.Singleton;
import org.jclouds.Constants;
import org.jclouds.chef.ChefAsyncClient;
import org.jclouds.chef.ChefClient;
import org.jclouds.chef.reference.ChefConstants;
import org.jclouds.chef.strategy.DeleteAllNodesInList;
import org.jclouds.logging.Logger;
import com.google.inject.Inject;
/**
*
*
* @author Adrian Cole
*/
@Singleton
public class DeleteAllNodesInListImpl implements DeleteAllNodesInList {
protected final ChefClient chefClient;
protected final ChefAsyncClient chefAsyncClient;
protected final ExecutorService userExecutor;
@Resource
@Named(ChefConstants.CHEF_LOGGER)
protected Logger logger = Logger.NULL;
@Inject(optional = true)
@Named(Constants.PROPERTY_REQUEST_TIMEOUT)
protected Long maxTime;
@Inject
DeleteAllNodesInListImpl(@Named(Constants.PROPERTY_USER_THREADS) ExecutorService userExecutor,
ChefClient getAllNode, ChefAsyncClient ablobstore) {
this.userExecutor = userExecutor;
this.chefAsyncClient = ablobstore;
this.chefClient = getAllNode;
}
@Override
public void execute(Iterable<String> names) {
Map<String, Exception> exceptions = newHashMap();
Map<String, Future<?>> responses = newHashMap();
for (String name : names) {
responses.put(name, chefAsyncClient.deleteNode(name));
}
exceptions = awaitCompletion(responses, userExecutor, maxTime, logger, String.format(
"deleting nodes: %s", names));
if (exceptions.size() > 0)
throw new RuntimeException(String.format("errors deleting nodes: %s: %s", names, exceptions));
}
}

View File

@ -1,94 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.filter;
import static org.jclouds.concurrent.FutureIterables.transformParallel;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import javax.annotation.Resource;
import javax.inject.Named;
import javax.inject.Singleton;
import org.jclouds.Constants;
import org.jclouds.chef.ChefAsyncClient;
import org.jclouds.chef.ChefClient;
import org.jclouds.chef.domain.Client;
import org.jclouds.chef.reference.ChefConstants;
import org.jclouds.chef.strategy.ListClients;
import org.jclouds.logging.Logger;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.inject.Inject;
/**
*
*
* @author Adrian Cole
*/
@Singleton
public class ListClientsImpl implements ListClients {
protected final ChefClient chefClient;
protected final ChefAsyncClient chefAsyncClient;
protected final ExecutorService userExecutor;
@Resource
@Named(ChefConstants.CHEF_LOGGER)
protected Logger logger = Logger.NULL;
@Inject(optional = true)
@Named(Constants.PROPERTY_REQUEST_TIMEOUT)
protected Long maxTime;
@Inject
ListClientsImpl(@Named(Constants.PROPERTY_USER_THREADS) ExecutorService userExecutor, ChefClient getAllClient,
ChefAsyncClient ablobstore) {
this.userExecutor = userExecutor;
this.chefAsyncClient = ablobstore;
this.chefClient = getAllClient;
}
@Override
public Iterable<? extends Client> execute() {
return execute(chefClient.listClients());
}
@Override
public Iterable<? extends Client> execute(Predicate<String> clientNameSelector) {
return execute(filter(chefClient.listClients(), clientNameSelector));
}
@Override
public Iterable<? extends Client> execute(Iterable<String> toGet) {
return transformParallel(toGet, new Function<String, Future<Client>>() {
@Override
public Future<Client> apply(String from) {
return chefAsyncClient.getClient(from);
}
}, userExecutor, maxTime, logger, "getting clients");
}
}

View File

@ -1,104 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.concat;
import static com.google.common.collect.Iterables.filter;
import static com.google.common.collect.Iterables.transform;
import static org.jclouds.concurrent.FutureIterables.transformParallel;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import javax.annotation.Resource;
import javax.inject.Named;
import javax.inject.Singleton;
import org.jclouds.Constants;
import org.jclouds.chef.ChefAsyncClient;
import org.jclouds.chef.ChefClient;
import org.jclouds.chef.domain.CookbookVersion;
import org.jclouds.chef.reference.ChefConstants;
import org.jclouds.chef.strategy.ListCookbookVersions;
import org.jclouds.logging.Logger;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.inject.Inject;
/**
*
*
* @author Adrian Cole
*/
@Singleton
public class ListCookbookVersionsImpl implements ListCookbookVersions {
protected final ChefClient chefClient;
protected final ChefAsyncClient chefAsyncClient;
protected final ExecutorService userExecutor;
@Resource
@Named(ChefConstants.CHEF_LOGGER)
protected Logger logger = Logger.NULL;
@Inject(optional = true)
@Named(Constants.PROPERTY_REQUEST_TIMEOUT)
protected Long maxTime;
@Inject
ListCookbookVersionsImpl(@Named(Constants.PROPERTY_USER_THREADS) ExecutorService userExecutor,
ChefClient getAllCookbookVersion, ChefAsyncClient ablobstore) {
this.userExecutor = userExecutor;
this.chefAsyncClient = ablobstore;
this.chefClient = getAllCookbookVersion;
}
@Override
public Iterable<? extends CookbookVersion> execute() {
return execute(chefClient.listCookbooks());
}
@Override
public Iterable<? extends CookbookVersion> execute(Predicate<String> cookbookNameSelector) {
return execute(filter(chefClient.listCookbooks(), cookbookNameSelector));
}
@Override
public 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
return transformParallel(chefClient.getVersionsOfCookbook(cookbook),
new Function<String, Future<CookbookVersion>>() {
@Override
public Future<CookbookVersion> apply(String version) {
return chefAsyncClient.getCookbook(cookbook, version);
}
}, userExecutor, maxTime, logger, "getting versions of cookbook " + cookbook);
}
}));
}
}

View File

@ -1,94 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.filter;
import static org.jclouds.concurrent.FutureIterables.transformParallel;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import javax.annotation.Resource;
import javax.inject.Named;
import javax.inject.Singleton;
import org.jclouds.Constants;
import org.jclouds.chef.ChefAsyncClient;
import org.jclouds.chef.ChefClient;
import org.jclouds.chef.domain.Node;
import org.jclouds.chef.reference.ChefConstants;
import org.jclouds.chef.strategy.ListNodes;
import org.jclouds.logging.Logger;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.inject.Inject;
/**
*
*
* @author Adrian Cole
*/
@Singleton
public class ListNodesImpl implements ListNodes {
protected final ChefClient chefClient;
protected final ChefAsyncClient chefAsyncClient;
protected final ExecutorService userExecutor;
@Resource
@Named(ChefConstants.CHEF_LOGGER)
protected Logger logger = Logger.NULL;
@Inject(optional = true)
@Named(Constants.PROPERTY_REQUEST_TIMEOUT)
protected Long maxTime;
@Inject
ListNodesImpl(@Named(Constants.PROPERTY_USER_THREADS) ExecutorService userExecutor, ChefClient getAllNode,
ChefAsyncClient ablobstore) {
this.userExecutor = userExecutor;
this.chefAsyncClient = ablobstore;
this.chefClient = getAllNode;
}
@Override
public Iterable<? extends Node> execute() {
return execute(chefClient.listNodes());
}
@Override
public Iterable<? extends Node> execute(Predicate<String> nodeNameSelector) {
return execute(filter(chefClient.listNodes(), nodeNameSelector));
}
@Override
public Iterable<? extends Node> execute(Iterable<String> toGet) {
return transformParallel(toGet, new Function<String, Future<Node>>() {
@Override
public Future<Node> apply(String from) {
return chefAsyncClient.getNode(from);
}
}, userExecutor, maxTime, logger, "getting nodes");
}
}

View File

@ -1,72 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.ChefClient;
import org.jclouds.chef.domain.Node;
import org.jclouds.chef.reference.ChefConstants;
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.
*
* @author Adrian Cole
*/
@Singleton
public class UpdateAutomaticAttributesOnNodeImpl implements UpdateAutomaticAttributesOnNode {
@Resource
@Named(ChefConstants.CHEF_LOGGER)
protected Logger logger = Logger.NULL;
private final ChefClient chef;
private final Supplier<Map<String, JsonBall>> automaticSupplier;
@Inject
public UpdateAutomaticAttributesOnNodeImpl(ChefClient 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.getAutomatic().putAll(automaticSupplier.get());
chef.updateNode(node);
logger.debug("updated node %s", nodeName);
}
}

View File

@ -1,346 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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 static org.jclouds.concurrent.Futures.compose;
import java.io.IOException;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import org.jclouds.Constants;
import org.jclouds.blobstore.TransientAsyncBlobStore;
import org.jclouds.blobstore.domain.Blob;
import org.jclouds.blobstore.domain.PageSet;
import org.jclouds.blobstore.domain.StorageMetadata;
import org.jclouds.chef.ChefAsyncClient;
import org.jclouds.chef.domain.Client;
import org.jclouds.chef.domain.CookbookVersion;
import org.jclouds.chef.domain.DatabagItem;
import org.jclouds.chef.domain.Node;
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.util.Utils;
import com.google.common.base.Function;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
/**
* In-memory chef simulator.
*
* @author Adrian Cole
*/
public class TransientChefAsyncClient implements ChefAsyncClient {
@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(), Utils.toStringAndClose(from
.getPayload().getInput()));
} catch (IOException e) {
propagate(e);
return null;
}
}
}
private final TransientAsyncBlobStore databags;
private final ExecutorService executor;
private final BlobToDatabagItem blobToDatabagItem;
private final StorageMetadataToName storageMetadataToName;
@Inject
TransientChefAsyncClient(@Named("databags") TransientAsyncBlobStore databags,
StorageMetadataToName storageMetadataToName, BlobToDatabagItem blobToDatabagItem,
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor) {
this.databags = checkNotNull(databags, "databags");
this.storageMetadataToName = checkNotNull(storageMetadataToName, "storageMetadataToName");
this.blobToDatabagItem = checkNotNull(blobToDatabagItem, "blobToDatabagItem");
this.executor = checkNotNull(executor, "executor");
}
@Override
public ListenableFuture<Boolean> clientExists(String clientname) {
// TODO Auto-generated method stub
return null;
}
@Override
public ListenableFuture<Sandbox> commitSandbox(String id, boolean isCompleted) {
// TODO Auto-generated method stub
return null;
}
@Override
public ListenableFuture<Client> createClient(String clientname) {
// TODO Auto-generated method stub
return null;
}
@Override
public ListenableFuture<Void> createDatabag(String databagName) {
return databags.createContainerInLocationIfAbsent(null, databagName);
}
@Override
public ListenableFuture<DatabagItem> createDatabagItem(String databagName, DatabagItem databagItem) {
Blob blob = databags.newBlob(databagItem.getId());
blob.setPayload(databagItem.toString());
databags.putBlobAndReturnOld(databagName, blob);
return Futures.immediateFuture(databagItem);
}
@Override
public ListenableFuture<Void> createNode(Node node) {
// TODO Auto-generated method stub
return null;
}
@Override
public ListenableFuture<Void> createRole(Role role) {
// TODO Auto-generated method stub
return null;
}
@Override
public ListenableFuture<Boolean> databagExists(String databagName) {
return databags.containerExists(databagName);
}
@Override
public ListenableFuture<Boolean> databagItemExists(String databagName, String databagItemId) {
return databags.blobExists(databagName, databagItemId);
}
@Override
public ListenableFuture<Client> deleteClient(String clientname) {
// TODO Auto-generated method stub
return null;
}
@Override
public ListenableFuture<CookbookVersion> deleteCookbook(String cookbookName, String version) {
// TODO Auto-generated method stub
return null;
}
@Override
public ListenableFuture<Void> deleteDatabag(String databagName) {
return databags.deleteContainer(databagName);
}
@Override
public ListenableFuture<DatabagItem> deleteDatabagItem(String databagName, String databagItemId) {
return compose(databags.removeBlobAndReturnOld(databagName, databagItemId), blobToDatabagItem, executor);
}
@Override
public ListenableFuture<Node> deleteNode(String nodename) {
// TODO Auto-generated method stub
return null;
}
@Override
public ListenableFuture<Role> deleteRole(String rolename) {
// TODO Auto-generated method stub
return null;
}
@Override
public ListenableFuture<Client> generateKeyForClient(String clientname) {
// TODO Auto-generated method stub
return null;
}
@Override
public ListenableFuture<Client> getClient(String clientname) {
// TODO Auto-generated method stub
return null;
}
@Override
public ListenableFuture<CookbookVersion> getCookbook(String cookbookName, String version) {
// TODO Auto-generated method stub
return null;
}
@Override
public ListenableFuture<DatabagItem> getDatabagItem(String databagName, String databagItemId) {
return compose(databags.getBlob(databagName, databagItemId), blobToDatabagItem, executor);
}
@Override
public ListenableFuture<Node> getNode(String nodename) {
// TODO Auto-generated method stub
return null;
}
@Override
public ListenableFuture<Role> getRole(String rolename) {
// TODO Auto-generated method stub
return null;
}
@Override
public ListenableFuture<UploadSandbox> getUploadSandboxForChecksums(Set<List<Byte>> md5s) {
// TODO Auto-generated method stub
return null;
}
@Override
public ListenableFuture<Set<String>> getVersionsOfCookbook(String cookbookName) {
// TODO Auto-generated method stub
return null;
}
@Override
public ListenableFuture<Set<String>> listClients() {
// TODO Auto-generated method stub
return null;
}
@Override
public ListenableFuture<Set<String>> listCookbooks() {
// TODO Auto-generated method stub
return null;
}
@Override
public ListenableFuture<Set<String>> listDatabagItems(String databagName) {
return compose(databags.list(databagName), storageMetadataToName, executor);
}
@Override
public ListenableFuture<Set<String>> listDatabags() {
return compose(databags.list(), storageMetadataToName, executor);
}
@Override
public ListenableFuture<Set<String>> listNodes() {
// TODO Auto-generated method stub
return null;
}
@Override
public ListenableFuture<Set<String>> listRoles() {
// TODO Auto-generated method stub
return null;
}
@Override
public ListenableFuture<Set<String>> listSearchIndexes() {
// TODO Auto-generated method stub
return null;
}
@Override
public ListenableFuture<Boolean> nodeExists(String nodename) {
// TODO Auto-generated method stub
return null;
}
@Override
public ListenableFuture<Boolean> roleExists(String rolename) {
// TODO Auto-generated method stub
return null;
}
@Override
public ListenableFuture<? extends SearchResult<? extends Client>> searchClients() {
// TODO Auto-generated method stub
return null;
}
@Override
public ListenableFuture<? extends SearchResult<? extends DatabagItem>> searchDatabag(String databagName) {
// TODO Auto-generated method stub
return null;
}
@Override
public ListenableFuture<? extends SearchResult<? extends Node>> searchNodes() {
// TODO Auto-generated method stub
return null;
}
@Override
public ListenableFuture<? extends SearchResult<? extends Role>> searchRoles() {
// TODO Auto-generated method stub
return null;
}
@Override
public ListenableFuture<CookbookVersion> updateCookbook(String cookbookName, String version, CookbookVersion cookbook) {
// TODO Auto-generated method stub
return null;
}
@Override
public ListenableFuture<DatabagItem> updateDatabagItem(String databagName, DatabagItem item) {
return createDatabagItem(databagName, item);
}
@Override
public ListenableFuture<Node> updateNode(Node node) {
// TODO Auto-generated method stub
return null;
}
@Override
public ListenableFuture<Role> updateRole(Role role) {
// TODO Auto-generated method stub
return null;
}
@Override
public ListenableFuture<Void> uploadContent(Set<List<Byte>> md5s) {
// TODO Auto-generated method stub
return null;
}
}

View File

@ -1,39 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.util.concurrent.TimeUnit;
import org.jclouds.chef.ChefAsyncClient;
import org.jclouds.chef.ChefClient;
import org.jclouds.concurrent.Timeout;
/**
* In-memory chef simulator.
* <p/>
*
* @see ChefAsyncClient
* @see <a href="TODO: insert URL of Chef documentation" />
* @author Adrian Cole
*/
@Timeout(duration = 30, timeUnit = TimeUnit.MILLISECONDS)
public interface TransientChefClient extends ChefClient {
}

View File

@ -1,43 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.util.List;
import java.util.Properties;
import org.jclouds.chef.ChefContextBuilder;
import org.jclouds.chef.test.config.TransientChefClientModule;
import com.google.inject.Module;
/**
* @author Adrian Cole
*/
public class TransientChefContextBuilder extends ChefContextBuilder {
public TransientChefContextBuilder(Properties props) {
super(props);
}
@Override
protected void addClientModule(List<Module> modules) {
modules.add(new TransientChefClientModule());
}
}

View File

@ -1,85 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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 java.util.List;
import java.util.Map;
import javax.inject.Singleton;
import org.jclouds.blobstore.TransientAsyncBlobStore;
import org.jclouds.chef.ChefAsyncClient;
import org.jclouds.chef.ChefClient;
import org.jclouds.chef.config.BaseChefRestClientModule;
import org.jclouds.chef.domain.Client;
import org.jclouds.chef.functions.ClientForTag;
import org.jclouds.chef.functions.RunListForTag;
import org.jclouds.chef.statements.InstallChefGems;
import org.jclouds.chef.test.TransientChefAsyncClient;
import org.jclouds.chef.test.TransientChefClient;
import org.jclouds.rest.RestContextFactory;
import org.jclouds.scriptbuilder.domain.Statement;
import com.google.common.collect.MapMaker;
import com.google.inject.Provides;
import com.google.inject.name.Names;
/**
*
* @author Adrian Cole
*/
public class TransientChefClientModule extends BaseChefRestClientModule<TransientChefClient, ChefAsyncClient> {
public TransientChefClientModule() {
super(TransientChefClient.class, ChefAsyncClient.class);
}
@Override
protected void configure() {
bind(TransientAsyncBlobStore.class).annotatedWith(Names.named("databags")).toInstance(
new RestContextFactory().createContextBuilder("transient", "foo", "bar").buildInjector().getInstance(
TransientAsyncBlobStore.class));
bind(Statement.class).annotatedWith(Names.named("installChefGems")).to(InstallChefGems.class);
super.configure();
}
@Override
protected void bindAsyncClient() {
bind(ChefAsyncClient.class).to(TransientChefAsyncClient.class).asEagerSingleton();
}
@Provides
@Singleton
ChefClient provideClient(TransientChefClient in) {
return in;
}
@Provides
@Singleton
Map<String, List<String>> runListForTag(RunListForTag runListForTag) {
return new MapMaker().makeComputingMap(runListForTag);
}
@Provides
@Singleton
Map<String, Client> tagToClient(ClientForTag tagToClient) {
return new MapMaker().makeComputingMap(tagToClient);
}
}

View File

@ -1,79 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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 org.jclouds.ohai.config.multibindings.MapBinder;
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;
/**
*
*
* @author Adrian Cole
*/
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

@ -1,88 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.
*
* @author Adrian Cole
*/
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

@ -1,40 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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;
/**
*
* @author Adrian Cole
*/
@Retention(RUNTIME)
@Target( { TYPE, METHOD, PARAMETER })
@Qualifier
public @interface Automatic {
}

View File

@ -1,56 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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;
/**
*
* @author Adrian Cole
*
*/
@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

@ -1,61 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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 java.util.Properties;
import javax.inject.Inject;
import org.jclouds.ohai.config.ConfiguresOhai;
import org.jclouds.ohai.config.JMXOhaiModule;
import org.jclouds.rest.RestContext;
import org.jclouds.rest.RestContextBuilder;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import com.google.inject.Module;
/**
*
* @see RestContext
*/
public class OhaiContextBuilder<S, A> extends RestContextBuilder<S, A> {
@Inject
public OhaiContextBuilder(Class<S> syncClientClass, Class<A> asyncClientClass, Properties properties) {
super(syncClientClass, asyncClientClass, properties);
}
protected void addOhaiModuleIfNotPresent() {
if (!Iterables.any(modules, new Predicate<Module>() {
public boolean apply(Module input) {
return input.getClass().isAnnotationPresent(ConfiguresOhai.class);
}
})) {
addOhaiModule();
}
}
protected void addOhaiModule() {
modules.add(new JMXOhaiModule());
}
}

View File

@ -1,35 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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;
/**
*
* @author Adrian Cole
*/
@Retention(RUNTIME)
@Target(TYPE)
public @interface ConfiguresOhai {
}

View File

@ -1,53 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.config.multibindings.MapBinder;
import org.jclouds.ohai.suppliers.UptimeSecondsSupplier;
import com.google.common.base.Supplier;
import com.google.inject.Provides;
/**
* Wires the components needed to parse ohai data from a JVM
*
* @author Adrian Cole
*/
@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;
}
}

View File

@ -1,188 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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 static org.jclouds.chef.util.ChefUtils.ohaiAutomaticAttributeBinder;
import static org.jclouds.chef.util.ChefUtils.toOhaiTime;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Provider;
import javax.inject.Singleton;
import org.jclouds.domain.JsonBall;
import org.jclouds.json.Json;
import org.jclouds.ohai.Automatic;
import org.jclouds.ohai.AutomaticSupplier;
import org.jclouds.ohai.config.multibindings.MapBinder;
import org.jclouds.ohai.functions.ByteArrayToMacAddress;
import org.jclouds.ohai.functions.MapSetToMultimap;
import com.google.common.base.Function;
import com.google.common.base.Supplier;
import com.google.common.collect.Multimap;
import com.google.inject.AbstractModule;
import com.google.inject.Provides;
import com.google.inject.TypeLiteral;
/**
* Wires the components needed to parse ohai data
*
* @author Adrian Cole
*/
@ConfiguresOhai
public class OhaiModule extends AbstractModule {
@Override
protected void configure() {
bind(new TypeLiteral<Function<byte[], String>>() {
}).to(new TypeLiteral<ByteArrayToMacAddress>() {
});
bindOhai();
}
@Provides
@Automatic
protected Supplier<Map<String, JsonBall>> provideAutomatic(AutomaticSupplier in) {
return in;
}
@Provides
@Automatic
Multimap<String, Supplier<JsonBall>> provideAutomatic(MapSetToMultimap<String, Supplier<JsonBall>> converter,
@Automatic Map<String, Set<Supplier<JsonBall>>> input) {
return converter.apply(input);
}
@Named("systemProperties")
@Provides
protected Properties systemProperties() {
return System.getProperties();
}
public MapBinder<String, Supplier<JsonBall>> bindOhai() {
MapBinder<String, Supplier<JsonBall>> mapbinder = ohaiAutomaticAttributeBinder(binder()).permitDuplicates();
mapbinder.addBinding("ohai_time").to(OhaiTimeProvider.class);
mapbinder.addBinding("jvm/system").to(SystemPropertiesProvider.class);
mapbinder.addBinding("platform").to(PlatformProvider.class);
mapbinder.addBinding("platform_version").to(PlatformVersionProvider.class);
mapbinder.addBinding("current_user").to(CurrentUserProvider.class);
return mapbinder;
}
@Singleton
public static class OhaiTimeProvider implements Supplier<JsonBall> {
private final Provider<Long> timeProvider;
@Inject
OhaiTimeProvider(Provider<Long> timeProvider) {
this.timeProvider = timeProvider;
}
@Override
public JsonBall get() {
return toOhaiTime(timeProvider.get());
}
}
@Provides
protected Long millis() {
return System.currentTimeMillis();
}
@Singleton
public static class SystemPropertiesProvider implements Supplier<JsonBall> {
private final Json json;
private final Properties systemProperties;
@Inject
SystemPropertiesProvider(Json json, @Named("systemProperties") Properties systemProperties) {
this.json = json;
this.systemProperties = systemProperties;
}
@Override
public JsonBall get() {
return new JsonBall(json.toJson(systemProperties));
}
}
@Singleton
public static class PlatformProvider extends SystemPropertyProvider {
@Inject
PlatformProvider(@Named("systemProperties") Properties systemProperties) {
super("os.name", systemProperties);
}
@Override
public JsonBall get() {
JsonBall returnValue = super.get();
return returnValue != null ? new JsonBall(returnValue.toString().replaceAll("[ -]", "").toLowerCase()) : null;
}
}
@Singleton
public static class PlatformVersionProvider extends SystemPropertyProvider {
@Inject
PlatformVersionProvider(@Named("systemProperties") Properties systemProperties) {
super("os.version", systemProperties);
}
}
@Singleton
public static class CurrentUserProvider extends SystemPropertyProvider {
@Inject
CurrentUserProvider(@Named("systemProperties") Properties systemProperties) {
super("user.name", systemProperties);
}
}
public static class SystemPropertyProvider implements Supplier<JsonBall> {
private final Properties systemProperties;
private final String property;
@Inject
SystemPropertyProvider(String property, @Named("systemProperties") Properties systemProperties) {
this.property = property;
this.systemProperties = systemProperties;
}
@Override
public JsonBall get() {
return systemProperties.containsKey(property) ? new JsonBall(systemProperties.getProperty(property)) : null;
}
}
}

View File

@ -1,38 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.multibindings;
import com.google.inject.BindingAnnotation;
import java.lang.annotation.Retention;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* An internal binding annotation applied to each element in a multibinding.
* All elements are assigned a globally-unique id to allow different modules
* to contribute multibindings independently.
*
* @author jessewilson@google.com (Jesse Wilson)
*/
@Retention(RUNTIME) @BindingAnnotation
@interface Element {
String setName();
int uniqueId();
}

View File

@ -1,537 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.multibindings;
import static com.google.inject.util.Types.newParameterizedTypeWithOwner;
import static org.jclouds.ohai.config.multibindings.Multibinder.checkConfiguration;
import static org.jclouds.ohai.config.multibindings.Multibinder.checkNotNull;
import static org.jclouds.ohai.config.multibindings.Multibinder.setOf;
import java.lang.annotation.Annotation;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;
import org.jclouds.ohai.config.multibindings.Multibinder.RealMultibinder;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.inject.Binder;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.Module;
import com.google.inject.Provider;
import com.google.inject.TypeLiteral;
import com.google.inject.binder.LinkedBindingBuilder;
import com.google.inject.spi.Dependency;
import com.google.inject.spi.ProviderWithDependencies;
import com.google.inject.util.Types;
/**
* An API to bind multiple map entries separately, only to later inject them as
* a complete map. MapBinder is intended for use in your application's module:
*
* <pre>
* <code>
* public class SnacksModule extends AbstractModule {
* protected void configure() {
* MapBinder&lt;String, Snack&gt; mapbinder
* = MapBinder.newMapBinder(binder(), String.class, Snack.class);
* mapbinder.addBinding("twix").toInstance(new Twix());
* mapbinder.addBinding("snickers").toProvider(SnickersProvider.class);
* mapbinder.addBinding("skittles").to(Skittles.class);
* }
* }</code>
* </pre>
*
* <p>
* With this binding, a {@link Map}{@code <String, Snack>} can now be injected:
*
* <pre>
* <code>
* class SnackMachine {
* {@literal @}Inject
* public SnackMachine(Map&lt;String, Snack&gt; snacks) { ... }
* }</code>
* </pre>
*
* <p>
* In addition to binding {@code Map<K, V>}, a mapbinder will also bind {@code
* Map<K, Provider<V>>} for lazy value provision:
*
* <pre>
* <code>
* class SnackMachine {
* {@literal @}Inject
* public SnackMachine(Map&lt;String, Provider&lt;Snack&gt;&gt; snackSuppliers) { ... }
* }</code>
* </pre>
*
* <p>
* Contributing mapbindings from different modules is supported. For example, it
* is okay to have both {@code CandyModule} and {@code ChipsModule} both create
* their own {@code MapBinder<String, Snack>}, and to each contribute bindings
* to the snacks map. When that map is injected, it will contain entries from
* both modules.
*
* <p>
* The map's iteration order is consistent with the binding order. This is
* convenient when multiple elements are contributed by the same module because
* that module can order its bindings appropriately. Avoid relying on the
* iteration order of elements contributed by different modules, since there is
* no equivalent mechanism to order modules.
*
* <p>
* Values are resolved at map injection time. If a value is bound to a provider,
* that provider's get method will be called each time the map is injected
* (unless the binding is also scoped, or a map of providers is injected).
*
* <p>
* Annotations are used to create different maps of the same key/value type.
* Each distinct annotation gets its own independent map.
*
* <p>
* <strong>Keys must be distinct.</strong> If the same key is bound more than
* once, map injection will fail. However, use {@link #permitDuplicates()} in
* order to allow duplicate keys; extra bindings to {@code Map<K, Set<V>>} and
* {@code Map<K, Set<Provider<V>>} will be added.
*
* <p>
* <strong>Keys must be non-null.</strong> {@code addBinding(null)} will throw
* an unchecked exception.
*
* <p>
* <strong>Values must be non-null to use map injection.</strong> If any value
* is null, map injection will fail (although injecting a map of providers will
* not).
*
* @author dpb@google.com (David P. Baker)
*/
public abstract class MapBinder<K, V> {
private MapBinder() {
}
/**
* Returns a new mapbinder that collects entries of {@code keyType}/{@code
* valueType} in a {@link Map} that is itself bound with no binding
* annotation.
*/
public static <K, V> MapBinder<K, V> newMapBinder(Binder binder, TypeLiteral<K> keyType, TypeLiteral<V> valueType) {
binder = binder.skipSources(MapBinder.class, RealMapBinder.class);
return newMapBinder(binder, valueType, Key.get(mapOf(keyType, valueType)), Key.get(mapOfProviderOf(keyType,
valueType)), Key.get(mapOf(keyType, setOf(valueType))), Key.get(mapOfSetOfProviderOf(keyType, valueType)),
Multibinder.newSetBinder(binder, entryOfProviderOf(keyType, valueType)));
}
/**
* Returns a new mapbinder that collects entries of {@code keyType}/{@code
* valueType} in a {@link Map} that is itself bound with no binding
* annotation.
*/
public static <K, V> MapBinder<K, V> newMapBinder(Binder binder, Class<K> keyType, Class<V> valueType) {
return newMapBinder(binder, TypeLiteral.get(keyType), TypeLiteral.get(valueType));
}
/**
* Returns a new mapbinder that collects entries of {@code keyType}/{@code
* valueType} in a {@link Map} that is itself bound with {@code annotation}.
*/
public static <K, V> MapBinder<K, V> newMapBinder(Binder binder, TypeLiteral<K> keyType, TypeLiteral<V> valueType,
Annotation annotation) {
binder = binder.skipSources(MapBinder.class, RealMapBinder.class);
return newMapBinder(binder, valueType, Key.get(mapOf(keyType, valueType), annotation), Key.get(mapOfProviderOf(
keyType, valueType), annotation), Key.get(mapOf(keyType, setOf(valueType)), annotation), Key.get(
mapOfSetOfProviderOf(keyType, valueType), annotation), Multibinder.newSetBinder(binder, entryOfProviderOf(
keyType, valueType), annotation));
}
/**
* Returns a new mapbinder that collects entries of {@code keyType}/{@code
* valueType} in a {@link Map} that is itself bound with {@code annotation}.
*/
public static <K, V> MapBinder<K, V> newMapBinder(Binder binder, Class<K> keyType, Class<V> valueType,
Annotation annotation) {
return newMapBinder(binder, TypeLiteral.get(keyType), TypeLiteral.get(valueType), annotation);
}
/**
* Returns a new mapbinder that collects entries of {@code keyType}/{@code
* valueType} in a {@link Map} that is itself bound with {@code
* annotationType}.
*/
public static <K, V> MapBinder<K, V> newMapBinder(Binder binder, TypeLiteral<K> keyType, TypeLiteral<V> valueType,
Class<? extends Annotation> annotationType) {
binder = binder.skipSources(MapBinder.class, RealMapBinder.class);
return newMapBinder(binder, valueType, Key.get(mapOf(keyType, valueType), annotationType), Key.get(
mapOfProviderOf(keyType, valueType), annotationType), Key.get(mapOf(keyType, setOf(valueType)),
annotationType), Key.get(mapOfSetOfProviderOf(keyType, valueType), annotationType), Multibinder
.newSetBinder(binder, entryOfProviderOf(keyType, valueType), annotationType));
}
/**
* Returns a new mapbinder that collects entries of {@code keyType}/{@code
* valueType} in a {@link Map} that is itself bound with {@code
* annotationType}.
*/
public static <K, V> MapBinder<K, V> newMapBinder(Binder binder, Class<K> keyType, Class<V> valueType,
Class<? extends Annotation> annotationType) {
return newMapBinder(binder, TypeLiteral.get(keyType), TypeLiteral.get(valueType), annotationType);
}
@SuppressWarnings("unchecked")
// a map of <K, V> is safely a Map<K, V>
private static <K, V> TypeLiteral<Map<K, V>> mapOf(TypeLiteral<K> keyType, TypeLiteral<V> valueType) {
return (TypeLiteral<Map<K, V>>) TypeLiteral.get(Types.mapOf(keyType.getType(), valueType.getType()));
}
@SuppressWarnings("unchecked")
// a provider map <K, V> is safely a Map<K, Provider<V>>
private static <K, V> TypeLiteral<Map<K, Provider<V>>> mapOfProviderOf(TypeLiteral<K> keyType,
TypeLiteral<V> valueType) {
return (TypeLiteral<Map<K, Provider<V>>>) TypeLiteral.get(Types.mapOf(keyType.getType(), Types
.providerOf(valueType.getType())));
}
@SuppressWarnings("unchecked")
// a provider map <K, Set<V>> is safely a Map<K, Set<Provider<V>>>
private static <K, V> TypeLiteral<Map<K, Set<Provider<V>>>> mapOfSetOfProviderOf(TypeLiteral<K> keyType,
TypeLiteral<V> valueType) {
return (TypeLiteral<Map<K, Set<Provider<V>>>>) TypeLiteral.get(Types.mapOf(keyType.getType(), Types.setOf(Types
.providerOf(valueType.getType()))));
}
@SuppressWarnings("unchecked")
// a provider entry <K, V> is safely a Map.Entry<K, Provider<V>>
private static <K, V> TypeLiteral<Map.Entry<K, Provider<V>>> entryOfProviderOf(TypeLiteral<K> keyType,
TypeLiteral<V> valueType) {
return (TypeLiteral<Entry<K, Provider<V>>>) TypeLiteral.get(newParameterizedTypeWithOwner(Map.class, Entry.class,
keyType.getType(), Types.providerOf(valueType.getType())));
}
private static <K, V> MapBinder<K, V> newMapBinder(Binder binder, TypeLiteral<V> valueType, Key<Map<K, V>> mapKey,
Key<Map<K, Provider<V>>> providerMapKey, Key<Map<K, Set<V>>> multimapKey,
Key<Map<K, Set<Provider<V>>>> providerMultimapKey, Multibinder<Entry<K, Provider<V>>> entrySetBinder) {
RealMapBinder<K, V> mapBinder = new RealMapBinder<K, V>(binder, valueType, mapKey, providerMapKey, multimapKey,
providerMultimapKey, entrySetBinder);
binder.install(mapBinder);
return mapBinder;
}
/**
* Configures the {@code MapBinder} to handle duplicate entries.
* <p>
* When multiple equal keys are bound, the value that gets included in the
* map is arbitrary.
* <p>
* In addition to the {@code Map<K, V>} and {@code Map<K, Provider<V>>} maps
* that are normally bound, a {@code Map<K, Set<V>>} and {@code Map<K,
* Set<Provider<V>>>} are <em>also</em> bound, which contain all values bound
* to each key.
* <p>
* When multiple modules contribute elements to the map, this configuration
* option impacts all of them.
*
* @return this map binder
*/
public abstract MapBinder<K, V> permitDuplicates();
/**
* Returns a binding builder used to add a new entry in the map. Each key
* must be distinct (and non-null). Bound providers will be evaluated each
* time the map is injected.
*
* <p>
* It is an error to call this method without also calling one of the {@code
* to} methods on the returned binding builder.
*
* <p>
* Scoping elements independently is supported. Use the {@code in} method to
* specify a binding scope.
*/
public abstract LinkedBindingBuilder<V> addBinding(K key);
/**
* The actual mapbinder plays several roles:
*
* <p>
* As a MapBinder, it acts as a factory for LinkedBindingBuilders for each of
* the map's values. It delegates to a {@link Multibinder} of entries (keys
* to value providers).
*
* <p>
* As a Module, it installs the binding to the map itself, as well as to a
* corresponding map whose values are providers. It uses the entry set
* multibinder to construct the map and the provider map.
*
* <p>
* As a module, this implements equals() and hashcode() in order to trick
* Guice into executing its configure() method only once. That makes it so
* that multiple mapbinders can be created for the same target map, but only
* one is bound. Since the list of bindings is retrieved from the injector
* itself (and not the mapbinder), each mapbinder has access to all
* contributions from all equivalent mapbinders.
*
* <p>
* Rather than binding a single Map.Entry&lt;K, V&gt;, the map binder binds
* keys and values independently. This allows the values to be properly
* scoped.
*
* <p>
* We use a subclass to hide 'implements Module' from the public API.
*/
private static final class RealMapBinder<K, V> extends MapBinder<K, V> implements Module {
private final TypeLiteral<V> valueType;
private final Key<Map<K, V>> mapKey;
private final Key<Map<K, Provider<V>>> providerMapKey;
private final Key<Map<K, Set<V>>> multimapKey;
private final Key<Map<K, Set<Provider<V>>>> providerMultimapKey;
private final RealMultibinder<Map.Entry<K, Provider<V>>> entrySetBinder;
/*
* the target injector's binder. non-null until initialization, null
* afterwards
*/
private Binder binder;
private RealMapBinder(Binder binder, TypeLiteral<V> valueType, Key<Map<K, V>> mapKey,
Key<Map<K, Provider<V>>> providerMapKey, Key<Map<K, Set<V>>> multimapKey,
Key<Map<K, Set<Provider<V>>>> providerMultimapKey, Multibinder<Map.Entry<K, Provider<V>>> entrySetBinder) {
this.valueType = valueType;
this.mapKey = mapKey;
this.providerMapKey = providerMapKey;
this.multimapKey = multimapKey;
this.providerMultimapKey = providerMultimapKey;
this.entrySetBinder = (RealMultibinder<Entry<K, Provider<V>>>) entrySetBinder;
this.binder = binder;
}
@Override
public MapBinder<K, V> permitDuplicates() {
entrySetBinder.permitDuplicates();
binder.install(new MultimapBinder<K, V>(multimapKey, providerMultimapKey, entrySetBinder.getSetKey()));
return this;
}
/**
* This creates two bindings. One for the {@code Map.Entry<K,
* Provider<V>>} and another for {@code V}.
*/
@Override
public LinkedBindingBuilder<V> addBinding(K key) {
checkNotNull(key, "key");
checkConfiguration(!isInitialized(), "MapBinder was already initialized");
Key<V> valueKey = Key.get(valueType, new RealElement(entrySetBinder.getSetName()));
entrySetBinder.addBinding().toInstance(new MapEntry<K, Provider<V>>(key, binder.getProvider(valueKey)));
return binder.bind(valueKey);
}
public void configure(Binder binder) {
checkConfiguration(!isInitialized(), "MapBinder was already initialized");
final ImmutableSet<Dependency<?>> dependencies = ImmutableSet.<Dependency<?>> of(Dependency.get(entrySetBinder
.getSetKey()));
// Binds a Map<K, Provider<V>> from a collection of Map<Entry<K,
// Provider<V>>.
final Provider<Set<Entry<K, Provider<V>>>> entrySetProvider = binder.getProvider(entrySetBinder.getSetKey());
binder.bind(providerMapKey).toProvider(new ProviderWithDependencies<Map<K, Provider<V>>>() {
private Map<K, Provider<V>> providerMap;
@SuppressWarnings("unused")
@Inject
void initialize(Injector injector) {
RealMapBinder.this.binder = null;
boolean permitDuplicates = entrySetBinder.permitsDuplicates(injector);
Map<K, Provider<V>> providerMapMutable = new LinkedHashMap<K, Provider<V>>();
for (Entry<K, Provider<V>> entry : entrySetProvider.get()) {
Provider<V> previous = providerMapMutable.put(entry.getKey(), entry.getValue());
checkConfiguration(previous == null || permitDuplicates,
"Map injection failed due to duplicated key \"%s\"", entry.getKey());
}
providerMap = ImmutableMap.copyOf(providerMapMutable);
}
public Map<K, Provider<V>> get() {
return providerMap;
}
public Set<Dependency<?>> getDependencies() {
return dependencies;
}
});
final Provider<Map<K, Provider<V>>> mapProvider = binder.getProvider(providerMapKey);
binder.bind(mapKey).toProvider(new ProviderWithDependencies<Map<K, V>>() {
public Map<K, V> get() {
Map<K, V> map = new LinkedHashMap<K, V>();
for (Entry<K, Provider<V>> entry : mapProvider.get().entrySet()) {
V value = entry.getValue().get();
K key = entry.getKey();
checkConfiguration(value != null, "Map injection failed due to null value for key \"%s\"", key);
map.put(key, value);
}
return Collections.unmodifiableMap(map);
}
public Set<Dependency<?>> getDependencies() {
return dependencies;
}
});
}
private boolean isInitialized() {
return binder == null;
}
@Override
public boolean equals(Object o) {
return o instanceof RealMapBinder<?, ?> && ((RealMapBinder<?, ?>) o).mapKey.equals(mapKey);
}
@Override
public int hashCode() {
return mapKey.hashCode();
}
/**
* Binds {@code Map<K, Set<V>>} and {{@code Map<K, Set<Provider<V>>>}.
*/
private static final class MultimapBinder<K, V> implements Module {
private final Key<Map<K, Set<V>>> multimapKey;
private final Key<Map<K, Set<Provider<V>>>> providerMultimapKey;
private final Key<Set<Entry<K, Provider<V>>>> entrySetKey;
public MultimapBinder(Key<Map<K, Set<V>>> multimapKey, Key<Map<K, Set<Provider<V>>>> providerMultimapKey,
Key<Set<Entry<K, Provider<V>>>> entrySetKey) {
this.multimapKey = multimapKey;
this.providerMultimapKey = providerMultimapKey;
this.entrySetKey = entrySetKey;
}
public void configure(Binder binder) {
final ImmutableSet<Dependency<?>> dependencies = ImmutableSet.<Dependency<?>> of(Dependency
.get(entrySetKey));
final Provider<Set<Entry<K, Provider<V>>>> entrySetProvider = binder.getProvider(entrySetKey);
// Binds a Map<K, Set<Provider<V>>> from a collection of
// Map<Entry<K, Provider<V>> if
// permitDuplicates was called.
binder.bind(providerMultimapKey).toProvider(new ProviderWithDependencies<Map<K, Set<Provider<V>>>>() {
private Map<K, Set<Provider<V>>> providerMultimap;
@SuppressWarnings("unused")
@Inject
void initialize(Injector injector) {
Map<K, ImmutableSet.Builder<Provider<V>>> providerMultimapMutable = new LinkedHashMap<K, ImmutableSet.Builder<Provider<V>>>();
for (Entry<K, Provider<V>> entry : entrySetProvider.get()) {
if (!providerMultimapMutable.containsKey(entry.getKey())) {
providerMultimapMutable.put(entry.getKey(), ImmutableSet.<Provider<V>> builder());
}
providerMultimapMutable.get(entry.getKey()).add(entry.getValue());
}
ImmutableMap.Builder<K, Set<Provider<V>>> providerMultimapBuilder = ImmutableMap.builder();
for (Entry<K, ImmutableSet.Builder<Provider<V>>> entry : providerMultimapMutable.entrySet()) {
providerMultimapBuilder.put(entry.getKey(), entry.getValue().build());
}
providerMultimap = providerMultimapBuilder.build();
}
public Map<K, Set<Provider<V>>> get() {
return providerMultimap;
}
public Set<Dependency<?>> getDependencies() {
return dependencies;
}
});
final Provider<Map<K, Set<Provider<V>>>> multimapProvider = binder.getProvider(providerMultimapKey);
binder.bind(multimapKey).toProvider(new ProviderWithDependencies<Map<K, Set<V>>>() {
public Map<K, Set<V>> get() {
ImmutableMap.Builder<K, Set<V>> multimapBuilder = ImmutableMap.builder();
for (Entry<K, Set<Provider<V>>> entry : multimapProvider.get().entrySet()) {
K key = entry.getKey();
ImmutableSet.Builder<V> valuesBuilder = ImmutableSet.builder();
for (Provider<V> valueProvider : entry.getValue()) {
V value = valueProvider.get();
checkConfiguration(value != null, "Multimap injection failed due to null value for key \"%s\"",
key);
valuesBuilder.add(value);
}
multimapBuilder.put(key, valuesBuilder.build());
}
return multimapBuilder.build();
}
public Set<Dependency<?>> getDependencies() {
return dependencies;
}
});
}
}
private static final class MapEntry<K, V> implements Map.Entry<K, V> {
private final K key;
private final V value;
private MapEntry(K key, V value) {
this.key = key;
this.value = value;
}
public K getKey() {
return key;
}
public V getValue() {
return value;
}
public V setValue(V value) {
throw new UnsupportedOperationException();
}
@Override
public boolean equals(Object obj) {
return obj instanceof Map.Entry<?, ?> && key.equals(((Map.Entry<?, ?>) obj).getKey())
&& value.equals(((Map.Entry<?, ?>) obj).getValue());
}
@Override
public int hashCode() {
return 127 * ("key".hashCode() ^ key.hashCode()) + 127 * ("value".hashCode() ^ value.hashCode());
}
@Override
public String toString() {
return "MapEntry(" + key + ", " + value + ")";
}
}
}
}

View File

@ -1,413 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.multibindings;
import static com.google.inject.name.Names.named;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import com.google.inject.AbstractModule;
import com.google.inject.Binder;
import com.google.inject.Binding;
import com.google.inject.ConfigurationException;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.Module;
import com.google.inject.Provider;
import com.google.inject.TypeLiteral;
import com.google.inject.binder.LinkedBindingBuilder;
import com.google.inject.internal.Errors;
import com.google.inject.spi.Dependency;
import com.google.inject.spi.HasDependencies;
import com.google.inject.spi.Message;
import com.google.inject.spi.Toolable;
import com.google.inject.util.Types;
/**
*
* An API to bind multiple values separately, only to later inject them as a
* complete collection. Multibinder is intended for use in your application's
* module:
*
* <pre>
* <code>
* public class SnacksModule extends AbstractModule {
* protected void configure() {
* Multibinder&lt;Snack&gt; multibinder
* = Multibinder.newSetBinder(binder(), Snack.class);
* multibinder.addBinding().toInstance(new Twix());
* multibinder.addBinding().toProvider(SnickersProvider.class);
* multibinder.addBinding().to(Skittles.class);
* }
* }</code>
* </pre>
*
* <p>
* With this binding, a {@link Set}{@code <Snack>} can now be injected:
*
* <pre>
* <code>
* class SnackMachine {
* {@literal @}Inject
* public SnackMachine(Set&lt;Snack&gt; snacks) { ... }
* }</code>
* </pre>
*
* <p>
* Contributing multibindings from different modules is supported. For example,
* it is okay to have both {@code CandyModule} and {@code ChipsModule} to both
* create their own {@code Multibinder<Snack>}, and to each contribute bindings
* to the set of snacks. When that set is injected, it will contain elements
* from both modules.
*
* <p>
* The set's iteration order is consistent with the binding order. This is
* convenient when multiple elements are contributed by the same module because
* that module can order its bindings appropriately. Avoid relying on the
* iteration order of elements contributed by different modules, since there is
* no equivalent mechanism to order modules.
*
* <p>
* Elements are resolved at set injection time. If an element is bound to a
* provider, that provider's get method will be called each time the set is
* injected (unless the binding is also scoped).
*
* <p>
* Annotations are be used to create different sets of the same element type.
* Each distinct annotation gets its own independent collection of elements.
*
* <p>
* <strong>Elements must be distinct.</strong> If multiple bound elements have
* the same value, set injection will fail.
*
* <p>
* <strong>Elements must be non-null.</strong> If any set element is null, set
* injection will fail.
*
* @author jessewilson@google.com (Jesse Wilson)
*/
public abstract class Multibinder<T> {
private Multibinder() {
}
/**
* Returns a new multibinder that collects instances of {@code type} in a
* {@link Set} that is itself bound with no binding annotation.
*/
public static <T> Multibinder<T> newSetBinder(Binder binder, TypeLiteral<T> type) {
binder = binder.skipSources(RealMultibinder.class, Multibinder.class);
RealMultibinder<T> result = new RealMultibinder<T>(binder, type, "", Key.get(Multibinder.<T> setOf(type)));
binder.install(result);
return result;
}
/**
* Returns a new multibinder that collects instances of {@code type} in a
* {@link Set} that is itself bound with no binding annotation.
*/
public static <T> Multibinder<T> newSetBinder(Binder binder, Class<T> type) {
return newSetBinder(binder, TypeLiteral.get(type));
}
/**
* Returns a new multibinder that collects instances of {@code type} in a
* {@link Set} that is itself bound with {@code annotation}.
*/
public static <T> Multibinder<T> newSetBinder(Binder binder, TypeLiteral<T> type, Annotation annotation) {
binder = binder.skipSources(RealMultibinder.class, Multibinder.class);
RealMultibinder<T> result = new RealMultibinder<T>(binder, type, annotation.toString(), Key.get(Multibinder
.<T> setOf(type), annotation));
binder.install(result);
return result;
}
/**
* Returns a new multibinder that collects instances of {@code type} in a
* {@link Set} that is itself bound with {@code annotation}.
*/
public static <T> Multibinder<T> newSetBinder(Binder binder, Class<T> type, Annotation annotation) {
return newSetBinder(binder, TypeLiteral.get(type), annotation);
}
/**
* Returns a new multibinder that collects instances of {@code type} in a
* {@link Set} that is itself bound with {@code annotationType}.
*/
public static <T> Multibinder<T> newSetBinder(Binder binder, TypeLiteral<T> type,
Class<? extends Annotation> annotationType) {
binder = binder.skipSources(RealMultibinder.class, Multibinder.class);
RealMultibinder<T> result = new RealMultibinder<T>(binder, type, "@" + annotationType.getName(), Key.get(
Multibinder.<T> setOf(type), annotationType));
binder.install(result);
return result;
}
/**
* Returns a new multibinder that collects instances of {@code type} in a
* {@link Set} that is itself bound with {@code annotationType}.
*/
public static <T> Multibinder<T> newSetBinder(Binder binder, Class<T> type,
Class<? extends Annotation> annotationType) {
return newSetBinder(binder, TypeLiteral.get(type), annotationType);
}
@SuppressWarnings("unchecked")
// wrapping a T in a Set safely returns a Set<T>
static <T> TypeLiteral<Set<T>> setOf(TypeLiteral<T> elementType) {
Type type = Types.setOf(elementType.getType());
return (TypeLiteral<Set<T>>) TypeLiteral.get(type);
}
/**
* Configures the bound set to silently discard duplicate elements. When
* multiple equal values are bound, the one that gets included is arbitrary.
* When multiple modules contribute elements to the set, this configuration
* option impacts all of them.
*
* @return this multibinder
*/
public abstract Multibinder<T> permitDuplicates();
/**
* Returns a binding builder used to add a new element in the set. Each bound
* element must have a distinct value. Bound providers will be evaluated each
* time the set is injected.
*
* <p>
* It is an error to call this method without also calling one of the {@code
* to} methods on the returned binding builder.
*
* <p>
* Scoping elements independently is supported. Use the {@code in} method to
* specify a binding scope.
*/
public abstract LinkedBindingBuilder<T> addBinding();
/**
* The actual multibinder plays several roles:
*
* <p>
* As a Multibinder, it acts as a factory for LinkedBindingBuilders for each
* of the set's elements. Each binding is given an annotation that identifies
* it as a part of this set.
*
* <p>
* As a Module, it installs the binding to the set itself. As a module, this
* implements equals() and hashcode() in order to trick Guice into executing
* its configure() method only once. That makes it so that multiple
* multibinders can be created for the same target collection, but only one
* is bound. Since the list of bindings is retrieved from the injector itself
* (and not the multibinder), each multibinder has access to all
* contributions from all multibinders.
*
* <p>
* As a Provider, this constructs the set instances.
*
* <p>
* We use a subclass to hide 'implements Module, Provider' from the public
* API.
*/
static final class RealMultibinder<T> extends Multibinder<T> implements Module, Provider<Set<T>>, HasDependencies {
private final TypeLiteral<T> elementType;
private final String setName;
private final Key<Set<T>> setKey;
private final Key<Boolean> permitDuplicatesKey;
/*
* the target injector's binder. non-null until initialization, null
* afterwards
*/
private Binder binder;
/*
* a provider for each element in the set. null until initialization,
* non-null afterwards
*/
private List<Provider<T>> providers;
private Set<Dependency<?>> dependencies;
/**
* whether duplicates are allowed. Possibly configured by a different
* instance
*/
private boolean permitDuplicates;
private RealMultibinder(Binder binder, TypeLiteral<T> elementType, String setName, Key<Set<T>> setKey) {
this.binder = checkNotNull(binder, "binder");
this.elementType = checkNotNull(elementType, "elementType");
this.setName = checkNotNull(setName, "setName");
this.setKey = checkNotNull(setKey, "setKey");
this.permitDuplicatesKey = Key.get(Boolean.class, named(toString() + " permits duplicates"));
}
public void configure(Binder binder) {
checkConfiguration(!isInitialized(), "Multibinder was already initialized");
binder.bind(setKey).toProvider(this);
}
@Override
public Multibinder<T> permitDuplicates() {
binder.install(new PermitDuplicatesModule(permitDuplicatesKey));
return this;
}
@Override
public LinkedBindingBuilder<T> addBinding() {
checkConfiguration(!isInitialized(), "Multibinder was already initialized");
return binder.bind(Key.get(elementType, new RealElement(setName)));
}
/**
* Invoked by Guice at Injector-creation time to prepare providers for
* each element in this set. At this time the set's size is known, but its
* contents are only evaluated when get() is invoked.
*/
@Toolable
@Inject
void initialize(Injector injector) {
providers = Lists.newArrayList();
List<Dependency<?>> dependencies = Lists.newArrayList();
for (Binding<?> entry : injector.findBindingsByType(elementType)) {
if (keyMatches(entry.getKey())) {
@SuppressWarnings("unchecked")
// protected by findBindingsByType()
Binding<T> binding = (Binding<T>) entry;
providers.add(binding.getProvider());
dependencies.add(Dependency.get(binding.getKey()));
}
}
this.dependencies = ImmutableSet.copyOf(dependencies);
this.permitDuplicates = permitsDuplicates(injector);
this.binder = null;
}
boolean permitsDuplicates(Injector injector) {
return injector.getBindings().containsKey(permitDuplicatesKey);
}
private boolean keyMatches(Key<?> key) {
return key.getTypeLiteral().equals(elementType) && key.getAnnotation() instanceof Element
&& ((Element) key.getAnnotation()).setName().equals(setName);
}
private boolean isInitialized() {
return binder == null;
}
public Set<T> get() {
checkConfiguration(isInitialized(), "Multibinder is not initialized");
Set<T> result = new LinkedHashSet<T>();
for (Provider<T> provider : providers) {
final T newValue = provider.get();
checkConfiguration(newValue != null, "Set injection failed due to null element");
checkConfiguration(result.add(newValue) || permitDuplicates,
"Set injection failed due to duplicated element \"%s\"", newValue);
}
return Collections.unmodifiableSet(result);
}
String getSetName() {
return setName;
}
Key<Set<T>> getSetKey() {
return setKey;
}
public Set<Dependency<?>> getDependencies() {
return dependencies;
}
@Override
public boolean equals(Object o) {
return o instanceof RealMultibinder<?> && ((RealMultibinder<?>) o).setKey.equals(setKey);
}
@Override
public int hashCode() {
return setKey.hashCode();
}
@Override
public String toString() {
return new StringBuilder().append(setName).append(setName.length() > 0 ? " " : "").append("Multibinder<")
.append(elementType).append(">").toString();
}
}
/**
* We install the permit duplicates configuration as its own binding, all by
* itself. This way, if only one of a multibinder's users remember to call
* permitDuplicates(), they're still permitted.
*/
private static class PermitDuplicatesModule extends AbstractModule {
private final Key<Boolean> key;
PermitDuplicatesModule(Key<Boolean> key) {
this.key = key;
}
@Override
protected void configure() {
bind(key).toInstance(true);
}
@Override
public boolean equals(Object o) {
return o instanceof PermitDuplicatesModule && ((PermitDuplicatesModule) o).key.equals(key);
}
@Override
public int hashCode() {
return getClass().hashCode() ^ key.hashCode();
}
}
static void checkConfiguration(boolean condition, String format, Object... args) {
if (condition) {
return;
}
throw new ConfigurationException(ImmutableSet.of(new Message(Errors.format(format, args))));
}
static <T> T checkNotNull(T reference, String name) {
if (reference != null) {
return reference;
}
NullPointerException npe = new NullPointerException(name);
throw new ConfigurationException(ImmutableSet.of(new Message(ImmutableList.of(), npe.toString(), npe)));
}
}

View File

@ -1,69 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.multibindings;
import java.lang.annotation.Annotation;
import java.util.concurrent.atomic.AtomicInteger;
/**
* @author jessewilson@google.com (Jesse Wilson)
*/
class RealElement implements Element {
private static final AtomicInteger nextUniqueId = new AtomicInteger(1);
private final int uniqueId;
private final String setName;
RealElement(String setName) {
uniqueId = nextUniqueId.getAndIncrement();
this.setName = setName;
}
public String setName() {
return setName;
}
public int uniqueId() {
return uniqueId;
}
public Class<? extends Annotation> annotationType() {
return Element.class;
}
@Override public String toString() {
return "@" + Element.class.getName() + "(setName=" + setName
+ ",uniqueId=" + uniqueId + ")";
}
@Override public boolean equals(Object o) {
return o instanceof Element
&& ((Element) o).setName().equals(setName())
&& ((Element) o).uniqueId() == uniqueId();
}
@Override public int hashCode() {
return 127 * ("setName".hashCode() ^ setName.hashCode())
+ 127 * ("uniqueId".hashCode() ^ uniqueId);
}
}

View File

@ -1,24 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.
* ====================================================================
*/
/**
* Taken from r1154 of Guice, as they decided to stop supporting multiple bindings and instead silently throw them away.
*/
package org.jclouds.ohai.config.multibindings;

View File

@ -1,57 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.functions;
import static com.google.common.collect.Iterables.transform;
import static com.google.common.collect.Lists.partition;
import static com.google.common.primitives.Bytes.asList;
import static com.google.common.primitives.Bytes.toArray;
import java.util.List;
import javax.inject.Singleton;
import org.jclouds.crypto.CryptoStreams;
import com.google.common.base.Function;
import com.google.common.base.Joiner;
/**
*
* Creates a string in the form: {@code 00:26:bb:09:e6:c4 }
*
* @author Adrian Cole
*/
@Singleton
public class ByteArrayToMacAddress implements Function<byte[], String> {
@Override
public String apply(byte[] from) {
return Joiner.on(':').join(transform(partition(asList(from), 1), new Function<List<Byte>, String>() {
@Override
public String apply(List<Byte> from) {
return CryptoStreams.hex(toArray(from));
}
}));
}
}

View File

@ -1,49 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.functions;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;
import javax.inject.Singleton;
import com.google.common.base.Function;
import com.google.common.collect.LinkedHashMultimap;
import com.google.common.collect.Multimap;
/**
*
* @author Adrian Cole
*/
@Singleton
public class MapSetToMultimap<K, V> implements Function<Map<K, Set<V>>, Multimap<K, V>> {
@Override
public Multimap<K, V> apply(Map<K, Set<V>> from) {
Multimap<K, V> returnV = LinkedHashMultimap.create();
for (Entry<K, Set<V>> entry : from.entrySet()) {
for (V value : entry.getValue())
returnV.put(entry.getKey(), value);
}
return returnV;
}
}

View File

@ -1,161 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.functions;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.domain.JsonBall;
import org.jclouds.json.Json;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.base.Splitter;
import com.google.common.base.Supplier;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import com.google.common.collect.Sets;
import com.google.inject.TypeLiteral;
/**
*
*
* @author Adrian Cole
*/
@Singleton
public class NestSlashKeys implements Function<Multimap<String, Supplier<JsonBall>>, Map<String, JsonBall>> {
private final Json json;
@Inject
NestSlashKeys(Json json) {
this.json = checkNotNull(json, "json");
}
@Override
public Map<String, JsonBall> apply(Multimap<String, Supplier<JsonBall>> from) {
Map<String, JsonBall> autoAttrs = mergeSameKeys(from);
Map<String, JsonBall> modifiableFlatMap = Maps.newLinkedHashMap(Maps.filterKeys(autoAttrs,
new Predicate<String>() {
@Override
public boolean apply(String input) {
return input.indexOf('/') == -1;
}
}));
Map<String, JsonBall> withSlashesMap = Maps.difference(autoAttrs, modifiableFlatMap).entriesOnlyOnLeft();
for (Entry<String, JsonBall> entry : withSlashesMap.entrySet()) {
List<String> keyParts = Lists.newArrayList(Splitter.on('/').split(entry.getKey()));
JsonBall toInsert = entry.getValue();
try {
putUnderContext(keyParts, toInsert, modifiableFlatMap);
} catch (IllegalArgumentException e) {
throw new IllegalArgumentException("error inserting value in entry: " + entry.getKey(), e);
}
}
return modifiableFlatMap;
}
private Map<String, JsonBall> mergeSameKeys(Multimap<String, Supplier<JsonBall>> from) {
Map<String, JsonBall> merged = Maps.newLinkedHashMap();
for (Entry<String, Supplier<JsonBall>> entry : from.entries()) {
if (merged.containsKey(entry.getKey())) {
mergeAsPeer(entry.getKey(), entry.getValue().get(), merged);
} else {
merged.put(entry.getKey(), entry.getValue().get());
}
}
return merged;
}
@VisibleForTesting
void mergeAsPeer(String key, JsonBall value, Map<String, JsonBall> insertionContext) {
Map<String, JsonBall> valueContext = json.fromJson(insertionContext.get(key).toString(), mapLiteral);
Map<String, JsonBall> toPut = json.<Map<String, JsonBall>> fromJson(value.toString(), mapLiteral);
Set<String> uniques = Sets.difference(toPut.keySet(), valueContext.keySet());
for (String k : uniques)
valueContext.put(k, toPut.get(k));
Set<String> conflicts = Sets.difference(toPut.keySet(), uniques);
for (String k : conflicts) {
JsonBall v = toPut.get(k);
if (v.toString().matches("^\\{.*\\}$")) {
mergeAsPeer(k, v, valueContext);
} else {
// replace
valueContext.put(k, v);
}
}
insertionContext.put(key, new JsonBall(json.toJson(valueContext, mapLiteral)));
}
/**
* @param keyParts
* @param toInsert
* @param destination
* @throws IllegalArgumentException
* <p/>
* if destination.get(keyParts(0)) is not a map *
* <p/>
* keyParts is zero length
*/
void putUnderContext(List<String> keyParts, JsonBall toInsert, Map<String, JsonBall> destination) {
checkNotNull(keyParts, "keyParts");
checkArgument(keyParts.size() >= 1, "keyParts must contain at least one element");
checkNotNull(toInsert, "toInsert");
checkNotNull(destination, "destination");
String rootKey = keyParts.remove(0);
String rootValue = destination.containsKey(rootKey) ? destination.get(rootKey).toString() : "{}";
checkArgument(rootValue.matches("^\\{.*\\}$"), "value must be a hash: %s", rootValue);
Map<String, JsonBall> insertionContext = json.fromJson(rootValue, mapLiteral);
if (keyParts.size() == 1) {
if (!insertionContext.containsKey(keyParts.get(0))) {
insertionContext.put(keyParts.get(0), toInsert);
} else {
String key = keyParts.get(0);
mergeAsPeer(key, toInsert, insertionContext);
}
} else {
putUnderContext(keyParts, toInsert, insertionContext);
}
destination.put(rootKey, new JsonBall(json.toJson(insertionContext, mapLiteral)));
}
final Type mapLiteral = new TypeLiteral<Map<String, JsonBall>>() {
}.getType();
final Type listLiteral = new TypeLiteral<List<JsonBall>>() {
}.getType();
}

View File

@ -1,51 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.suppliers;
import java.lang.management.RuntimeMXBean;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.domain.JsonBall;
import com.google.common.base.Supplier;
/**
*
* @author Adrian Cole
*/
@Singleton
public class UptimeSecondsSupplier implements Supplier<JsonBall> {
@Inject
UptimeSecondsSupplier(RuntimeMXBean runtime) {
this.runtime = runtime;
}
private final RuntimeMXBean runtime;
@Override
public JsonBall get() {
long uptimeInSeconds = runtime.getUptime() / 1000;
return new JsonBall(uptimeInSeconds);
}
}

View File

@ -1,15 +0,0 @@
if [ ! -f /usr/bin/chef-client ]; then
apt-get update
apt-get install -y ruby ruby1.8-dev build-essential wget libruby-extras libruby1.8-extras
mkdir -p /tmp/bootchef
(
cd /tmp/bootchef
wget http://rubyforge.org/frs/download.php/69365/rubygems-1.3.6.tgz
tar xvf rubygems-1.3.6.tgz
cd rubygems-1.3.6
ruby setup.rb
cp /usr/bin/gem1.8 /usr/bin/gem
)
rm -rf /tmp/bootchef
gem install chef ohai --no-rdoc --no-ri --verbose
fi

View File

@ -1,72 +0,0 @@
;
;
; Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
;
; ====================================================================
; Licensed under the Apache License, Version 2.0 (the "License");
; you may not use this file except in compliance with the License.
; You may obtain a copy of the License at
;
; http://www.apache.org/licenses/LICENSE-2.0
;
; Unless required by applicable law or agreed to in writing, software
; distributed under the License is distributed on an "AS IS" BASIS,
; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
; See the License for the specific language governing permissions and
; limitations under the License.
; ====================================================================
;
(ns org.jclouds.chef-test
(:use [org.jclouds.chef] :reload-all)
(:use [clojure.test]))
(defn clean-stub-fixture
"This should allow basic tests to easily be run with another service."
[service account key & options]
(fn [f]
(with-chef-service [(apply chef-service service account key options)]
(doseq [databag (databags)]
(delete-databag databag))
(f))))
(use-fixtures :each (clean-stub-fixture "transientchef" "" ""))
(deftest chef-service?-test
(is (chef-service? *chef*)))
(deftest as-chef-service-test
(is (chef-service? (chef-service "transientchef" "" "")))
(is (chef-service? (as-chef-service *chef*)))
(is (chef-service? (as-chef-service (chef-context *chef*)))))
(deftest create-existing-databag-test
(is (not (databag-exists? "")))
(create-databag "fred")
(is (databag-exists? "fred")))
(deftest create-databag-test
(create-databag "fred")
(is (databag-exists? "fred")))
(deftest databags-test
(is (empty? (databags)))
(create-databag "fred")
(is (= 1 (count (databags)))))
(deftest databag-items-test
(create-databag "databag")
(is (empty? (databag-items "databag")))
(is (create-databag-item "databag" {:id "databag-item1" :value "databag-value1"}))
(is (create-databag-item "databag" {:id "databag-item2" :value "databag-value2"}))
(is (= 2 (count (databag-items "databag")))))
(deftest databag-item-test
(create-databag "databag")
(is (create-databag-item "databag" {:id "databag-item1" :value "databag-value1"}))
(is (create-databag-item "databag" {:id "databag-item2" :value "databag-value2"}))
(is (= {:id "databag-item2" :value "databag-value2"} (databag-item "databag" "databag-item2"))))
(deftest run-list-test
(update-run-list #{"recipe[foo]"} "tag")
(is (= ["recipe[foo]"] (run-list "tag"))))

View File

@ -1,378 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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 org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Collections;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import org.jclouds.chef.domain.ChecksumStatus;
import org.jclouds.chef.domain.Client;
import org.jclouds.chef.domain.CookbookVersion;
import org.jclouds.chef.domain.DatabagItem;
import org.jclouds.chef.domain.Node;
import org.jclouds.chef.domain.Resource;
import org.jclouds.chef.domain.Role;
import org.jclouds.chef.domain.SearchResult;
import org.jclouds.chef.domain.UploadSandbox;
import org.jclouds.crypto.CryptoStreams;
import org.jclouds.crypto.Pems;
import org.jclouds.io.InputSuppliers;
import org.jclouds.io.Payloads;
import org.jclouds.io.payloads.FilePayload;
import org.jclouds.json.Json;
import org.jclouds.rest.AuthorizationException;
import org.jclouds.rest.HttpClient;
import org.jclouds.rest.ResourceNotFoundException;
import org.testng.annotations.AfterClass;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.primitives.Bytes;
/**
* Tests behavior of {@code ChefClient}
*
* @author Adrian Cole
*/
@Test(groups = "live", testName = "chef.ChefClientLiveTest")
public abstract class BaseChefClientLiveTest {
protected String clientKey;
protected abstract void closeContexts();
protected abstract void recreateClientConnection() throws IOException;
protected abstract ChefClient getClientConnection();
protected abstract ChefClient getValidatorConnection();
protected abstract ChefClient getAdminConnection();
protected abstract HttpClient getHttp();
public abstract void setupClient() throws IOException;
protected String endpoint;
protected String user;
private Node node;
private Role role;
protected Json json;
protected DatabagItem databagItem;
public static final String PREFIX = System.getProperty("user.name") + "-jcloudstest";
public BaseChefClientLiveTest() {
super();
}
public void testCreateNewCookbook() throws Exception {
// define the file you want in the cookbook
FilePayload content = Payloads.newFilePayload(new File(System.getProperty("user.dir"), "pom.xml"));
content.setContentType("application/x-binary");
// get an md5 so that you can see if the server already has it or not
Payloads.calculateMD5(content);
// Note that java collections cannot effectively do equals or hashcodes on
// byte arrays,
// so let's convert to a list of bytes.
List<Byte> md5 = Bytes.asList(content.getContentMD5());
// request an upload site for this file
UploadSandbox site = getAdminConnection().getUploadSandboxForChecksums(ImmutableSet.of(md5));
try {
assert site.getChecksums().containsKey(md5) : md5 + " not in " + site.getChecksums();
ChecksumStatus status = site.getChecksums().get(md5);
if (status.needsUpload()) {
getHttp().put(status.getUrl(), content);
}
getAdminConnection().commitSandbox(site.getSandboxId(), true);
} catch (RuntimeException e) {
getAdminConnection().commitSandbox(site.getSandboxId(), false);
}
// create a new cookbook
CookbookVersion cookbook = new CookbookVersion("test3", "0.0.0");
cookbook.getRootFiles().add(new Resource(content));
// upload the cookbook to the remote server
getAdminConnection().updateCookbook("test3", "0.0.0", cookbook);
}
@Test(dependsOnMethods = "testCreateClient")
public void testGenerateKeyForClient() throws Exception {
clientKey = Pems.pem(getClientConnection().generateKeyForClient(PREFIX).getPrivateKey());
assertNotNull(clientKey);
recreateClientConnection();
getClientConnection().clientExists(PREFIX);
}
@Test(dependsOnMethods = "testCreateNewCookbook")
public void testListCookbooks() throws Exception {
for (String cookbook : getAdminConnection().listCookbooks())
for (String version : getAdminConnection().getVersionsOfCookbook(cookbook)) {
System.err.printf("%s/%s:%n", cookbook, version);
CookbookVersion cookbookO = getAdminConnection().getCookbook(cookbook, version);
for (Resource resource : ImmutableList.<Resource> builder().addAll(cookbookO.getDefinitions()).addAll(
cookbookO.getFiles()).addAll(cookbookO.getLibraries()).addAll(cookbookO.getSuppliers()).addAll(
cookbookO.getRecipes()).addAll(cookbookO.getResources()).addAll(cookbookO.getRootFiles()).addAll(
cookbookO.getTemplates()).build()) {
try {
InputStream stream = getHttp().get(resource.getUrl());
byte[] md5 = CryptoStreams.md5(InputSuppliers.of(stream));
assertEquals(md5, resource.getChecksum());
} catch (NullPointerException e) {
assert false : "resource not found: " + resource;
}
System.err.printf("resource %s ok%n", resource.getName());
}
}
}
@Test(dependsOnMethods = "testListCookbooks")
public void testUpdateCookbook() throws Exception {
for (String cookbook : getAdminConnection().listCookbooks())
for (String version : getAdminConnection().getVersionsOfCookbook(cookbook)) {
System.err.printf("%s/%s:%n", cookbook, version);
CookbookVersion cook = getAdminConnection().getCookbook(cookbook, version);
getAdminConnection().updateCookbook(cookbook, version, cook);
}
}
@Test(dependsOnMethods = "testUpdateCookbook")
public void testCreateCookbook() throws Exception {
for (String cookbook : getAdminConnection().listCookbooks())
for (String version : getAdminConnection().getVersionsOfCookbook(cookbook)) {
System.err.printf("%s/%s:%n", cookbook, version);
CookbookVersion cook = getAdminConnection().getCookbook(cookbook, version);
getAdminConnection().deleteCookbook(cookbook, version);
assert getAdminConnection().getCookbook(cookbook, version) == null : cookbook + version;
getAdminConnection().updateCookbook(cookbook, version, cook);
}
}
@Test(expectedExceptions = AuthorizationException.class)
public void testValidatorCannotListClients() throws Exception {
for (String client : getValidatorConnection().listClients())
assertNotNull(getValidatorConnection().getClient(client));
}
@Test(expectedExceptions = AuthorizationException.class)
public void testValidatorCannotDeleteClient() throws Exception {
getValidatorConnection().deleteClient(PREFIX);
}
@Test(expectedExceptions = AuthorizationException.class)
public void testValidatorCannotCreateClient() throws Exception {
getValidatorConnection().createClient(PREFIX);
}
@Test
public void testCreateClient() throws Exception {
getAdminConnection().deleteClient(PREFIX);
clientKey = Pems.pem(getAdminConnection().createClient(PREFIX).getPrivateKey());
recreateClientConnection();
getClientConnection().clientExists(PREFIX);
Set<String> clients = getAdminConnection().listClients();
assert clients.contains(PREFIX) : String.format("client %s not in %s", PREFIX, clients);
assertNotNull(getClientConnection().getClient(PREFIX));
}
@Test(dependsOnMethods = "testCreateClient")
public void testClientExists() throws Exception {
assertNotNull(getValidatorConnection().clientExists(PREFIX));
}
@Test
public void testListNodes() throws Exception {
Set<String> nodes = getAdminConnection().listNodes();
assertNotNull(nodes);
}
@Test(dependsOnMethods = "testCreateRole")
public void testCreateNode() throws Exception {
getAdminConnection().deleteNode(PREFIX);
getClientConnection().createNode(new Node(PREFIX, Collections.singleton("role[" + PREFIX + "]")));
node = getAdminConnection().getNode(PREFIX);
// TODO check recipes
assertNotNull(node);
Set<String> nodes = getAdminConnection().listNodes();
assert nodes.contains(PREFIX) : String.format("node %s not in %s", PREFIX, nodes);
}
@Test(dependsOnMethods = "testCreateNode")
public void testNodeExists() throws Exception {
assertNotNull(getClientConnection().nodeExists(PREFIX));
}
@Test(dependsOnMethods = "testNodeExists")
public void testUpdateNode() throws Exception {
for (String nodename : getClientConnection().listNodes()) {
Node node = getAdminConnection().getNode(nodename);
getAdminConnection().updateNode(node);
}
}
@Test
public void testListRoles() throws Exception {
Set<String> roles = getAdminConnection().listRoles();
assertNotNull(roles);
}
@Test(dependsOnMethods = "testCreateClient")
public void testCreateRole() throws Exception {
getAdminConnection().deleteRole(PREFIX);
getAdminConnection().createRole(new Role(PREFIX, Collections.singleton("recipe[java]")));
role = getAdminConnection().getRole(PREFIX);
assertNotNull(role);
assertEquals(role.getName(), PREFIX);
assertEquals(role.getRunList(), Collections.singleton("recipe[java]"));
}
@Test(dependsOnMethods = "testCreateRole")
public void testRoleExists() throws Exception {
assertNotNull(getClientConnection().roleExists(PREFIX));
}
@Test(dependsOnMethods = "testRoleExists")
public void testUpdateRole() throws Exception {
for (String rolename : getClientConnection().listRoles()) {
Role role = getAdminConnection().getRole(rolename);
getAdminConnection().updateRole(role);
}
}
@Test
public void testListDatabags() throws Exception {
Set<String> databags = getAdminConnection().listDatabags();
assertNotNull(databags);
}
@Test(dependsOnMethods = "testCreateClient")
public void testCreateDatabag() throws Exception {
getAdminConnection().deleteDatabag(PREFIX);
getAdminConnection().createDatabag(PREFIX);
}
@Test(dependsOnMethods = "testCreateDatabag")
public void testDatabagExists() throws Exception {
assertNotNull(getClientConnection().databagExists(PREFIX));
}
@Test(dependsOnMethods = "testCreateDatabagItem")
public void testListDatabagItems() throws Exception {
Set<String> databagItems = getAdminConnection().listDatabagItems(PREFIX);
assertNotNull(databagItems);
}
@Test(dependsOnMethods = { "testCreateDatabag", "testCreateRole" })
public void testCreateDatabagItem() throws Exception {
Properties config = new Properties();
config.setProperty("foo", "bar");
getAdminConnection().deleteDatabagItem(PREFIX, PREFIX);
databagItem = getAdminConnection().createDatabagItem(PREFIX, new DatabagItem("config", json.toJson(config)));
assertNotNull(databagItem);
assertEquals(databagItem.getId(), "config");
assertEquals(config, json.fromJson(databagItem.toString(), Properties.class));
}
@Test(dependsOnMethods = "testCreateDatabagItem")
public void testDatabagItemExists() throws Exception {
assertNotNull(getClientConnection().databagItemExists(PREFIX, PREFIX));
}
@Test(dependsOnMethods = "testDatabagItemExists")
public void testUpdateDatabagItem() throws Exception {
for (String databagItemId : getClientConnection().listDatabagItems(PREFIX)) {
DatabagItem databagItem = getAdminConnection().getDatabagItem(PREFIX, databagItemId);
getAdminConnection().updateDatabagItem(PREFIX, databagItem);
}
}
@Test
public void testListSearchIndexes() throws Exception {
Set<String> indexes = getAdminConnection().listSearchIndexes();
assertNotNull(indexes);
assert indexes.contains("node") : indexes;
assert indexes.contains("client") : indexes;
assert indexes.contains("role") : indexes;
}
@Test
public void testSearchNodes() throws Exception {
SearchResult<? extends Node> results = getAdminConnection().searchNodes();
assertNotNull(results);
}
@Test
public void testSearchClients() throws Exception {
SearchResult<? extends Client> results = getAdminConnection().searchClients();
assertNotNull(results);
}
@Test
public void testSearchRoles() throws Exception {
SearchResult<? extends Role> results = getAdminConnection().searchRoles();
assertNotNull(results);
}
@Test(dependsOnMethods = "testDatabagItemExists")
public void testSearchDatabag() throws Exception {
SearchResult<? extends DatabagItem> results = getAdminConnection().searchDatabag(PREFIX);
assertNotNull(results);
}
@Test(expectedExceptions = ResourceNotFoundException.class)
public void testSearchDatabagNotFound() throws Exception {
SearchResult<? extends DatabagItem> results = getAdminConnection().searchDatabag("whoopie");
assertNotNull(results);
}
@AfterClass(groups = { "live" })
public void teardownClient() throws IOException {
if (getValidatorConnection().clientExists(PREFIX))
getValidatorConnection().deleteClient(PREFIX);
if (getAdminConnection().nodeExists(PREFIX))
getAdminConnection().deleteNode(PREFIX);
if (getAdminConnection().roleExists(PREFIX))
getAdminConnection().deleteRole(PREFIX);
if (getAdminConnection().databagExists(PREFIX))
getAdminConnection().deleteDatabag(PREFIX);
closeContexts();
}
}

View File

@ -1,745 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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 org.testng.Assert.assertEquals;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.Properties;
import java.util.Set;
import org.jclouds.chef.config.ChefRestClientModule;
import org.jclouds.chef.domain.CookbookVersion;
import org.jclouds.chef.domain.DatabagItem;
import org.jclouds.chef.domain.Node;
import org.jclouds.chef.domain.Role;
import org.jclouds.chef.filters.SignedHeaderAuth;
import org.jclouds.chef.filters.SignedHeaderAuthTest;
import org.jclouds.chef.functions.ParseKeySetFromJson;
import org.jclouds.chef.functions.ParseSearchClientsFromJson;
import org.jclouds.chef.functions.ParseSearchDatabagFromJson;
import org.jclouds.chef.functions.ParseSearchNodesFromJson;
import org.jclouds.chef.functions.ParseSearchRolesFromJson;
import org.jclouds.crypto.CryptoStreams;
import org.jclouds.date.TimeStamp;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.RequiresHttp;
import org.jclouds.http.functions.ParseJson;
import org.jclouds.http.functions.ReleasePayloadAndReturn;
import org.jclouds.http.functions.ReturnTrueIf2xx;
import org.jclouds.rest.ConfiguresRestClient;
import org.jclouds.rest.RestClientTest;
import org.jclouds.rest.RestContextFactory;
import org.jclouds.rest.RestContextFactory.ContextSpec;
import org.jclouds.rest.functions.MapHttp4xxCodesToExceptions;
import org.jclouds.rest.functions.ReturnEmptySetOnNotFoundOr404;
import org.jclouds.rest.functions.ReturnFalseOnNotFoundOr404;
import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
import org.jclouds.rest.functions.ReturnVoidOnNotFoundOr404;
import org.jclouds.rest.internal.GeneratedHttpRequest;
import org.jclouds.rest.internal.RestAnnotationProcessor;
import org.testng.annotations.Test;
import com.google.common.base.Supplier;
import com.google.common.collect.ImmutableSet;
import com.google.common.primitives.Bytes;
import com.google.inject.Module;
import com.google.inject.TypeLiteral;
/**
* Tests annotation parsing of {@code ChefAsyncClient}
*
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "chef.ChefAsyncClientTest")
public class ChefAsyncClientTest extends RestClientTest<ChefAsyncClient> {
public void testCommitSandbox() throws SecurityException, NoSuchMethodException, IOException {
Method method = ChefAsyncClient.class.getMethod("commitSandbox", String.class, boolean.class);
GeneratedHttpRequest<ChefAsyncClient> httpRequest = processor.createRequest(method,
"0189e76ccc476701d6b374e5a1a27347", true);
assertRequestLineEquals(httpRequest,
"PUT http://localhost:4000/sandboxes/0189e76ccc476701d6b374e5a1a27347 HTTP/1.1");
assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\nX-Chef-Version: 0.9.8\n");
assertPayloadEquals(httpRequest, "{\"is_completed\":\"true\"}", "application/json", false);
assertResponseParserClassEquals(method, httpRequest, ParseJson.class);
assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, null);
checkFilters(httpRequest);
}
public void testGetUploadSandboxForChecksums() throws SecurityException, NoSuchMethodException, IOException {
Method method = ChefAsyncClient.class.getMethod("getUploadSandboxForChecksums", Set.class);
GeneratedHttpRequest<ChefAsyncClient> httpRequest = processor.createRequest(method, ImmutableSet.of(Bytes
.asList(CryptoStreams.hex("0189e76ccc476701d6b374e5a1a27347")), Bytes.asList(CryptoStreams
.hex("0c5ecd7788cf4f6c7de2a57193897a6c")), Bytes.asList(CryptoStreams
.hex("1dda05ed139664f1f89b9dec482b77c0"))));
assertRequestLineEquals(httpRequest, "POST http://localhost:4000/sandboxes HTTP/1.1");
assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\nX-Chef-Version: 0.9.8\n");
assertPayloadEquals(
httpRequest,
"{\"checksums\":{\"0189e76ccc476701d6b374e5a1a27347\":null,\"0c5ecd7788cf4f6c7de2a57193897a6c\":null,\"1dda05ed139664f1f89b9dec482b77c0\":null}}",
"application/json", false);
assertResponseParserClassEquals(method, httpRequest, ParseJson.class);
assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, null);
checkFilters(httpRequest);
}
public void testGetCookbook() throws SecurityException, NoSuchMethodException, IOException {
Method method = ChefAsyncClient.class.getMethod("getCookbook", String.class, String.class);
GeneratedHttpRequest<ChefAsyncClient> httpRequest = processor.createRequest(method, "cookbook", "1.0.0");
assertRequestLineEquals(httpRequest, "GET http://localhost:4000/cookbooks/cookbook/1.0.0 HTTP/1.1");
assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\nX-Chef-Version: 0.9.8\n");
assertPayloadEquals(httpRequest, null, null, false);
assertResponseParserClassEquals(method, httpRequest, ParseJson.class);
assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, ReturnNullOnNotFoundOr404.class);
checkFilters(httpRequest);
}
public void testDeleteCookbook() throws SecurityException, NoSuchMethodException, IOException {
Method method = ChefAsyncClient.class.getMethod("deleteCookbook", String.class, String.class);
GeneratedHttpRequest<ChefAsyncClient> httpRequest = processor.createRequest(method, "cookbook", "1.0.0");
assertRequestLineEquals(httpRequest, "DELETE http://localhost:4000/cookbooks/cookbook/1.0.0 HTTP/1.1");
assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\nX-Chef-Version: 0.9.8\n");
assertPayloadEquals(httpRequest, null, null, false);
assertResponseParserClassEquals(method, httpRequest, ParseJson.class);
assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, ReturnNullOnNotFoundOr404.class);
checkFilters(httpRequest);
}
public void testUpdateCookbook() throws SecurityException, NoSuchMethodException, IOException {
Method method = ChefAsyncClient.class.getMethod("updateCookbook", String.class, String.class,
CookbookVersion.class);
GeneratedHttpRequest<ChefAsyncClient> httpRequest = processor.createRequest(method, "cookbook", "1.0.1",
new CookbookVersion("cookbook", "1.0.1"));
assertRequestLineEquals(httpRequest, "PUT http://localhost:4000/cookbooks/cookbook/1.0.1 HTTP/1.1");
assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\nX-Chef-Version: 0.9.8\n");
assertPayloadEquals(
httpRequest,
"{\"name\":\"cookbook-1.0.1\",\"definitions\":[],\"attributes\":[],\"files\":[],\"metadata\":{\"suggestions\":{},\"dependencies\":{},\"conflicting\":{},\"providing\":{},\"platforms\":{},\"recipes\":{},\"replacing\":{},\"groupings\":{},\"attributes\":{},\"recommendations\":{}},\"providers\":[],\"cookbook_name\":\"cookbook\",\"resources\":[],\"templates\":[],\"libraries\":[],\"version\":\"1.0.1\",\"recipes\":[],\"root_files\":[],\"json_class\":\"Chef::CookbookVersion\",\"chef_type\":\"cookbook_version\"}",
"application/json", false);
assertResponseParserClassEquals(method, httpRequest, ParseJson.class);
assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, null);
checkFilters(httpRequest);
}
public void testListCookbooks() throws SecurityException, NoSuchMethodException, IOException {
Method method = ChefAsyncClient.class.getMethod("listCookbooks");
GeneratedHttpRequest<ChefAsyncClient> httpRequest = processor.createRequest(method);
assertRequestLineEquals(httpRequest, "GET http://localhost:4000/cookbooks HTTP/1.1");
assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\nX-Chef-Version: 0.9.8\n");
assertPayloadEquals(httpRequest, null, null, false);
assertResponseParserClassEquals(method, httpRequest, ParseKeySetFromJson.class);
assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, ReturnEmptySetOnNotFoundOr404.class);
checkFilters(httpRequest);
}
public void testClientExists() throws SecurityException, NoSuchMethodException, IOException {
Method method = ChefAsyncClient.class.getMethod("clientExists", String.class);
GeneratedHttpRequest<ChefAsyncClient> httpRequest = processor.createRequest(method, "client");
assertRequestLineEquals(httpRequest, "HEAD http://localhost:4000/clients/client HTTP/1.1");
assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\nX-Chef-Version: 0.9.8\n");
assertPayloadEquals(httpRequest, null, null, false);
assertResponseParserClassEquals(method, httpRequest, ReturnTrueIf2xx.class);
assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, ReturnFalseOnNotFoundOr404.class);
checkFilters(httpRequest);
}
public void testDeleteClient() throws SecurityException, NoSuchMethodException, IOException {
Method method = ChefAsyncClient.class.getMethod("deleteClient", String.class);
GeneratedHttpRequest<ChefAsyncClient> httpRequest = processor.createRequest(method, "client");
assertRequestLineEquals(httpRequest, "DELETE http://localhost:4000/clients/client HTTP/1.1");
assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\nX-Chef-Version: 0.9.8\n");
assertPayloadEquals(httpRequest, null, null, false);
assertResponseParserClassEquals(method, httpRequest, ParseJson.class);
assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, ReturnNullOnNotFoundOr404.class);
checkFilters(httpRequest);
}
public void testCreateClient() throws SecurityException, NoSuchMethodException, IOException {
Method method = ChefAsyncClient.class.getMethod("createClient", String.class);
GeneratedHttpRequest<ChefAsyncClient> httpRequest = processor.createRequest(method, "client");
assertRequestLineEquals(httpRequest, "POST http://localhost:4000/clients HTTP/1.1");
assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\nX-Chef-Version: 0.9.8\n");
assertPayloadEquals(httpRequest, "{\"clientname\":\"client\"}", "application/json", false);
assertResponseParserClassEquals(method, httpRequest, ParseJson.class);
assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, null);
checkFilters(httpRequest);
}
public void testListClients() throws SecurityException, NoSuchMethodException, IOException {
Method method = ChefAsyncClient.class.getMethod("listClients");
GeneratedHttpRequest<ChefAsyncClient> httpRequest = processor.createRequest(method);
assertRequestLineEquals(httpRequest, "GET http://localhost:4000/clients HTTP/1.1");
assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\nX-Chef-Version: 0.9.8\n");
assertPayloadEquals(httpRequest, null, null, false);
assertResponseParserClassEquals(method, httpRequest, ParseKeySetFromJson.class);
assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, ReturnEmptySetOnNotFoundOr404.class);
checkFilters(httpRequest);
}
public void testGenerateKeyForClient() throws SecurityException, NoSuchMethodException, IOException {
Method method = ChefAsyncClient.class.getMethod("generateKeyForClient", String.class);
GeneratedHttpRequest<ChefAsyncClient> httpRequest = processor.createRequest(method, "client");
assertRequestLineEquals(httpRequest, "PUT http://localhost:4000/clients/client HTTP/1.1");
assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\nX-Chef-Version: 0.9.8\n");
assertPayloadEquals(httpRequest, "{\"clientname\":\"client\", \"private_key\": true}", "application/json", false);
assertResponseParserClassEquals(method, httpRequest, ParseJson.class);
assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, null);
checkFilters(httpRequest);
}
public void testNodeExists() throws SecurityException, NoSuchMethodException, IOException {
Method method = ChefAsyncClient.class.getMethod("nodeExists", String.class);
GeneratedHttpRequest<ChefAsyncClient> httpRequest = processor.createRequest(method, "node");
assertRequestLineEquals(httpRequest, "HEAD http://localhost:4000/nodes/node HTTP/1.1");
assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\nX-Chef-Version: 0.9.8\n");
assertPayloadEquals(httpRequest, null, null, false);
assertResponseParserClassEquals(method, httpRequest, ReturnTrueIf2xx.class);
assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, ReturnFalseOnNotFoundOr404.class);
checkFilters(httpRequest);
}
public void testDeleteNode() throws SecurityException, NoSuchMethodException, IOException {
Method method = ChefAsyncClient.class.getMethod("deleteNode", String.class);
GeneratedHttpRequest<ChefAsyncClient> httpRequest = processor.createRequest(method, "node");
assertRequestLineEquals(httpRequest, "DELETE http://localhost:4000/nodes/node HTTP/1.1");
assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\nX-Chef-Version: 0.9.8\n");
assertPayloadEquals(httpRequest, null, null, false);
assertResponseParserClassEquals(method, httpRequest, ParseJson.class);
assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, ReturnNullOnNotFoundOr404.class);
checkFilters(httpRequest);
}
public void testCreateNode() throws SecurityException, NoSuchMethodException, IOException {
Method method = ChefAsyncClient.class.getMethod("createNode", Node.class);
GeneratedHttpRequest<ChefAsyncClient> httpRequest = processor.createRequest(method, new Node("testnode",
ImmutableSet.of("recipe[java]")));
assertRequestLineEquals(httpRequest, "POST http://localhost:4000/nodes HTTP/1.1");
assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\nX-Chef-Version: 0.9.8\n");
assertPayloadEquals(
httpRequest,
"{\"name\":\"testnode\",\"normal\":{},\"override\":{},\"default\":{},\"automatic\":{},\"run_list\":[\"recipe[java]\"],\"json_class\":\"Chef::Node\",\"chef_type\":\"node\"}",
"application/json", false);
assertResponseParserClassEquals(method, httpRequest, ReleasePayloadAndReturn.class);
assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, null);
checkFilters(httpRequest);
}
public void testUpdateNode() throws SecurityException, NoSuchMethodException, IOException {
Method method = ChefAsyncClient.class.getMethod("updateNode", Node.class);
GeneratedHttpRequest<ChefAsyncClient> httpRequest = processor.createRequest(method, new Node("testnode",
ImmutableSet.of("recipe[java]")));
assertRequestLineEquals(httpRequest, "PUT http://localhost:4000/nodes/testnode HTTP/1.1");
assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\nX-Chef-Version: 0.9.8\n");
assertPayloadEquals(
httpRequest,
"{\"name\":\"testnode\",\"normal\":{},\"override\":{},\"default\":{},\"automatic\":{},\"run_list\":[\"recipe[java]\"],\"json_class\":\"Chef::Node\",\"chef_type\":\"node\"}",
"application/json", false);
assertResponseParserClassEquals(method, httpRequest, ParseJson.class);
assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, null);
checkFilters(httpRequest);
}
public void testListNodes() throws SecurityException, NoSuchMethodException, IOException {
Method method = ChefAsyncClient.class.getMethod("listNodes");
GeneratedHttpRequest<ChefAsyncClient> httpRequest = processor.createRequest(method);
assertRequestLineEquals(httpRequest, "GET http://localhost:4000/nodes HTTP/1.1");
assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\nX-Chef-Version: 0.9.8\n");
assertPayloadEquals(httpRequest, null, null, false);
assertResponseParserClassEquals(method, httpRequest, ParseKeySetFromJson.class);
assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, ReturnEmptySetOnNotFoundOr404.class);
checkFilters(httpRequest);
}
public void testRoleExists() throws SecurityException, NoSuchMethodException, IOException {
Method method = ChefAsyncClient.class.getMethod("roleExists", String.class);
GeneratedHttpRequest<ChefAsyncClient> httpRequest = processor.createRequest(method, "role");
assertRequestLineEquals(httpRequest, "HEAD http://localhost:4000/roles/role HTTP/1.1");
assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\nX-Chef-Version: 0.9.8\n");
assertPayloadEquals(httpRequest, null, null, false);
assertResponseParserClassEquals(method, httpRequest, ReturnTrueIf2xx.class);
assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, ReturnFalseOnNotFoundOr404.class);
checkFilters(httpRequest);
}
public void testDeleteRole() throws SecurityException, NoSuchMethodException, IOException {
Method method = ChefAsyncClient.class.getMethod("deleteRole", String.class);
GeneratedHttpRequest<ChefAsyncClient> httpRequest = processor.createRequest(method, "role");
assertRequestLineEquals(httpRequest, "DELETE http://localhost:4000/roles/role HTTP/1.1");
assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\nX-Chef-Version: 0.9.8\n");
assertPayloadEquals(httpRequest, null, null, false);
assertResponseParserClassEquals(method, httpRequest, ParseJson.class);
assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, ReturnNullOnNotFoundOr404.class);
checkFilters(httpRequest);
}
public void testCreateRole() throws SecurityException, NoSuchMethodException, IOException {
Method method = ChefAsyncClient.class.getMethod("createRole", Role.class);
GeneratedHttpRequest<ChefAsyncClient> httpRequest = processor.createRequest(method, new Role("testrole",
ImmutableSet.of("recipe[java]")));
assertRequestLineEquals(httpRequest, "POST http://localhost:4000/roles HTTP/1.1");
assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\nX-Chef-Version: 0.9.8\n");
assertPayloadEquals(
httpRequest,
"{\"name\":\"testrole\",\"override_attributes\":{},\"default_attributes\":{},\"run_list\":[\"recipe[java]\"],\"json_class\":\"Chef::Role\",\"chef_type\":\"role\"}",
"application/json", false);
assertResponseParserClassEquals(method, httpRequest, ReleasePayloadAndReturn.class);
assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, null);
checkFilters(httpRequest);
}
public void testUpdateRole() throws SecurityException, NoSuchMethodException, IOException {
Method method = ChefAsyncClient.class.getMethod("updateRole", Role.class);
GeneratedHttpRequest<ChefAsyncClient> httpRequest = processor.createRequest(method, new Role("testrole",
ImmutableSet.of("recipe[java]")));
assertRequestLineEquals(httpRequest, "PUT http://localhost:4000/roles/testrole HTTP/1.1");
assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\nX-Chef-Version: 0.9.8\n");
assertPayloadEquals(
httpRequest,
"{\"name\":\"testrole\",\"override_attributes\":{},\"default_attributes\":{},\"run_list\":[\"recipe[java]\"],\"json_class\":\"Chef::Role\",\"chef_type\":\"role\"}",
"application/json", false);
assertResponseParserClassEquals(method, httpRequest, ParseJson.class);
assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, null);
checkFilters(httpRequest);
}
public void testListRoles() throws SecurityException, NoSuchMethodException, IOException {
Method method = ChefAsyncClient.class.getMethod("listRoles");
GeneratedHttpRequest<ChefAsyncClient> httpRequest = processor.createRequest(method);
assertRequestLineEquals(httpRequest, "GET http://localhost:4000/roles HTTP/1.1");
assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\nX-Chef-Version: 0.9.8\n");
assertPayloadEquals(httpRequest, null, null, false);
assertResponseParserClassEquals(method, httpRequest, ParseKeySetFromJson.class);
assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, ReturnEmptySetOnNotFoundOr404.class);
checkFilters(httpRequest);
}
public void testDatabagExists() throws SecurityException, NoSuchMethodException, IOException {
Method method = ChefAsyncClient.class.getMethod("databagExists", String.class);
GeneratedHttpRequest<ChefAsyncClient> httpRequest = processor.createRequest(method, "databag");
assertRequestLineEquals(httpRequest, "HEAD http://localhost:4000/data/databag HTTP/1.1");
assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\nX-Chef-Version: 0.9.8\n");
assertPayloadEquals(httpRequest, null, null, false);
assertResponseParserClassEquals(method, httpRequest, ReturnTrueIf2xx.class);
assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, ReturnFalseOnNotFoundOr404.class);
checkFilters(httpRequest);
}
public void testDeleteDatabag() throws SecurityException, NoSuchMethodException, IOException {
Method method = ChefAsyncClient.class.getMethod("deleteDatabag", String.class);
GeneratedHttpRequest<ChefAsyncClient> httpRequest = processor.createRequest(method, "databag");
assertRequestLineEquals(httpRequest, "DELETE http://localhost:4000/data/databag HTTP/1.1");
assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\nX-Chef-Version: 0.9.8\n");
assertPayloadEquals(httpRequest, null, null, false);
assertResponseParserClassEquals(method, httpRequest, ReleasePayloadAndReturn.class);
assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, ReturnVoidOnNotFoundOr404.class);
checkFilters(httpRequest);
}
public void testCreateDatabag() throws SecurityException, NoSuchMethodException, IOException {
Method method = ChefAsyncClient.class.getMethod("createDatabag", String.class);
GeneratedHttpRequest<ChefAsyncClient> httpRequest = processor.createRequest(method, "name");
assertRequestLineEquals(httpRequest, "POST http://localhost:4000/data HTTP/1.1");
assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\nX-Chef-Version: 0.9.8\n");
assertPayloadEquals(httpRequest, "{\"name\":\"name\"}", "application/json", false);
assertResponseParserClassEquals(method, httpRequest, ReleasePayloadAndReturn.class);
assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, null);
checkFilters(httpRequest);
}
public void testListDatabags() throws SecurityException, NoSuchMethodException, IOException {
Method method = ChefAsyncClient.class.getMethod("listDatabags");
GeneratedHttpRequest<ChefAsyncClient> httpRequest = processor.createRequest(method);
assertRequestLineEquals(httpRequest, "GET http://localhost:4000/data HTTP/1.1");
assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\nX-Chef-Version: 0.9.8\n");
assertPayloadEquals(httpRequest, null, null, false);
assertResponseParserClassEquals(method, httpRequest, ParseKeySetFromJson.class);
assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, ReturnEmptySetOnNotFoundOr404.class);
checkFilters(httpRequest);
}
public void testDatabagItemExists() throws SecurityException, NoSuchMethodException, IOException {
Method method = ChefAsyncClient.class.getMethod("databagItemExists", String.class, String.class);
GeneratedHttpRequest<ChefAsyncClient> httpRequest = processor.createRequest(method, "name", "databagItem");
assertRequestLineEquals(httpRequest, "HEAD http://localhost:4000/data/name/databagItem HTTP/1.1");
assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\nX-Chef-Version: 0.9.8\n");
assertPayloadEquals(httpRequest, null, null, false);
assertResponseParserClassEquals(method, httpRequest, ReturnTrueIf2xx.class);
assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, ReturnFalseOnNotFoundOr404.class);
checkFilters(httpRequest);
}
public void testDeleteDatabagItem() throws SecurityException, NoSuchMethodException, IOException {
Method method = ChefAsyncClient.class.getMethod("deleteDatabagItem", String.class, String.class);
GeneratedHttpRequest<ChefAsyncClient> httpRequest = processor.createRequest(method, "name", "databagItem");
assertRequestLineEquals(httpRequest, "DELETE http://localhost:4000/data/name/databagItem HTTP/1.1");
assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\nX-Chef-Version: 0.9.8\n");
assertPayloadEquals(httpRequest, null, null, false);
assertResponseParserClassEquals(method, httpRequest, ParseJson.class);
assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, ReturnNullOnNotFoundOr404.class);
checkFilters(httpRequest);
}
@Test(expectedExceptions = IllegalArgumentException.class)
public void testCreateDatabagItemThrowsIllegalArgumentOnPrimitive() throws SecurityException, NoSuchMethodException,
IOException {
Method method = ChefAsyncClient.class.getMethod("createDatabagItem", String.class, DatabagItem.class);
GeneratedHttpRequest<ChefAsyncClient> httpRequest = processor.createRequest(method, "name", new DatabagItem("id",
"100"));
assertRequestLineEquals(httpRequest, "POST http://localhost:4000/data/name HTTP/1.1");
assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\nX-Chef-Version: 0.9.8\n");
assertPayloadEquals(
httpRequest,
"{\"name\":\"testdatabagItem\",\"override_attributes\":{},\"default_attributes\":{},\"run_list\":[\"recipe[java]\"],\"json_class\":\"Chef::DatabagItem\",\"chef_type\":\"databagItem\"}",
"application/json", false);
assertResponseParserClassEquals(method, httpRequest, ParseJson.class);
assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, null);
checkFilters(httpRequest);
}
@Test(expectedExceptions = IllegalArgumentException.class)
public void testCreateDatabagItemThrowsIllegalArgumentOnWrongId() throws SecurityException, NoSuchMethodException,
IOException {
Method method = ChefAsyncClient.class.getMethod("createDatabagItem", String.class, DatabagItem.class);
GeneratedHttpRequest<ChefAsyncClient> httpRequest = processor.createRequest(method, "name", new DatabagItem("id",
"{\"id\": \"item1\",\"my_key\": \"my_data\"}"));
assertRequestLineEquals(httpRequest, "POST http://localhost:4000/data/name HTTP/1.1");
assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\nX-Chef-Version: 0.9.8\n");
assertPayloadEquals(
httpRequest,
"{\"name\":\"testdatabagItem\",\"override_attributes\":{},\"default_attributes\":{},\"run_list\":[\"recipe[java]\"],\"json_class\":\"Chef::DatabagItem\",\"chef_type\":\"databagItem\"}",
"application/json", false);
assertResponseParserClassEquals(method, httpRequest, ParseJson.class);
assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, null);
checkFilters(httpRequest);
}
public void testCreateDatabagItem() throws SecurityException, NoSuchMethodException, IOException {
Method method = ChefAsyncClient.class.getMethod("createDatabagItem", String.class, DatabagItem.class);
GeneratedHttpRequest<ChefAsyncClient> httpRequest = processor.createRequest(method, "name", new DatabagItem("id",
"{\"id\": \"id\",\"my_key\": \"my_data\"}"));
assertRequestLineEquals(httpRequest, "POST http://localhost:4000/data/name HTTP/1.1");
assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\nX-Chef-Version: 0.9.8\n");
assertPayloadEquals(httpRequest, "{\"id\": \"id\",\"my_key\": \"my_data\"}", "application/json", false);
assertResponseParserClassEquals(method, httpRequest, ParseJson.class);
assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, null);
checkFilters(httpRequest);
}
public void testCreateDatabagItemEvenWhenUserForgotId() throws SecurityException, NoSuchMethodException, IOException {
Method method = ChefAsyncClient.class.getMethod("createDatabagItem", String.class, DatabagItem.class);
GeneratedHttpRequest<ChefAsyncClient> httpRequest = processor.createRequest(method, "name", new DatabagItem("id",
"{\"my_key\": \"my_data\"}"));
assertRequestLineEquals(httpRequest, "POST http://localhost:4000/data/name HTTP/1.1");
assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\nX-Chef-Version: 0.9.8\n");
assertPayloadEquals(httpRequest, "{\"id\":\"id\",\"my_key\": \"my_data\"}", "application/json", false);
assertResponseParserClassEquals(method, httpRequest, ParseJson.class);
assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, null);
checkFilters(httpRequest);
}
public void testUpdateDatabagItem() throws SecurityException, NoSuchMethodException, IOException {
Method method = ChefAsyncClient.class.getMethod("updateDatabagItem", String.class, DatabagItem.class);
GeneratedHttpRequest<ChefAsyncClient> httpRequest = processor.createRequest(method, "name", new DatabagItem("id",
"{\"my_key\": \"my_data\"}"));
assertRequestLineEquals(httpRequest, "PUT http://localhost:4000/data/name/id HTTP/1.1");
assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\nX-Chef-Version: 0.9.8\n");
assertPayloadEquals(httpRequest, "{\"id\":\"id\",\"my_key\": \"my_data\"}", "application/json", false);
assertResponseParserClassEquals(method, httpRequest, ParseJson.class);
assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, null);
checkFilters(httpRequest);
}
public void testListDatabagItems() throws SecurityException, NoSuchMethodException, IOException {
Method method = ChefAsyncClient.class.getMethod("listDatabagItems", String.class);
GeneratedHttpRequest<ChefAsyncClient> httpRequest = processor.createRequest(method, "name");
assertRequestLineEquals(httpRequest, "GET http://localhost:4000/data/name HTTP/1.1");
assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\nX-Chef-Version: 0.9.8\n");
assertPayloadEquals(httpRequest, null, null, false);
assertResponseParserClassEquals(method, httpRequest, ParseKeySetFromJson.class);
assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, ReturnEmptySetOnNotFoundOr404.class);
checkFilters(httpRequest);
}
public void testListSearchIndexes() throws SecurityException, NoSuchMethodException, IOException {
Method method = ChefAsyncClient.class.getMethod("listSearchIndexes");
GeneratedHttpRequest<ChefAsyncClient> httpRequest = processor.createRequest(method);
assertRequestLineEquals(httpRequest, "GET http://localhost:4000/search HTTP/1.1");
assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\nX-Chef-Version: 0.9.8\n");
assertPayloadEquals(httpRequest, null, null, false);
assertResponseParserClassEquals(method, httpRequest, ParseKeySetFromJson.class);
assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, ReturnEmptySetOnNotFoundOr404.class);
checkFilters(httpRequest);
}
public void testSearchRoles() throws SecurityException, NoSuchMethodException, IOException {
Method method = ChefAsyncClient.class.getMethod("searchRoles");
GeneratedHttpRequest<ChefAsyncClient> httpRequest = processor.createRequest(method);
assertRequestLineEquals(httpRequest, "GET http://localhost:4000/search/role HTTP/1.1");
assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\nX-Chef-Version: 0.9.8\n");
assertPayloadEquals(httpRequest, null, null, false);
assertResponseParserClassEquals(method, httpRequest, ParseSearchRolesFromJson.class);
assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, MapHttp4xxCodesToExceptions.class);
checkFilters(httpRequest);
}
public void testSearchClients() throws SecurityException, NoSuchMethodException, IOException {
Method method = ChefAsyncClient.class.getMethod("searchClients");
GeneratedHttpRequest<ChefAsyncClient> httpRequest = processor.createRequest(method);
assertRequestLineEquals(httpRequest, "GET http://localhost:4000/search/client HTTP/1.1");
assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\nX-Chef-Version: 0.9.8\n");
assertPayloadEquals(httpRequest, null, null, false);
assertResponseParserClassEquals(method, httpRequest, ParseSearchClientsFromJson.class);
assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, MapHttp4xxCodesToExceptions.class);
checkFilters(httpRequest);
}
public void testSearchNodes() throws SecurityException, NoSuchMethodException, IOException {
Method method = ChefAsyncClient.class.getMethod("searchNodes");
GeneratedHttpRequest<ChefAsyncClient> httpRequest = processor.createRequest(method);
assertRequestLineEquals(httpRequest, "GET http://localhost:4000/search/node HTTP/1.1");
assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\nX-Chef-Version: 0.9.8\n");
assertPayloadEquals(httpRequest, null, null, false);
assertResponseParserClassEquals(method, httpRequest, ParseSearchNodesFromJson.class);
assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, MapHttp4xxCodesToExceptions.class);
checkFilters(httpRequest);
}
public void testSearchDatabag() throws SecurityException, NoSuchMethodException, IOException {
Method method = ChefAsyncClient.class.getMethod("searchDatabag", String.class);
GeneratedHttpRequest<ChefAsyncClient> httpRequest = processor.createRequest(method, "foo");
assertRequestLineEquals(httpRequest, "GET http://localhost:4000/search/foo HTTP/1.1");
assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\nX-Chef-Version: 0.9.8\n");
assertPayloadEquals(httpRequest, null, null, false);
assertResponseParserClassEquals(method, httpRequest, ParseSearchDatabagFromJson.class);
assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, MapHttp4xxCodesToExceptions.class);
checkFilters(httpRequest);
}
@Override
protected void checkFilters(HttpRequest request) {
assertEquals(request.getFilters().size(), 1);
assertEquals(request.getFilters().get(0).getClass(), SignedHeaderAuth.class);
}
@Override
protected TypeLiteral<RestAnnotationProcessor<ChefAsyncClient>> createTypeLiteral() {
return new TypeLiteral<RestAnnotationProcessor<ChefAsyncClient>>() {
};
}
@Override
protected Module createModule() {
return new TestChefRestClientModule();
}
@RequiresHttp
@ConfiguresRestClient
static class TestChefRestClientModule extends ChefRestClientModule {
@Override
protected String provideTimeStamp(@TimeStamp Supplier<String> cache) {
return "timestamp";
}
}
@Override
public ContextSpec<ChefClient, ChefAsyncClient> createContextSpec() {
return new RestContextFactory().createContextSpec("chef", "user", SignedHeaderAuthTest.PRIVATE_KEY,
new Properties());
}
}

View File

@ -1,126 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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 com.google.common.base.Preconditions.checkNotNull;
import static org.testng.Assert.assertNotNull;
import java.io.File;
import java.io.IOException;
import java.util.Properties;
import org.jclouds.chef.config.ChefParserModule;
import org.jclouds.chef.domain.CookbookVersion;
import org.jclouds.json.Json;
import org.jclouds.json.config.GsonModule;
import org.jclouds.logging.log4j.config.Log4JLoggingModule;
import org.jclouds.rest.HttpClient;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import com.google.common.base.Charsets;
import com.google.common.collect.ImmutableSet;
import com.google.common.io.Files;
import com.google.inject.Guice;
import com.google.inject.Module;
/**
* Tests behavior of {@code ChefClient}
*
* @author Adrian Cole
*/
@Test(groups = "live", testName = "chef.ChefClientLiveTest")
public class ChefClientLiveTest extends BaseChefClientLiveTest {
private ChefContext validatorConnection;
private ChefContext clientConnection;
private ChefContext adminConnection;
private String validator;
@Override
@BeforeClass(groups = { "live" })
public void setupClient() throws IOException {
endpoint = checkNotNull(System.getProperty("jclouds.test.endpoint"), "jclouds.test.endpoint");
validator = System.getProperty("jclouds.test.validator");
if (validator == null || validator.equals(""))
validator = "chef-validator";
String validatorKey = System.getProperty("jclouds.test.validator.key");
if (validatorKey == null || validatorKey.equals(""))
validatorKey = System.getProperty("user.home") + "/.chef/validation.pem";
user = checkNotNull(System.getProperty("jclouds.test.identity"), "jclouds.test.identity");
String keyfile = System.getProperty("jclouds.test.credential");
if (keyfile == null || keyfile.equals(""))
keyfile = System.getProperty("user.home") + "/.chef/" + user + ".pem";
validatorConnection = createConnection(validator, Files.toString(new File(validatorKey), Charsets.UTF_8));
adminConnection = createConnection(user, Files.toString(new File(keyfile), Charsets.UTF_8));
json = Guice.createInjector(new GsonModule(), new ChefParserModule()).getInstance(Json.class);
}
private ChefContext createConnection(String identity, String key) throws IOException {
Properties props = new Properties();
props.setProperty("chef.endpoint", endpoint);
return new ChefContextFactory().createContext(identity, key, ImmutableSet.<Module> of(new Log4JLoggingModule()),
props);
}
@Override
protected HttpClient getHttp() {
return adminConnection.utils().http();
}
@Override
protected ChefClient getAdminConnection() {
return adminConnection.getApi();
}
@Override
protected ChefClient getValidatorConnection() {
return validatorConnection.getApi();
}
@Override
protected ChefClient getClientConnection() {
return clientConnection.getApi();
}
@Override
protected void recreateClientConnection() throws IOException {
if (clientConnection != null)
clientConnection.close();
clientConnection = createConnection(PREFIX, clientKey);
}
@Test
public void testListCookbookVersionsWithChefService() throws Exception {
Iterable<? extends CookbookVersion> cookbooks = adminConnection.getChefService().listCookbookVersions();
assertNotNull(cookbooks);
}
@Override
protected void closeContexts() {
if (clientConnection != null)
clientConnection.close();
if (validatorConnection != null)
validatorConnection.close();
if (adminConnection != null)
adminConnection.close();
}
}

View File

@ -1,41 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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 org.jclouds.util.Utils;
import org.testng.annotations.Test;
import com.google.common.collect.Iterables;
/**
*
* @author Adrian Cole
*
*/
@Test(groups = "unit")
public class ProvidersInPropertiesTest {
@Test
public void testSupportedProviders() {
Iterable<String> providers = Utils.getSupportedProviders();
assert Iterables.contains(providers, "chef") : providers;
}
}

View File

@ -1,67 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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 org.testng.Assert.assertEquals;
import java.io.File;
import java.net.URI;
import javax.ws.rs.HttpMethod;
import org.jclouds.chef.config.ChefParserModule;
import org.jclouds.crypto.CryptoStreams;
import org.jclouds.http.HttpRequest;
import org.jclouds.json.config.GsonModule;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableSet;
import com.google.inject.Guice;
import com.google.inject.Injector;
/**
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "chef.BootstrapChefClientTest")
public class BindHexEncodedMD5sToJsonPayloadTest {
Injector injector = Guice.createInjector(new ChefParserModule(), new GsonModule());
BindChecksumsToJsonPayload binder = injector.getInstance(BindChecksumsToJsonPayload.class);
@Test(expectedExceptions = IllegalArgumentException.class)
public void testMustBeIterable() {
HttpRequest request = new HttpRequest(HttpMethod.POST, URI.create("http://localhost"));
binder.bindToRequest(request, new File("foo"));
}
@Test(enabled = false)
public void testCorrect() {
HttpRequest request = new HttpRequest(HttpMethod.POST, URI.create("http://localhost"));
binder.bindToRequest(request, ImmutableSet.of(CryptoStreams.hex("abddef"), CryptoStreams.hex("1234")));
assertEquals(request.getPayload().getRawContent(), "{\"checksums\":{\"abddef\":null,\"1234\":null}}");
}
@Test(expectedExceptions = { NullPointerException.class, IllegalStateException.class })
public void testNullIsBad() {
HttpRequest request = new HttpRequest(HttpMethod.POST, URI.create("http://localhost"));
binder.bindToRequest(request, null);
}
}

View File

@ -1,201 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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 org.testng.Assert.assertEquals;
import java.io.IOException;
import java.net.URI;
import java.security.PrivateKey;
import java.util.Properties;
import javax.inject.Provider;
import javax.ws.rs.HttpMethod;
import javax.ws.rs.core.HttpHeaders;
import org.jclouds.crypto.Crypto;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpUtils;
import org.jclouds.http.internal.SignatureWire;
import org.jclouds.logging.config.NullLoggingModule;
import org.jclouds.rest.RestContextFactory;
import org.jclouds.rest.BaseRestClientTest.MockModule;
import org.jclouds.util.Utils;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import com.google.common.base.Joiner;
import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.LinkedHashMultimap;
import com.google.common.collect.Multimap;
import com.google.inject.Injector;
import com.google.inject.Module;
/**
*
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "chef.SignedHeaderAuthTest")
public class SignedHeaderAuthTest {
public static final String USER_ID = "spec-user";
public static final String BODY = "Spec Body";
// Base64.encode64(Digest::SHA1.digest("Spec Body")).chomp
public static final String HASHED_BODY = "DFteJZPVv6WKdQmMqZUQUumUyRs=";
public static final String TIMESTAMP_ISO8601 = "2009-01-01T12:00:00Z";
public static final String PATH = "/organizations/clownco";
// Base64.encode64(Digest::SHA1.digest("/organizations/clownco")).chomp
public static final String HASHED_CANONICAL_PATH = "YtBWDn1blGGuFIuKksdwXzHU9oE=";
public static final String REQUESTING_ACTOR_ID = "c0f8a68c52bffa1020222a56b23cccfa";
// Content hash is ???TODO
public static final String X_OPS_CONTENT_HASH = "DFteJZPVv6WKdQmMqZUQUumUyRs=";
public static final String[] X_OPS_AUTHORIZATION_LINES = new String[] {
"jVHrNniWzpbez/eGWjFnO6lINRIuKOg40ZTIQudcFe47Z9e/HvrszfVXlKG4",
"NMzYZgyooSvU85qkIUmKuCqgG2AIlvYa2Q/2ctrMhoaHhLOCWWoqYNMaEqPc",
"3tKHE+CfvP+WuPdWk4jv4wpIkAz6ZLxToxcGhXmZbXpk56YTmqgBW2cbbw4O",
"IWPZDHSiPcw//AYNgW1CCDptt+UFuaFYbtqZegcBd2n/jzcWODA7zL4KWEUy",
"9q4rlh/+1tBReg60QdsmDRsw/cdO1GZrKtuCwbuD4+nbRdVBKv72rqHX9cu0", "utju9jzczCyB+sSAQWrxSsXB/b8vV2qs0l4VD2ML+w==" };
// We expect Mixlib::Authentication::SignedHeaderAuth//sign to return this
// if passed the BODY above.
public static final Multimap<String, String> EXPECTED_SIGN_RESULT = ImmutableMultimap.<String, String> builder()
.put("X-Ops-Content-Hash", X_OPS_CONTENT_HASH).put("X-Ops-Userid", USER_ID).put("X-Ops-Sign", "version=1.0")
.put("X-Ops-Authorization-1", X_OPS_AUTHORIZATION_LINES[0]).put("X-Ops-Authorization-2",
X_OPS_AUTHORIZATION_LINES[1]).put("X-Ops-Authorization-3", X_OPS_AUTHORIZATION_LINES[2]).put(
"X-Ops-Authorization-4", X_OPS_AUTHORIZATION_LINES[3]).put("X-Ops-Authorization-5",
X_OPS_AUTHORIZATION_LINES[4]).put("X-Ops-Authorization-6", X_OPS_AUTHORIZATION_LINES[5]).put(
"X-Ops-Timestamp", TIMESTAMP_ISO8601).build();
// Content hash for empty string
public static final String X_OPS_CONTENT_HASH_EMPTY = "2jmj7l5rSw0yVb/vlWAYkK/YBwk=";
public static final Multimap<String, String> EXPECTED_SIGN_RESULT_EMPTY = ImmutableMultimap
.<String, String> builder().put("X-Ops-Content-Hash", X_OPS_CONTENT_HASH_EMPTY).put("X-Ops-Userid", USER_ID)
.put("X-Ops-Sign", "version=1.0").put("X-Ops-Authorization-1",
"N6U75kopDK64cEFqrB6vw+PnubnXr0w5LQeXnIGNGLRP2LvifwIeisk7QxEx").put("X-Ops-Authorization-2",
"mtpQOWAw8HvnWErjzuk9AvUsqVmWpv14ficvkaD79qsPMvbje+aLcIrCGT1P").put("X-Ops-Authorization-3",
"3d2uvf4w7iqwzrIscPnkxLR6o6pymR90gvJXDPzV7Le0jbfD8kmZ8AAK0sGG").put("X-Ops-Authorization-4",
"09F1ftW80bLatJTA66Cw2wBz261r6x/abZhIKFJFDWLzyQGJ8ZNOkUrDDtgI").put("X-Ops-Authorization-5",
"svLVXpOJKZZfKunsElpWjjsyNt3k8vpI1Y4ANO8Eg2bmeCPeEK+YriGm5fbC").put("X-Ops-Authorization-6",
"DzWNPylHJqMeGKVYwGQKpg62QDfe5yXh3wZLiQcXow==").put("X-Ops-Timestamp", TIMESTAMP_ISO8601).build();
public static String PUBLIC_KEY;
public static String PRIVATE_KEY;
static {
try {
PUBLIC_KEY = Utils.toStringAndClose(SignedHeaderAuthTest.class.getResourceAsStream("/pubkey.txt"));
PRIVATE_KEY = Utils.toStringAndClose(SignedHeaderAuthTest.class.getResourceAsStream("/privkey.txt"));
} catch (IOException e) {
Throwables.propagate(e);
}
}
@Test
void canonicalizedPathRemovesMultipleSlashes() {
assertEquals(signing_obj.canonicalPath("///"), "/");
}
@Test
void canonicalizedPathRemovesTrailingSlash() {
assertEquals(signing_obj.canonicalPath("/path/"), "/path");
}
@Test
void shouldGenerateTheCorrectStringToSignAndSignature() {
URI host = URI.create("http://localhost/" + PATH);
HttpRequest request = new HttpRequest(HttpMethod.POST, host);
request.setPayload(BODY);
String expected_string_to_sign = new StringBuilder().append("Method:POST").append("\n").append("Hashed Path:")
.append(HASHED_CANONICAL_PATH).append("\n").append("X-Ops-Content-Hash:").append(HASHED_BODY).append("\n")
.append("X-Ops-Timestamp:").append(TIMESTAMP_ISO8601).append("\n").append("X-Ops-UserId:").append(USER_ID)
.toString();
assertEquals(signing_obj.createStringToSign("POST", HASHED_CANONICAL_PATH, HASHED_BODY, TIMESTAMP_ISO8601),
expected_string_to_sign);
assertEquals(signing_obj.sign(expected_string_to_sign), Joiner.on("").join(X_OPS_AUTHORIZATION_LINES));
signing_obj.filter(request);
Multimap<String, String> headersWithoutContentLength = LinkedHashMultimap.create(request.getHeaders());
headersWithoutContentLength.removeAll(HttpHeaders.CONTENT_LENGTH);
assertEquals(headersWithoutContentLength.values(), EXPECTED_SIGN_RESULT.values());
}
@Test
void shouldGenerateTheCorrectStringToSignAndSignatureWithNoBody() {
URI host = URI.create("http://localhost/" + PATH);
HttpRequest request = new HttpRequest(HttpMethod.DELETE, host);
signing_obj.filter(request);
Multimap<String, String> headersWithoutContentLength = LinkedHashMultimap.create(request.getHeaders());
assertEquals(headersWithoutContentLength.entries(), EXPECTED_SIGN_RESULT_EMPTY.entries());
}
@Test
void shouldNotChokeWhenSigningARequestForAResourceWithALongName() {
StringBuilder path = new StringBuilder("nodes/");
for (int i = 0; i < 100; i++)
path.append('A');
URI host = URI.create("http://localhost/" + path.toString());
HttpRequest request = new HttpRequest(HttpMethod.PUT, host);
request.setPayload(BODY);
signing_obj.filter(request);
}
private SignedHeaderAuth signing_obj;
private Crypto crypto;
/**
* before class, as we need to ensure that the filter is threadsafe.
*
* @throws IOException
*
*/
@BeforeClass
protected void createFilter() throws IOException {
Injector injector = new RestContextFactory().createContextBuilder("chef", USER_ID, PRIVATE_KEY,
ImmutableSet.<Module> of(new MockModule(), new NullLoggingModule()), new Properties()).buildInjector();
crypto = injector.getInstance(Crypto.class);
HttpUtils utils = injector.getInstance(HttpUtils.class);
PrivateKey privateKey = injector.getInstance(PrivateKey.class);
signing_obj = new SignedHeaderAuth(new SignatureWire(), USER_ID, privateKey, new Provider<String>() {
@Override
public String get() {
return TIMESTAMP_ISO8601;
}
}, crypto, utils);
}
}

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