Issue 191: added in-memory chef-client; use provider: transientchef

This commit is contained in:
Adrian Cole 2010-08-12 18:53:51 -07:00
parent 420503d32e
commit 4b76982261
12 changed files with 1051 additions and 50 deletions

View File

@ -45,6 +45,7 @@ import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import java.net.URI;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
@ -274,6 +275,13 @@ public class TransientAsyncBlobStore extends BaseAsyncBlobStore {
return immediateFuture(null);
}
public ListenableFuture<Blob> removeBlobAndReturnOld(String container, String key) {
if (getContainerToBlobs().containsKey(container)) {
return immediateFuture(getContainerToBlobs().get(container).remove(key));
}
return immediateFuture(null);
}
/**
* {@inheritDoc}
*/
@ -346,6 +354,20 @@ public class TransientAsyncBlobStore extends BaseAsyncBlobStore {
return immediateFuture(getContainerToBlobs().containsKey(name));
}
/**
* throws IllegalStateException if the container already exists
*/
public ListenableFuture<Void> createContainerInLocationIfAbsent(final Location location, final String name) {
ConcurrentMap<String, Blob> container = getContainerToBlobs().putIfAbsent(name,
new ConcurrentHashMap<String, Blob>());
if (container == null) {
getContainerToLocation().put(name, location != null ? location : defaultLocation);
return immediateFuture((Void) null);
} else {
return Futures.immediateFailedFuture(new IllegalStateException("container " + name + " already exists"));
}
}
public String getFirstQueryOrNull(String string, @Nullable HttpRequestOptions options) {
if (options == null)
return null;
@ -454,33 +476,54 @@ public class TransientAsyncBlobStore extends BaseAsyncBlobStore {
* {@inheritDoc}
*/
@Override
public ListenableFuture<String> putBlob(String containerName, Blob object) {
Map<String, Blob> container = getContainerToBlobs().get(containerName);
public ListenableFuture<String> putBlob(String containerName, Blob in) {
ConcurrentMap<String, Blob> container = getContainerToBlobs().get(containerName);
if (container == null) {
new RuntimeException("containerName not found: " + containerName);
new IllegalStateException("containerName not found: " + containerName);
}
ByteArrayPayload payload = (object.getPayload() instanceof ByteArrayPayload) ? ByteArrayPayload.class.cast(object
Blob blob = createUpdatedCopyOfBlob(in);
container.put(blob.getMetadata().getName(), blob);
return immediateFuture(Iterables.getOnlyElement(blob.getAllHeaders().get(HttpHeaders.ETAG)));
}
public ListenableFuture<Blob> putBlobAndReturnOld(String containerName, Blob in) {
ConcurrentMap<String, Blob> container = getContainerToBlobs().get(containerName);
if (container == null) {
new IllegalStateException("containerName not found: " + containerName);
}
Blob blob = createUpdatedCopyOfBlob(in);
Blob old = container.put(blob.getMetadata().getName(), blob);
return immediateFuture(old);
}
protected Blob createUpdatedCopyOfBlob(Blob in) {
ByteArrayPayload payload = (in.getPayload() instanceof ByteArrayPayload) ? ByteArrayPayload.class.cast(in
.getPayload()) : null;
if (payload == null)
payload = (object.getPayload() instanceof DelegatingPayload) ? (DelegatingPayload.class.cast(
object.getPayload()).getDelegate() instanceof ByteArrayPayload) ? ByteArrayPayload.class
.cast(DelegatingPayload.class.cast(object.getPayload()).getDelegate()) : null : null;
payload = (in.getPayload() instanceof DelegatingPayload) ? (DelegatingPayload.class.cast(in.getPayload())
.getDelegate() instanceof ByteArrayPayload) ? ByteArrayPayload.class.cast(DelegatingPayload.class.cast(
in.getPayload()).getDelegate()) : null : null;
try {
if (payload == null || !(payload instanceof ByteArrayPayload)) {
String oldContentType = object.getPayload().getContentType();
String oldContentType = in.getPayload().getContentType();
ByteArrayOutputStream out = new ByteArrayOutputStream();
object.getPayload().writeTo(out);
in.getPayload().writeTo(out);
payload = (ByteArrayPayload) Payloads.calculateMD5(Payloads.newPayload(out.toByteArray()));
payload.setContentType(oldContentType);
} else {
if (payload.getContentMD5() == null)
Payloads.calculateMD5(object, crypto.md5());
Payloads.calculateMD5(in, crypto.md5());
}
} catch (IOException e) {
Throwables.propagate(e);
}
Blob blob = blobFactory.create(copy(object.getMetadata()));
Blob blob = blobFactory.create(copy(in.getMetadata()));
blob.setPayload(payload);
blob.getMetadata().setLastModified(new Date());
blob.getMetadata().setSize(payload.getContentLength());
@ -489,18 +532,17 @@ public class TransientAsyncBlobStore extends BaseAsyncBlobStore {
String eTag = CryptoStreams.hex(payload.getContentMD5());
blob.getMetadata().setETag(eTag);
container.put(blob.getMetadata().getName(), blob);
// Set HTTP headers to match metadata
blob.getAllHeaders().put(HttpHeaders.LAST_MODIFIED,
dateService.rfc822DateFormat(blob.getMetadata().getLastModified()));
blob.getAllHeaders().put(HttpHeaders.ETAG, eTag);
blob.getAllHeaders().put(HttpHeaders.CONTENT_TYPE, payload.getContentType());
blob.getAllHeaders().put(HttpHeaders.CONTENT_LENGTH, payload.getContentLength() + "");
blob.getAllHeaders().put("Content-MD5", CryptoStreams.base64(payload.getContentMD5()));
blob.getAllHeaders().replaceValues(HttpHeaders.LAST_MODIFIED,
Collections.singleton(dateService.rfc822DateFormat(blob.getMetadata().getLastModified())));
blob.getAllHeaders().replaceValues(HttpHeaders.ETAG, Collections.singleton(eTag));
blob.getAllHeaders().replaceValues(HttpHeaders.CONTENT_TYPE, Collections.singleton(payload.getContentType()));
blob.getAllHeaders().replaceValues(HttpHeaders.CONTENT_LENGTH,
Collections.singleton(payload.getContentLength() + ""));
blob.getAllHeaders().replaceValues("Content-MD5",
Collections.singleton(CryptoStreams.base64(payload.getContentMD5())));
blob.getAllHeaders().putAll(Multimaps.forMap(blob.getMetadata().getUserMetadata()));
return immediateFuture(eTag);
return blob;
}
/**

View File

@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
$HeadURL$ $Revision$ $Date$ Copyright (C) 2010 Cloud Conscious, LLC
<info@cloudconscious.com>
Copyright (C) 2010 Cloud Conscious, LLC <info@cloudconscious.com>
====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
@ -97,5 +96,12 @@
<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

@ -30,12 +30,16 @@ which is basically Chef Server as a Service.
;; load the rsa key from ~/.chef/CLIENT_NAME.pem
(def credential (load-pem client))
(def chef (chef-service client credential :chef.endpoint \"https://api.opscode.com/organizations/YOUR_ORG\"))
;; 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])
@ -57,14 +61,22 @@ See http://code.google.com/p/jclouds for details."}
([#^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."
([#^String identity #^String credential & options]
"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 identity credential
(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)))
@ -125,6 +137,13 @@ See http://code.google.com/p/jclouds for details."}
([#^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]
@ -146,6 +165,13 @@ See http://code.google.com/p/jclouds for details."}
([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]

View File

@ -75,50 +75,87 @@ public class ChefContextFactory {
}
/**
* @see RestContextFactory#createContextBuilder(String, String)
* @see #createContext(String, String, String)
*/
public ChefContext createContext(String identity, String credential) {
RestContextBuilder<?, ?> builder = RestContextBuilder.class.cast(contextFactory.createContextBuilder("chef",
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 RestContextFactory#createContextBuilder(Properties)
* @see #createContext(String, Properties)
*/
public ChefContext createContext(Properties overrides) {
RestContextBuilder<?, ?> builder = RestContextBuilder.class.cast(contextFactory.createContextBuilder("chef",
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 RestContextFactory#createContextBuilder(Iterable)
* @see #createContext(String, Iterable, Properties)
*/
public ChefContext createContext(Iterable<? extends Module> modules, Properties overrides) {
RestContextBuilder<?, ?> builder = RestContextBuilder.class.cast(contextFactory.createContextBuilder("chef",
modules, overrides));
return buildContextUnwrappingExceptions(builder);
return createContext("chef", modules, overrides);
}
/**
* @see RestContextFactory#createContextBuilder(String,String, Iterable)
* @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) {
RestContextBuilder<?, ?> builder = RestContextBuilder.class.cast(contextFactory.createContextBuilder("chef",
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 RestContextFactory#createContextBuilder(String,String, Iterable,
* Properties)
* @see #createContext(String,String, String, Iterable, Properties)
*/
public ChefContext createContext(@Nullable String identity, @Nullable String credential,
Iterable<? extends Module> modules, Properties overrides) {
RestContextBuilder<?, ?> builder = RestContextBuilder.class.cast(contextFactory.createContextBuilder("chef",
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);
}

View File

@ -0,0 +1,346 @@
/**
*
* 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

@ -0,0 +1,39 @@
/**
*
* 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

@ -0,0 +1,43 @@
/**
*
* 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

@ -0,0 +1,63 @@
/**
*
* 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 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.test.TransientChefAsyncClient;
import org.jclouds.chef.test.TransientChefClient;
import org.jclouds.rest.RestContextFactory;
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));
super.configure();
}
@Override
protected void bindAsyncClient() {
bind(ChefAsyncClient.class).to(TransientChefAsyncClient.class).asEagerSingleton();
}
@Provides
@Singleton
ChefClient provideClient(TransientChefClient in) {
return in;
}
}

View File

@ -0,0 +1,69 @@
;
;
; 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"))))

View File

@ -84,7 +84,7 @@ public abstract class BaseChefClientLiveTest {
private Node node;
private Role role;
protected Json json;
private DatabagItem databagItem;
protected DatabagItem databagItem;
public static final String PREFIX = System.getProperty("user.name") + "-jcloudstest";
public BaseChefClientLiveTest() {

View File

@ -0,0 +1,327 @@
/**
*
* 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 org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
import java.io.IOException;
import java.util.Properties;
import org.jclouds.chef.BaseChefClientLiveTest;
import org.jclouds.chef.ChefClient;
import org.jclouds.chef.ChefContext;
import org.jclouds.chef.ChefContextFactory;
import org.jclouds.chef.config.ChefParserModule;
import org.jclouds.chef.domain.DatabagItem;
import org.jclouds.json.Json;
import org.jclouds.json.config.GsonModule;
import org.jclouds.rest.HttpClient;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import com.google.inject.Guice;
/**
* Tests behavior of {@code TransientChefClient}
*
* @author Adrian Cole
*/
@Test(groups = "integration", testName = "chef.TransientChefClientIntegrationTest")
public class TransientChefClientIntegrationTest extends BaseChefClientLiveTest {
public void testCreateDatabag1() throws Exception {
getAdminConnection().deleteDatabag(PREFIX);
getAdminConnection().createDatabag(PREFIX);
}
@Test(dependsOnMethods = "testCreateDatabag1")
public void testDatabagExists1() throws Exception {
assertNotNull(getClientConnection().databagExists(PREFIX));
}
@Test(dependsOnMethods = { "testCreateDatabag1"})
public void testCreateDatabagItem1() 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 = "testCreateDatabagItem1")
public void testDatabagItemExists1() throws Exception {
assertNotNull(getClientConnection().databagItemExists(PREFIX, PREFIX));
}
@Test(dependsOnMethods = "testDatabagItemExists1")
public void testUpdateDatabagItem1() throws Exception {
for (String databagItemId : getClientConnection().listDatabagItems(PREFIX)) {
DatabagItem databagItem = getAdminConnection().getDatabagItem(PREFIX, databagItemId);
getAdminConnection().updateDatabagItem(PREFIX, databagItem);
}
}
@Override
@Test(enabled = false)
public void testClientExists() throws Exception {
super.testClientExists();
}
@Override
public void testCreateClient() throws Exception {
}
@Override
public void testCreateDatabag() throws Exception {
super.testCreateDatabag();
}
@Override
public void testCreateDatabagItem() throws Exception {
super.testCreateDatabagItem();
}
@Override
public void testDatabagExists() throws Exception {
super.testDatabagExists();
}
@Override
public void testDatabagItemExists() throws Exception {
super.testDatabagItemExists();
}
@Override
public void testListDatabagItems() throws Exception {
super.testListDatabagItems();
}
@Override
public void testListDatabags() throws Exception {
super.testListDatabags();
}
@Override
@Test(enabled = false)
public void testCreateCookbook() throws Exception {
super.testCreateCookbook();
}
@Override
@Test(enabled = false)
public void testCreateNewCookbook() throws Exception {
super.testCreateNewCookbook();
}
@Override
@Test(enabled = false)
public void testCreateNode() throws Exception {
super.testCreateNode();
}
@Override
@Test(enabled = false)
public void testCreateRole() throws Exception {
super.testCreateRole();
}
@Override
@Test(enabled = false)
public void testGenerateKeyForClient() throws Exception {
super.testGenerateKeyForClient();
}
@Override
@Test(enabled = false)
public void testListCookbooks() throws Exception {
super.testListCookbooks();
}
@Override
@Test(enabled = false)
public void testListNodes() throws Exception {
super.testListNodes();
}
@Override
@Test(enabled = false)
public void testListRoles() throws Exception {
super.testListRoles();
}
@Override
@Test(enabled = false)
public void testListSearchIndexes() throws Exception {
super.testListSearchIndexes();
}
@Override
@Test(enabled = false)
public void testNodeExists() throws Exception {
super.testNodeExists();
}
@Override
@Test(enabled = false)
public void testRoleExists() throws Exception {
super.testRoleExists();
}
@Override
@Test(enabled = false)
public void testSearchClients() throws Exception {
super.testSearchClients();
}
@Override
@Test(enabled = false)
public void testSearchDatabag() throws Exception {
super.testSearchDatabag();
}
@Override
@Test(enabled = false)
public void testSearchDatabagNotFound() throws Exception {
super.testSearchDatabagNotFound();
}
@Override
@Test(enabled = false)
public void testSearchNodes() throws Exception {
super.testSearchNodes();
}
@Override
@Test(enabled = false)
public void testSearchRoles() throws Exception {
super.testSearchRoles();
}
@Override
@Test(enabled = false)
public void testUpdateCookbook() throws Exception {
super.testUpdateCookbook();
}
@Override
@Test(enabled = false)
public void testUpdateDatabagItem() throws Exception {
super.testUpdateDatabagItem();
}
@Override
@Test(enabled = false)
public void testUpdateNode() throws Exception {
super.testUpdateNode();
}
@Override
@Test(enabled = false)
public void testUpdateRole() throws Exception {
super.testUpdateRole();
}
@Override
@Test(enabled = false)
public void testValidatorCannotCreateClient() throws Exception {
super.testValidatorCannotCreateClient();
}
@Override
@Test(enabled = false)
public void testValidatorCannotDeleteClient() throws Exception {
super.testValidatorCannotDeleteClient();
}
@Override
@Test(enabled = false)
public void testValidatorCannotListClients() throws Exception {
super.testValidatorCannotListClients();
}
private ChefContext validatorConnection;
private ChefContext clientConnection;
private ChefContext adminConnection;
@Override
@BeforeClass(groups = { "integration" })
public void setupClient() throws IOException {
// TODO make this nicer
validatorConnection = adminConnection = clientConnection = createConnection("user", "userkey");
json = Guice.createInjector(new GsonModule(), new ChefParserModule()).getInstance(Json.class);
}
@Override
@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();
}
private ChefContext createConnection(String identity, String key) throws IOException {
return new ChefContextFactory().createContext("transientchef", identity, key);
}
@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);
}
@Override
protected void closeContexts() {
if (clientConnection != null)
clientConnection.close();
if (validatorConnection != null)
validatorConnection.close();
if (adminConnection != null)
adminConnection.close();
}
}

View File

@ -62,6 +62,9 @@ hostingdotcom.propertiesbuilder=org.jclouds.vcloud.hostingdotcom.HostingDotComVC
chef.contextbuilder=org.jclouds.chef.ChefContextBuilder
chef.propertiesbuilder=org.jclouds.chef.ChefPropertiesBuilder
transientchef.contextbuilder=org.jclouds.chef.test.TransientChefContextBuilder
transientchef.propertiesbuilder=org.jclouds.chef.ChefPropertiesBuilder
opscodeplatform.contextbuilder=org.jclouds.opscodeplatform.OpscodePlatformContextBuilder
opscodeplatform.propertiesbuilder=org.jclouds.opscodeplatform.OpscodePlatformPropertiesBuilder