Issue 191: added databag support to chef

This commit is contained in:
Adrian Cole 2010-08-01 11:19:06 -07:00
parent d79eb21e69
commit 2f3c0b4afe
28 changed files with 1608 additions and 570 deletions

View File

@ -40,17 +40,19 @@ 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.UploadSandbox;
import org.jclouds.chef.filters.SignedHeaderAuth;
import org.jclouds.chef.functions.ParseKeySetFromJson;
import org.jclouds.domain.JsonBall;
import org.jclouds.rest.annotations.BinderParam;
import org.jclouds.rest.annotations.ExceptionParser;
import org.jclouds.rest.annotations.Headers;
@ -62,6 +64,7 @@ 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;
@ -85,7 +88,7 @@ public interface ChefAsyncClient {
@POST
@Path("sandboxes")
ListenableFuture<UploadSandbox> getUploadSandboxForChecksums(
@BinderParam(BindChecksumsToJsonPayload.class) Set<List<Byte>> md5s);
@BinderParam(BindChecksumsToJsonPayload.class) Set<List<Byte>> md5s);
@PUT
ListenableFuture<Void> uploadContent(@BinderParam(BindChecksumsToJsonPayload.class) Set<List<Byte>> md5s);
@ -96,7 +99,7 @@ public interface ChefAsyncClient {
@PUT
@Path("sandboxes/{id}")
ListenableFuture<Sandbox> commitSandbox(@PathParam("id") String id,
@BinderParam(BindIsCompletedToJsonPayload.class) boolean isCompleted);
@BinderParam(BindIsCompletedToJsonPayload.class) boolean isCompleted);
/**
* @see ChefCookbooks#listCookbooks
@ -113,7 +116,7 @@ public interface ChefAsyncClient {
@PUT
@Path("cookbooks/{cookbookname}/{version}")
ListenableFuture<CookbookVersion> updateCookbook(@PathParam("cookbookname") String cookbookName,
@PathParam("version") String version, @BinderParam(BindToJsonPayload.class) CookbookVersion cookbook);
@PathParam("version") String version, @BinderParam(BindToJsonPayload.class) CookbookVersion cookbook);
/**
* @see ChefCookbook#deleteCookbook(String)
@ -122,7 +125,7 @@ public interface ChefAsyncClient {
@Path("cookbooks/{cookbookname}/{version}")
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
ListenableFuture<CookbookVersion> deleteCookbook(@PathParam("cookbookname") String cookbookName,
@PathParam("version") String version);
@PathParam("version") String version);
/**
* @see ChefCookbook#getVersionsOfCookbook
@ -140,7 +143,7 @@ public interface ChefAsyncClient {
@Path("cookbooks/{cookbookname}/{version}")
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
ListenableFuture<CookbookVersion> getCookbook(@PathParam("cookbookname") String cookbookName,
@PathParam("version") String version);
@PathParam("version") String version);
/**
* @see ChefClient#createClient
@ -155,7 +158,7 @@ public interface ChefAsyncClient {
@PUT
@Path("clients/{clientname}")
ListenableFuture<Client> generateKeyForClient(
@PathParam("clientname") @BinderParam(BindGenerateKeyForClientToJsonPayload.class) String clientname);
@PathParam("clientname") @BinderParam(BindGenerateKeyForClientToJsonPayload.class) String clientname);
/**
* @see ChefClient#clientExists
@ -203,7 +206,7 @@ public interface ChefAsyncClient {
@PUT
@Path("nodes/{nodename}")
ListenableFuture<Node> updateNode(
@PathParam("nodename") @ParamParser(NodeName.class) @BinderParam(BindToJsonPayload.class) Node node);
@PathParam("nodename") @ParamParser(NodeName.class) @BinderParam(BindToJsonPayload.class) Node node);
/**
* @see ChefNode#nodeExists
@ -243,7 +246,7 @@ public interface ChefAsyncClient {
*/
@POST
@Path("roles")
ListenableFuture<Role> createRole(@BinderParam(BindToJsonPayload.class) Role role);
ListenableFuture<Void> createRole(@BinderParam(BindToJsonPayload.class) Role role);
/**
* @see ChefClient#updateRole
@ -251,7 +254,7 @@ public interface ChefAsyncClient {
@PUT
@Path("roles/{rolename}")
ListenableFuture<Role> updateRole(
@PathParam("rolename") @ParamParser(RoleName.class) @BinderParam(BindToJsonPayload.class) Role role);
@PathParam("rolename") @ParamParser(RoleName.class) @BinderParam(BindToJsonPayload.class) Role role);
/**
* @see ChefRole#roleExists
@ -287,51 +290,88 @@ public interface ChefAsyncClient {
ListenableFuture<Set<String>> listRoles();
/**
* @see ChefClient#createDataBag
*/
@POST
@Path("data")
ListenableFuture<JsonBall> createDataBag(@BinderParam(BindToJsonPayload.class) JsonBall node);
/**
* @see ChefClient#updateDataBag
*/
@PUT
@Path("data/{path}")
ListenableFuture<JsonBall> updateDataBag(@PathParam("path") String path,
@BinderParam(BindToJsonPayload.class) JsonBall node);
/**
* @see ChefDataBag#nodeExists
*/
@HEAD
@Path("data/{path}")
@ExceptionParser(ReturnFalseOnNotFoundOr404.class)
ListenableFuture<Boolean> dataBagExists(@PathParam("path") String path);
/**
* @see ChefDataBag#getDataBag
*/
@GET
@Path("data/{path}")
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
ListenableFuture<JsonBall> getDataBag(@PathParam("path") String path);
/**
* @see ChefDataBag#deleteDataBag
*/
@DELETE
@Path("data/{path}")
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
ListenableFuture<JsonBall> deleteDataBag(@PathParam("path") String path);
/**
* @see ChefDataBag#listDataBags
* @see ChefDatabag#listDatabags
*/
@GET
@Path("data")
@ResponseParser(ParseKeySetFromJson.class)
@ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
ListenableFuture<Set<String>> listDataBags();
ListenableFuture<Set<String>> listDatabags();
/**
* @see ChefClient#createDatabag
*/
@POST
@Path("data")
ListenableFuture<Void> createDatabag(@BinderParam(BindNameToJsonPayload.class) String databagName);
/**
* @see ChefDatabag#databagExists
*/
@HEAD
@Path("data/{name}")
@ExceptionParser(ReturnFalseOnNotFoundOr404.class)
ListenableFuture<Boolean> databagExists(@PathParam("name") String databagName);
/**
* @see ChefDatabag#deleteDatabag
*/
@DELETE
@Path("data/{name}")
@ExceptionParser(ReturnVoidOnNotFoundOr404.class)
ListenableFuture<Void> deleteDatabag(@PathParam("name") String databagName);
/**
* @see ChefDatabag#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 ChefDatabag#databagItemExists
*/
@HEAD
@Path("data/{databagName}/{databagItemId}")
@ExceptionParser(ReturnFalseOnNotFoundOr404.class)
ListenableFuture<Boolean> databagItemExists(@PathParam("databagName") String databagName,
@PathParam("databagItemId") String databagItemId);
/**
* @see ChefDatabag#getDatabagItem
*/
@GET
@Path("data/{databagName}/{databagItemId}")
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
ListenableFuture<DatabagItem> getDatabagItem(@PathParam("databagName") String databagName,
@PathParam("databagItemId") String databagItemId);
/**
* @see ChefDatabag#deleteDatabagItem
*/
@DELETE
@Path("data/{databagName}/{databagItemId}")
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
ListenableFuture<DatabagItem> deleteDatabagItem(@PathParam("databagName") String databagName,
@PathParam("databagItemId") String databagItemId);
}

View File

@ -47,6 +47,7 @@ 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;
@ -54,6 +55,8 @@ 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.
@ -70,7 +73,8 @@ public interface ChefClient {
* FIXME Comment this
*
* @param md5s
* raw md5s; uses {@code Bytes.asList()} and {@code Bytes.toByteArray()} as necessary
* raw md5s; uses {@code Bytes.asList()} and {@code
* Bytes.toByteArray()} as necessary
* @return
*/
UploadSandbox getUploadSandboxForChecksums(Set<List<Byte>> md5s);
@ -84,7 +88,8 @@ public interface ChefClient {
* <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.
* "403 Forbidden" if you do not have permission to see the
* cookbook list.
*/
Set<String> listCookbooks();
@ -106,7 +111,8 @@ public interface ChefClient {
* <p/>
* "401 Unauthorized" if you are not a recognized user.
* <p/>
* "403 Forbidden" if you do not have Delete rights on the cookbook.
* "403 Forbidden" if you do not have Delete rights on the
* cookbook.
*/
CookbookVersion deleteCookbook(String cookbookName, String version);
@ -118,13 +124,14 @@ public interface ChefClient {
* <p/>
* "401 Unauthorized" if the caller is not a recognized user.
* <p/>
* "403 Forbidden" if the caller is not authorized to view the cookbook.
* "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.
* 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
*
@ -132,20 +139,22 @@ public interface ChefClient {
* <p/>
* "401 Unauthorized" if the caller is not a recognized user.
* <p/>
* "403 Forbidden" if the caller is not authorized to view the cookbook.
* "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.
* @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.
* "403 Forbidden" if the caller is not authorized to create a
* client.
* @throws HttpResponseException
* "409 Conflict" if the client already exists
*/
@ -153,7 +162,8 @@ public interface ChefClient {
Client createClient(String name);
/**
* generate a new key-pair for this client, and return the new private key in the response body.
* generate a new key-pair for this client, and return the new private key in
* the response body.
*
* @return the new private key
*
@ -161,7 +171,8 @@ public interface ChefClient {
* <p/>
* "401 Unauthorized" if the caller is not a recognized user.
* <p/>
* "403 Forbidden" if the caller is not authorized to modify the client.
* "403 Forbidden" if the caller is not authorized to modify the
* client.
*/
@Timeout(duration = 120, timeUnit = TimeUnit.SECONDS)
Client generateKeyForClient(String name);
@ -221,7 +232,8 @@ public interface ChefClient {
* <p/>
* "401 Unauthorized" if the caller is not a recognized user.
* <p/>
* "403 Forbidden" if the caller is not authorized to create a node.
* "403 Forbidden" if the caller is not authorized to create a
* node.
* @throws HttpResponseException
* "409 Conflict" if the node already exists
*/
@ -293,12 +305,13 @@ public interface ChefClient {
* <p/>
* "401 Unauthorized" if the caller is not a recognized user.
* <p/>
* "403 Forbidden" if the caller is not authorized to create a role.
* "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)
Role createRole(Role role);
void createRole(Role role);
/**
* Creates or updates (uploads) a role //TODO document
@ -356,4 +369,119 @@ public interface ChefClient {
* "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();
/**
* gets an existing 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);
}

View File

@ -1,6 +1,6 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed under the Apache License, Version 2.0 (the "License");

View File

@ -1,6 +1,6 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
@ -22,19 +22,15 @@ import java.util.List;
import java.util.Properties;
import org.jclouds.chef.config.ChefRestClientModule;
import org.jclouds.ohai.config.ConfiguresOhai;
import org.jclouds.ohai.config.JMXOhaiJVMModule;
import org.jclouds.rest.RestContextBuilder;
import org.jclouds.ohai.OhaiContextBuilder;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import com.google.inject.Injector;
import com.google.inject.Module;
/**
* @author Adrian Cole
*/
public class ChefContextBuilder extends RestContextBuilder<ChefClient, ChefAsyncClient> {
public class ChefContextBuilder extends OhaiContextBuilder<ChefClient, ChefAsyncClient> {
public ChefContextBuilder(Properties props) {
super(ChefClient.class, ChefAsyncClient.class, props);
@ -65,19 +61,4 @@ public class ChefContextBuilder extends RestContextBuilder<ChefClient, ChefAsync
Injector injector = buildInjector();
return injector.getInstance(ChefContext.class);
}
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 JMXOhaiJVMModule());
}
}

View File

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

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

@ -18,6 +18,9 @@
*/
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;
@ -33,10 +36,11 @@ import javax.inject.Named;
import javax.inject.Singleton;
import org.jclouds.Constants;
import org.jclouds.chef.domain.DataBagItem;
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;
@ -75,7 +79,7 @@ public class ChefParserModule extends AbstractModule {
@Override
public PrivateKey deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
throws JsonParseException {
String keyText = json.getAsString().replaceAll("\\n", "\n");
try {
return crypto.rsaKeyFactory().generatePrivate(Pems.privateKeySpec(InputSuppliers.of(keyText)));
@ -108,7 +112,7 @@ public class ChefParserModule extends AbstractModule {
@Override
public PublicKey deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
throws JsonParseException {
String keyText = json.getAsString().replaceAll("\\n", "\n");
try {
return crypto.rsaKeyFactory().generatePublic(Pems.publicKeySpec(InputSuppliers.of(keyText)));
@ -141,7 +145,7 @@ public class ChefParserModule extends AbstractModule {
@Override
public X509Certificate deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
throws JsonParseException {
String keyText = json.getAsString().replaceAll("\\n", "\n");
try {
return Pems.x509Certificate(InputSuppliers.of(keyText), crypto.certFactory());
@ -159,23 +163,45 @@ public class ChefParserModule extends AbstractModule {
}
@ImplementedBy(DataBagItemAdapterImpl.class)
public static interface DataBagItemAdapter extends JsonSerializer<DataBagItem>, JsonDeserializer<DataBagItem> {
public static interface DataBagItemAdapter extends JsonSerializer<DatabagItem>, JsonDeserializer<DatabagItem> {
}
@Singleton
public static class DataBagItemAdapterImpl implements DataBagItemAdapter {
private final Json json;
@Override
public JsonElement serialize(DataBagItem src, Type typeOfSrc, JsonSerializationContext context) {
return new JsonLiteral(src.toString());
@Inject
DataBagItemAdapterImpl(Json json) {
this.json = json;
}
@Override
public DataBagItem deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
IdHolder idHolder = context.deserialize(json, IdHolder.class);
return new DataBagItem(idHolder.id, json.toString());
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);
}
}
@ -187,9 +213,9 @@ public class ChefParserModule extends AbstractModule {
@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);
PublicKeyAdapter publicAdapter, X509CertificateAdapter certAdapter) {
return ImmutableMap.<Type, Object> of(DatabagItem.class, adapter, PrivateKey.class, privateAdapter,
PublicKey.class, publicAdapter, X509Certificate.class, certAdapter);
}
@Override

View File

@ -1,3 +1,26 @@
/**
*
* 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
*
* 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;
@ -8,12 +31,12 @@ import org.jclouds.domain.JsonBall;
*
* @author Adrian Cole
*/
public class DataBagItem extends JsonBall {
public class DatabagItem extends JsonBall {
private static final long serialVersionUID = 7905637919304343493L;
private final String id;
public DataBagItem(String id, String value) {
public DatabagItem(String id, String value) {
super(value);
this.id = checkNotNull(id, "id");
}
@ -34,7 +57,7 @@ public class DataBagItem extends JsonBall {
return false;
if (getClass() != obj.getClass())
return false;
DataBagItem other = (DataBagItem) obj;
DatabagItem other = (DatabagItem) obj;
if (id == null) {
if (other.id != null)
return false;

View File

@ -1,6 +1,6 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
@ -16,7 +16,6 @@
* limitations under the License.
* ====================================================================
*/
package org.jclouds.chef.internal;
import java.net.URI;

View File

@ -0,0 +1,60 @@
/**
*
* 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.JMXOhaiJVMModule;
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 JMXOhaiJVMModule());
}
}

View File

@ -0,0 +1,353 @@
/**
*
* 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
*
* 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.
* ====================================================================
*/
/**
*
* 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
*
* 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.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.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.HttpClient;
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;
private 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(getValidatorConnection().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.getProviders()).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
public void testListClients() throws Exception {
for (String client : getValidatorConnection().listClients())
assertNotNull(getValidatorConnection().getClient(client));
}
@Test(dependsOnMethods = "testListClients")
public void testCreateClient() throws Exception {
getValidatorConnection().deleteClient(PREFIX);
clientKey = Pems.pem(getValidatorConnection().createClient(PREFIX).getPrivateKey());
recreateClientConnection();
getClientConnection().clientExists(PREFIX);
Set<String> clients = getValidatorConnection().listClients();
assert clients.contains(PREFIX) : String.format("client %s not in %s", PREFIX, clients);
assertNotNull(getValidatorConnection().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);
}
}
@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

@ -32,6 +32,7 @@ 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;
@ -51,6 +52,7 @@ import org.jclouds.rest.RestContextFactory.ContextSpec;
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;
@ -73,9 +75,9 @@ public class ChefAsyncClientTest extends RestClientTest<ChefAsyncClient> {
Method method = ChefAsyncClient.class.getMethod("commitSandbox", String.class, boolean.class);
GeneratedHttpRequest<ChefAsyncClient> httpRequest = processor.createRequest(method,
"0189e76ccc476701d6b374e5a1a27347", true);
"0189e76ccc476701d6b374e5a1a27347", true);
assertRequestLineEquals(httpRequest,
"PUT http://localhost:4000/sandboxes/0189e76ccc476701d6b374e5a1a27347 HTTP/1.1");
"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);
@ -90,15 +92,15 @@ public class ChefAsyncClientTest extends RestClientTest<ChefAsyncClient> {
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"))));
.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);
httpRequest,
"{\"checksums\":{\"0189e76ccc476701d6b374e5a1a27347\":null,\"0c5ecd7788cf4f6c7de2a57193897a6c\":null,\"1dda05ed139664f1f89b9dec482b77c0\":null}}",
"application/json", false);
assertResponseParserClassEquals(method, httpRequest, ParseJson.class);
assertSaxResponseParserClassEquals(method, null);
@ -140,16 +142,16 @@ public class ChefAsyncClientTest extends RestClientTest<ChefAsyncClient> {
public void testUpdateCookbook() throws SecurityException, NoSuchMethodException, IOException {
Method method = ChefAsyncClient.class.getMethod("updateCookbook", String.class, String.class,
CookbookVersion.class);
CookbookVersion.class);
GeneratedHttpRequest<ChefAsyncClient> httpRequest = processor.createRequest(method, "cookbook", "1.0.1",
new CookbookVersion("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);
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);
@ -284,14 +286,14 @@ public class ChefAsyncClientTest extends RestClientTest<ChefAsyncClient> {
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]")));
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);
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);
@ -304,14 +306,14 @@ public class ChefAsyncClientTest extends RestClientTest<ChefAsyncClient> {
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]")));
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);
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);
@ -370,16 +372,16 @@ public class ChefAsyncClientTest extends RestClientTest<ChefAsyncClient> {
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]")));
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);
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);
assertResponseParserClassEquals(method, httpRequest, ReleasePayloadAndReturn.class);
assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, null);
@ -390,14 +392,14 @@ public class ChefAsyncClientTest extends RestClientTest<ChefAsyncClient> {
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]")));
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);
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);
@ -423,6 +425,210 @@ public class ChefAsyncClientTest extends RestClientTest<ChefAsyncClient> {
}
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);
}
@Override
protected void checkFilters(HttpRequest request) {
assertEquals(request.getFilters().size(), 1);
@ -453,6 +659,6 @@ public class ChefAsyncClientTest extends RestClientTest<ChefAsyncClient> {
@Override
public ContextSpec<ChefClient, ChefAsyncClient> createContextSpec() {
return new RestContextFactory().createContextSpec("chef", "user", SignedHeaderAuthTest.PRIVATE_KEY,
new Properties());
new Properties());
}
}

View File

@ -24,39 +24,24 @@
package org.jclouds.chef;
import static com.google.common.base.Preconditions.checkNotNull;
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.CookbookVersion;
import org.jclouds.chef.domain.Node;
import org.jclouds.chef.domain.Resource;
import org.jclouds.chef.domain.Role;
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.chef.config.ChefParserModule;
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.jclouds.rest.RestContextFactory;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import com.google.common.base.Charsets;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.io.Files;
import com.google.common.primitives.Bytes;
import com.google.inject.Guice;
import com.google.inject.Module;
/**
@ -65,21 +50,15 @@ import com.google.inject.Module;
* @author Adrian Cole
*/
@Test(groups = "live", testName = "chef.ChefClientLiveTest")
public class ChefClientLiveTest {
public class ChefClientLiveTest extends BaseChefClientLiveTest {
private ChefContext validatorConnection;
private ChefContext clientConnection;
private ChefContext adminConnection;
private String clientKey;
private String endpoint;
private String validator;
private String user;
private Node node;
private Role role;
public static final String PREFIX = System.getProperty("user.name") + "-jcloudstest";
@Override
@BeforeClass(groups = { "live" })
public void setupClient() throws IOException {
endpoint = checkNotNull(System.getProperty("jclouds.test.endpoint"), "jclouds.test.endpoint");
@ -95,199 +74,45 @@ public class ChefClientLiveTest {
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 (ChefContext) new RestContextFactory().<ChefClient, ChefAsyncClient> createContext("chef", identity, key,
ImmutableSet.<Module> of(new Log4JLoggingModule()), props);
ImmutableSet.<Module> of(new Log4JLoggingModule()), props);
}
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 = adminConnection.getApi().getUploadSandboxForChecksums(ImmutableSet.of(md5));
try {
assert site.getChecksums().containsKey(md5) : md5 + " not in " + site.getChecksums();
ChecksumStatus status = site.getChecksums().get(md5);
if (status.needsUpload()) {
adminConnection.utils().http().put(status.getUrl(), content);
}
adminConnection.getApi().commitSandbox(site.getSandboxId(), true);
} catch (RuntimeException e) {
adminConnection.getApi().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
adminConnection.getApi().updateCookbook("test3", "0.0.0", cookbook);
@Override
protected HttpClient getHttp() {
return adminConnection.utils().http();
}
@Test(dependsOnMethods = "testCreateClient")
public void testGenerateKeyForClient() throws Exception {
clientKey = Pems.pem(validatorConnection.getApi().generateKeyForClient(PREFIX).getPrivateKey());
@Override
protected ChefClient getAdminConnection() {
return adminConnection.getApi();
}
assertNotNull(clientKey);
clientConnection.close();
@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);
clientConnection.getApi().clientExists(PREFIX);
}
@Test(dependsOnMethods = "testCreateNewCookbook")
public void testListCookbooks() throws Exception {
for (String cookbook : adminConnection.getApi().listCookbooks())
for (String version : adminConnection.getApi().getVersionsOfCookbook(cookbook)) {
System.err.printf("%s/%s:%n", cookbook, version);
CookbookVersion cookbookO = adminConnection.getApi().getCookbook(cookbook, version);
for (Resource resource : ImmutableList.<Resource> builder().addAll(cookbookO.getDefinitions()).addAll(
cookbookO.getFiles()).addAll(cookbookO.getLibraries()).addAll(cookbookO.getProviders()).addAll(
cookbookO.getRecipes()).addAll(cookbookO.getResources()).addAll(cookbookO.getRootFiles()).addAll(
cookbookO.getTemplates()).build()) {
try {
InputStream stream = adminConnection.utils().http().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 : adminConnection.getApi().listCookbooks())
for (String version : adminConnection.getApi().getVersionsOfCookbook(cookbook)) {
System.err.printf("%s/%s:%n", cookbook, version);
CookbookVersion cook = adminConnection.getApi().getCookbook(cookbook, version);
adminConnection.getApi().updateCookbook(cookbook, version, cook);
}
}
@Test(dependsOnMethods = "testUpdateCookbook")
public void testCreateCookbook() throws Exception {
for (String cookbook : adminConnection.getApi().listCookbooks())
for (String version : adminConnection.getApi().getVersionsOfCookbook(cookbook)) {
System.err.printf("%s/%s:%n", cookbook, version);
CookbookVersion cook = adminConnection.getApi().getCookbook(cookbook, version);
adminConnection.getApi().deleteCookbook(cookbook, version);
assert adminConnection.getApi().getCookbook(cookbook, version) == null : cookbook + version;
adminConnection.getApi().updateCookbook(cookbook, version, cook);
}
}
@Test
public void testListClients() throws Exception {
for (String client : validatorConnection.getApi().listClients())
assertNotNull(validatorConnection.getApi().getClient(client));
}
@Test(dependsOnMethods = "testListClients")
public void testCreateClient() throws Exception {
validatorConnection.getApi().deleteClient(PREFIX);
clientKey = Pems.pem(validatorConnection.getApi().createClient(PREFIX).getPrivateKey());
System.out.println(clientKey);
assertNotNull(clientKey);
clientConnection = createConnection(PREFIX, clientKey);
clientConnection.getApi().clientExists(PREFIX);
Set<String> clients = validatorConnection.getApi().listClients();
assert clients.contains(PREFIX) : String.format("client %s not in %s", PREFIX, clients);
assertNotNull(validatorConnection.getApi().getClient(PREFIX));
}
@Test(dependsOnMethods = "testCreateClient")
public void testClientExists() throws Exception {
assertNotNull(validatorConnection.getApi().clientExists(PREFIX));
}
@Test
public void testListNodes() throws Exception {
Set<String> nodes = adminConnection.getApi().listNodes();
assertNotNull(nodes);
}
@Test(dependsOnMethods = "testCreateRole")
public void testCreateNode() throws Exception {
adminConnection.getApi().deleteNode(PREFIX);
clientConnection.getApi().createNode(new Node(PREFIX, Collections.singleton("role[" + PREFIX + "]")));
node = adminConnection.getApi().getNode(PREFIX);
// TODO check recipes
assertNotNull(node);
Set<String> nodes = adminConnection.getApi().listNodes();
assert nodes.contains(PREFIX) : String.format("node %s not in %s", PREFIX, nodes);
}
@Test(dependsOnMethods = "testCreateNode")
public void testNodeExists() throws Exception {
assertNotNull(clientConnection.getApi().nodeExists(PREFIX));
}
@Test(dependsOnMethods = "testNodeExists")
public void testUpdateNode() throws Exception {
for (String nodename : clientConnection.getApi().listNodes()) {
Node node = adminConnection.getApi().getNode(nodename);
adminConnection.getApi().updateNode(node);
}
}
@Test
public void testListRoles() throws Exception {
Set<String> roles = adminConnection.getApi().listRoles();
assertNotNull(roles);
}
@Test(dependsOnMethods = "testCreateClient")
public void testCreateRole() throws Exception {
adminConnection.getApi().deleteRole(PREFIX);
role = adminConnection.getApi().createRole(new Role(PREFIX, Collections.singleton("recipe[java]")));
// TODO check recipes
assertNotNull(role);
}
@Test(dependsOnMethods = "testCreateRole")
public void testRoleExists() throws Exception {
assertNotNull(clientConnection.getApi().roleExists(PREFIX));
}
@Test(dependsOnMethods = "testRoleExists")
public void testUpdateRole() throws Exception {
for (String rolename : clientConnection.getApi().listRoles()) {
Role role = adminConnection.getApi().getRole(rolename);
adminConnection.getApi().updateRole(role);
}
}
@AfterClass(groups = { "live" })
public void teardownClient() throws IOException {
if (validatorConnection.getApi().clientExists(PREFIX))
validatorConnection.getApi().deleteClient(PREFIX);
if (adminConnection.getApi().nodeExists(PREFIX))
adminConnection.getApi().deleteNode(PREFIX);
if (adminConnection.getApi().roleExists(PREFIX))
adminConnection.getApi().deleteRole(PREFIX);
@Override
protected void closeContexts() {
if (clientConnection != null)
clientConnection.close();
if (validatorConnection != null)

View File

@ -5,7 +5,7 @@ import static org.testng.Assert.assertEquals;
import java.io.IOException;
import org.jclouds.chef.config.ChefParserModule;
import org.jclouds.chef.domain.DataBagItem;
import org.jclouds.chef.domain.DatabagItem;
import org.jclouds.http.HttpResponse;
import org.jclouds.http.functions.ParseJson;
import org.jclouds.io.Payloads;
@ -24,20 +24,20 @@ import com.google.inject.TypeLiteral;
*/
@Test(groups = "unit", testName = "chef.ParseDataBagItemFromJsonTest")
public class ParseDataBagItemFromJsonTest {
private ParseJson<DataBagItem> handler;
private ParseJson<DatabagItem> handler;
private Json mapper;
@BeforeTest
protected void setUpInjector() throws IOException {
Injector injector = Guice.createInjector(new ChefParserModule(), new GsonModule());
handler = injector.getInstance(Key.get(new TypeLiteral<ParseJson<DataBagItem>>() {
handler = injector.getInstance(Key.get(new TypeLiteral<ParseJson<DatabagItem>>() {
}));
mapper = injector.getInstance(Json.class);
}
public void test1() {
String json = "{\"my_key\":\"my_data\",\"id\":\"item1\"}";
DataBagItem item = new DataBagItem("item1", json);
DatabagItem item = new DatabagItem("item1", json);
assertEquals(handler.apply(new HttpResponse(200, "ok", Payloads.newStringPayload(json))), item);
assertEquals(mapper.toJson(item), json);
}

View File

@ -23,9 +23,12 @@
*/
package org.jclouds.opscodeplatform;
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;
@ -34,17 +37,21 @@ import javax.ws.rs.core.MediaType;
import org.jclouds.chef.ChefAsyncClient;
import org.jclouds.chef.ChefClient;
import org.jclouds.chef.domain.Organization;
import org.jclouds.chef.domain.User;
import org.jclouds.chef.filters.SignedHeaderAuth;
import org.jclouds.chef.functions.OrganizationName;
import org.jclouds.chef.functions.Username;
import org.jclouds.chef.functions.ParseKeySetFromJson;
import org.jclouds.opscodeplatform.config.OrganizationName;
import org.jclouds.opscodeplatform.config.Username;
import org.jclouds.opscodeplatform.domain.Organization;
import org.jclouds.opscodeplatform.domain.User;
import org.jclouds.rest.annotations.BinderParam;
import org.jclouds.rest.annotations.Delegate;
import org.jclouds.rest.annotations.ExceptionParser;
import org.jclouds.rest.annotations.ParamParser;
import org.jclouds.rest.annotations.RequestFilters;
import org.jclouds.rest.annotations.ResponseParser;
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 com.google.common.util.concurrent.ListenableFuture;
@ -61,33 +68,50 @@ import com.google.common.util.concurrent.ListenableFuture;
@Consumes(MediaType.APPLICATION_JSON)
public interface OpscodePlatformAsyncClient {
/**
* @see ChefCookbooks#listCookbooksInOrg
* @see ChefCookbooks#listCookbooksInOrganization
*/
@Delegate
@Path("/organizations/{orgname}")
ChefAsyncClient getChefClientForOrg(@PathParam("orgname") String orgname);
@Path("organizations/{orgname}")
ChefAsyncClient getChefClientForOrganization(@PathParam("orgname") String orgname);
/**
* @see ChefUser#listUsers
*/
@GET
@Path("users")
@ResponseParser(ParseKeySetFromJson.class)
@ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
ListenableFuture<Set<String>> listUsers();
/**
* @see ChefRole#userExists
*/
@HEAD
@Path("users/{username}")
@ExceptionParser(ReturnFalseOnNotFoundOr404.class)
ListenableFuture<Boolean> userExists(@PathParam("username") String username);
/**
* @see ChefClient#createUser
*/
@POST
@Path("/users")
@Path("users")
ListenableFuture<User> createUser(@BinderParam(BindToJsonPayload.class) User user);
/**
* @see ChefClient#updateUser
*/
@PUT
@Path("/users/{username}")
@Path("users/{username}")
@Consumes(MediaType.APPLICATION_JSON)
ListenableFuture<User> updateUser(
@PathParam("username") @ParamParser(Username.class) @BinderParam(BindToJsonPayload.class) User user);
@PathParam("username") @ParamParser(Username.class) @BinderParam(BindToJsonPayload.class) User user);
/**
* @see ChefClient#getUser
*/
@GET
@Path("/users/{username}")
@Path("users/{username}")
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
@Consumes(MediaType.APPLICATION_JSON)
ListenableFuture<User> getUser(@PathParam("username") String username);
@ -96,43 +120,60 @@ public interface OpscodePlatformAsyncClient {
* @see ChefClient#deleteUser
*/
@DELETE
@Path("/users/{username}")
@Path("users/{username}")
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
@Consumes(MediaType.APPLICATION_JSON)
ListenableFuture<User> deleteUser(@PathParam("username") String username);
/**
* @see ChefClient#createOrg
*/
@POST
@Path("/organizations")
ListenableFuture<Organization> createOrg(@BinderParam(BindToJsonPayload.class) Organization org);
/**
* @see ChefClient#updateOrg
*/
@PUT
@Path("/organizations/{orgname}")
@Consumes(MediaType.APPLICATION_JSON)
ListenableFuture<Organization> updateOrg(
@PathParam("orgname") @ParamParser(OrganizationName.class) @BinderParam(BindToJsonPayload.class) Organization org);
/**
* @see ChefClient#getOrg
* @see ChefOrganization#listOrganizations
*/
@GET
@Path("/organizations/{orgname}")
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
@Consumes(MediaType.APPLICATION_JSON)
ListenableFuture<Organization> getOrg(@PathParam("orgname") String orgname);
@Path("organizations")
@ResponseParser(ParseKeySetFromJson.class)
@ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
ListenableFuture<Set<String>> listOrganizations();
/**
* @see ChefClient#deleteOrg
* @see ChefRole#organizationExists
*/
@DELETE
@Path("/organizations/{orgname}")
@HEAD
@Path("organizations/{organizationname}")
@ExceptionParser(ReturnFalseOnNotFoundOr404.class)
ListenableFuture<Boolean> organizationExists(@PathParam("organizationname") String organizationname);
/**
* @see ChefClient#createOrganization
*/
@POST
@Path("organizations")
ListenableFuture<Organization> createOrganization(@BinderParam(BindToJsonPayload.class) Organization org);
/**
* @see ChefClient#updateOrganization
*/
@PUT
@Path("organizations/{orgname}")
@Consumes(MediaType.APPLICATION_JSON)
ListenableFuture<Organization> updateOrganization(
@PathParam("orgname") @ParamParser(OrganizationName.class) @BinderParam(BindToJsonPayload.class) Organization org);
/**
* @see ChefClient#getOrganization
*/
@GET
@Path("organizations/{orgname}")
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
@Consumes(MediaType.APPLICATION_JSON)
ListenableFuture<Organization> deleteOrg(@PathParam("orgname") String orgname);
ListenableFuture<Organization> getOrganization(@PathParam("orgname") String orgname);
/**
* @see ChefClient#deleteOrganization
*/
@DELETE
@Path("organizations/{orgname}")
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
@Consumes(MediaType.APPLICATION_JSON)
ListenableFuture<Organization> deleteOrganization(@PathParam("orgname") String orgname);
}

View File

@ -23,15 +23,16 @@
*/
package org.jclouds.opscodeplatform;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import org.jclouds.chef.ChefClient;
import org.jclouds.chef.domain.Organization;
import org.jclouds.chef.domain.User;
import org.jclouds.concurrent.Timeout;
import org.jclouds.opscodeplatform.domain.Organization;
import org.jclouds.opscodeplatform.domain.User;
import org.jclouds.rest.AuthorizationException;
import org.jclouds.rest.ResourceNotFoundException;
import org.jclouds.rest.annotations.Delegate;
@ -51,18 +52,42 @@ public interface OpscodePlatformClient {
*/
@Delegate
@Path("/organizations/{orgname}")
ChefClient getChefClientForOrg(@PathParam("orgname") String orgname);
ChefClient getChefClientForOrganization(@PathParam("orgname") String orgname);
/**
* @return list of user names.
*
* @throws AuthorizationException
* <p/>
* "401 Unauthorized" if you are not a recognized user.
* <p/>
* "403 Forbidden" if you do not have rights to list users.
*/
Set<String> listUsers();
/**
*
* @return true if the specified user 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 user.
*/
boolean userExists(String name);
/**
* creates a new user
*
* @return the private key of the user. You can then use this user name and private key to access
* the Opscode API.
* @return the private key of the user. You can then use this user 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 user.
* "403 Forbidden" if the caller is not authorized to create a
* user.
*/
User createUser(User user);
@ -99,47 +124,79 @@ public interface OpscodePlatformClient {
User deleteUser(String username);
/**
* creates a new organization
* @return list of organization names.
*
* @return the private key of the organization. You can then use this organization name and
* private key to access the Opscode API.
* @throws AuthorizationException
* <p/>
* "401 Unauthorized" if the caller is not a recognized organization.
* "401 Unauthorized" if you are not a recognized user.
* <p/>
* "403 Forbidden" if the caller is not authorized to create a organization.
* "403 Forbidden" if you do not have rights to list
* organizations.
*/
Organization createOrg(Organization organization);
Set<String> listOrganizations();
/**
* updates an existing organization. Note: you must have update rights on the organization.
*
* @return true if the specified organization 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
* organization.
*/
boolean organizationExists(String name);
/**
* creates a new organization
*
* @return the private key of the organization. You can then use this
* organization name and private key to access the Opscode API.
* @throws AuthorizationException
* <p/>
* "401 Unauthorized" if the caller is not a recognized
* organization.
* <p/>
* "403 Forbidden" if the caller is not authorized to create a
* organization.
*/
Organization createOrganization(Organization organization);
/**
* updates an existing organization. Note: you must have update rights on the
* organization.
*
* @throws AuthorizationException
* <p/>
* "401 Unauthorized" if you are not a recognized organization.
* <p/>
* "403 Forbidden" if you do not have Update rights on the organization.
* "403 Forbidden" if you do not have Update rights on the
* organization.
* @throws ResourceNotFoundException
* if the organization does not exist.
*/
Organization updateOrg(Organization organization);
Organization updateOrganization(Organization organization);
/**
* retrieves an existing organization. Note: you must have update rights on the organization.
* retrieves an existing organization. Note: you must have update rights on
* the organization.
*
* @return null, if the organization is not found
*/
Organization getOrg(String organizationname);
Organization getOrganization(String organizationname);
/**
* deletes an existing organization. Note: you must have delete rights on the organization.
* deletes an existing organization. Note: you must have delete rights on the
* organization.
*
* @return last state of the org you deleted or null, if not found
* @throws AuthorizationException
* <p/>
* "401 Unauthorized" if you are not a recognized organization.
* <p/>
* "403 Forbidden" if you do not have Delete rights on the organization.
* "403 Forbidden" if you do not have Delete rights on the
* organization.
*/
Organization deleteOrg(String organizationname);
Organization deleteOrganization(String organizationname);
}

View File

@ -0,0 +1,35 @@
/**
*
* 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.opscodeplatform;
import org.jclouds.opscodeplatform.internal.OpscodePlatformContextImpl;
import org.jclouds.rest.RestContext;
import com.google.inject.ImplementedBy;
/**
*
*
* @author Adrian Cole
*
*/
@ImplementedBy(OpscodePlatformContextImpl.class)
public interface OpscodePlatformContext extends RestContext<OpscodePlatformClient, OpscodePlatformAsyncClient> {
}

View File

@ -3,22 +3,17 @@
* 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
* 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
* 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.
* 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.opscodeplatform;
@ -26,25 +21,44 @@ package org.jclouds.opscodeplatform;
import java.util.List;
import java.util.Properties;
import org.jclouds.opscodeplatform.config.OpscodePlatformRestClientModule;
import org.jclouds.rest.RestContextBuilder;
import org.jclouds.ohai.OhaiContextBuilder;
import org.jclouds.opscodeplatform.functions.OpscodePlatformRestClientModule;
import com.google.inject.Injector;
import com.google.inject.Module;
/**
*
* @author Adrian Cole
*/
public class OpscodePlatformContextBuilder extends
RestContextBuilder<OpscodePlatformClient, OpscodePlatformAsyncClient> {
public class OpscodePlatformContextBuilder extends OhaiContextBuilder<OpscodePlatformClient, OpscodePlatformAsyncClient> {
public OpscodePlatformContextBuilder(Properties props) {
super(OpscodePlatformClient.class, OpscodePlatformAsyncClient.class, props);
}
@Override
protected void addClientModule(List<Module> modules) {
modules.add(new OpscodePlatformRestClientModule());
}
}
@Override
public Injector buildInjector() {
addOhaiModuleIfNotPresent();
return super.buildInjector();
}
/**
* {@inheritDoc}
*/
@Override
public OpscodePlatformContextBuilder withModules(Iterable<Module> modules) {
return (OpscodePlatformContextBuilder) super.withModules(modules);
}
@SuppressWarnings("unchecked")
@Override
public OpscodePlatformContext buildContext() {
Injector injector = buildInjector();
return injector.getInstance(OpscodePlatformContext.class);
}
}

View File

@ -16,11 +16,11 @@
* limitations under the License.
* ====================================================================
*/
package org.jclouds.chef.functions;
package org.jclouds.opscodeplatform.config;
import javax.inject.Singleton;
import org.jclouds.chef.domain.Organization;
import org.jclouds.opscodeplatform.domain.Organization;
import com.google.common.base.Function;

View File

@ -16,11 +16,11 @@
* limitations under the License.
* ====================================================================
*/
package org.jclouds.chef.functions;
package org.jclouds.opscodeplatform.config;
import javax.inject.Singleton;
import org.jclouds.chef.domain.User;
import org.jclouds.opscodeplatform.domain.User;
import com.google.common.base.Function;

View File

@ -16,7 +16,7 @@
* limitations under the License.
* ====================================================================
*/
package org.jclouds.chef.domain;
package org.jclouds.opscodeplatform.domain;
import java.security.PrivateKey;

View File

@ -16,7 +16,7 @@
* limitations under the License.
* ====================================================================
*/
package org.jclouds.chef.domain;
package org.jclouds.opscodeplatform.domain;
import java.security.PrivateKey;

View File

@ -39,7 +39,7 @@
* under the License.
* ====================================================================
*/
package org.jclouds.opscodeplatform.config;
package org.jclouds.opscodeplatform.functions;
import java.util.Map;

View File

@ -0,0 +1,53 @@
/**
*
* 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.opscodeplatform.internal;
import java.net.URI;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.lifecycle.Closer;
import org.jclouds.opscodeplatform.OpscodePlatformAsyncClient;
import org.jclouds.opscodeplatform.OpscodePlatformClient;
import org.jclouds.opscodeplatform.OpscodePlatformContext;
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 OpscodePlatformContextImpl extends RestContextImpl<OpscodePlatformClient, OpscodePlatformAsyncClient>
implements OpscodePlatformContext {
@Inject
protected OpscodePlatformContextImpl(Closer closer, Utils utils, Injector injector,
TypeLiteral<OpscodePlatformClient> syncApi, TypeLiteral<OpscodePlatformAsyncClient> asyncApi,
@Provider URI endpoint, @Provider String provider, @Identity String identity, @ApiVersion String apiVersion) {
super(closer, utils, injector, syncApi, asyncApi, endpoint, provider, identity, apiVersion);
}
}

View File

@ -33,10 +33,9 @@ import java.lang.reflect.Method;
import java.util.Properties;
import java.util.concurrent.ExecutionException;
import org.jclouds.chef.domain.Organization;
import org.jclouds.chef.domain.User;
import org.jclouds.chef.filters.SignedHeaderAuth;
import org.jclouds.chef.filters.SignedHeaderAuthTest;
import org.jclouds.chef.functions.ParseKeySetFromJson;
import org.jclouds.concurrent.MoreExecutors;
import org.jclouds.concurrent.config.ConfiguresExecutorService;
import org.jclouds.concurrent.config.ExecutorServiceModule;
@ -46,12 +45,17 @@ import org.jclouds.http.RequiresHttp;
import org.jclouds.http.TransformingHttpCommandExecutorService;
import org.jclouds.http.config.ConfiguresHttpCommandExecutorService;
import org.jclouds.http.functions.ParseJson;
import org.jclouds.http.functions.ReturnTrueIf2xx;
import org.jclouds.logging.config.NullLoggingModule;
import org.jclouds.opscodeplatform.config.OpscodePlatformRestClientModule;
import org.jclouds.opscodeplatform.domain.Organization;
import org.jclouds.opscodeplatform.domain.User;
import org.jclouds.opscodeplatform.functions.OpscodePlatformRestClientModule;
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.ReturnEmptySetOnNotFoundOr404;
import org.jclouds.rest.functions.ReturnFalseOnNotFoundOr404;
import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
import org.jclouds.rest.internal.GeneratedHttpRequest;
import org.jclouds.rest.internal.RestAnnotationProcessor;
@ -74,31 +78,94 @@ import com.google.inject.TypeLiteral;
public class OpscodePlatformAsyncClientTest extends RestClientTest<OpscodePlatformAsyncClient> {
public void testDelegatedOpscodePlatformCallsResolveProperly() throws SecurityException, NoSuchMethodException,
InterruptedException, ExecutionException {
InterruptedException, ExecutionException {
final TransformingHttpCommandExecutorService httpExecutor = createMock(TransformingHttpCommandExecutorService.class);
Injector injector = createContextBuilder(createContextSpec(),
ImmutableSet.of(new HttpExecutorModule(httpExecutor), new NullLoggingModule(), createModule()))
.buildInjector();
ImmutableSet.of(new HttpExecutorModule(httpExecutor), new NullLoggingModule(), createModule()))
.buildInjector();
replay(httpExecutor);
OpscodePlatformAsyncClient caller = injector.getInstance(OpscodePlatformAsyncClient.class);
try {
caller.getChefClientForOrg("goo").listClients().get();
caller.getChefClientForOrganization("goo").listClients().get();
assert false : "shouldn't have connected as this url should be dummy";
} catch (AssertionError e) {
assert e.getMessage().indexOf("[request=GET https://api.opscode.com/organizations/goo/clients HTTP/1.1]") != -1 : e
.getMessage();
.getMessage();
}
}
public void testListUsers() throws SecurityException, NoSuchMethodException, IOException {
Method method = OpscodePlatformAsyncClient.class.getMethod("listUsers");
GeneratedHttpRequest<OpscodePlatformAsyncClient> httpRequest = processor.createRequest(method);
assertRequestLineEquals(httpRequest, "GET https://api.opscode.com/users HTTP/1.1");
assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\n");
assertPayloadEquals(httpRequest, null, null, false);
assertResponseParserClassEquals(method, httpRequest, ParseKeySetFromJson.class);
assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, ReturnEmptySetOnNotFoundOr404.class);
checkFilters(httpRequest);
}
public void testUserExists() throws SecurityException, NoSuchMethodException, IOException {
Method method = OpscodePlatformAsyncClient.class.getMethod("userExists", String.class);
GeneratedHttpRequest<OpscodePlatformAsyncClient> httpRequest = processor.createRequest(method, "user");
assertRequestLineEquals(httpRequest, "HEAD https://api.opscode.com/users/user HTTP/1.1");
assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\n");
assertPayloadEquals(httpRequest, null, null, false);
assertResponseParserClassEquals(method, httpRequest, ReturnTrueIf2xx.class);
assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, ReturnFalseOnNotFoundOr404.class);
checkFilters(httpRequest);
}
public void testOrganizationExists() throws SecurityException, NoSuchMethodException, IOException {
Method method = OpscodePlatformAsyncClient.class.getMethod("organizationExists", String.class);
GeneratedHttpRequest<OpscodePlatformAsyncClient> httpRequest = processor.createRequest(method, "organization");
assertRequestLineEquals(httpRequest, "HEAD https://api.opscode.com/organizations/organization HTTP/1.1");
assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\n");
assertPayloadEquals(httpRequest, null, null, false);
assertResponseParserClassEquals(method, httpRequest, ReturnTrueIf2xx.class);
assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, ReturnFalseOnNotFoundOr404.class);
checkFilters(httpRequest);
}
public void testListOrganizations() throws SecurityException, NoSuchMethodException, IOException {
Method method = OpscodePlatformAsyncClient.class.getMethod("listOrganizations");
GeneratedHttpRequest<OpscodePlatformAsyncClient> httpRequest = processor.createRequest(method);
assertRequestLineEquals(httpRequest, "GET https://api.opscode.com/organizations HTTP/1.1");
assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\n");
assertPayloadEquals(httpRequest, null, null, false);
assertResponseParserClassEquals(method, httpRequest, ParseKeySetFromJson.class);
assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, ReturnEmptySetOnNotFoundOr404.class);
checkFilters(httpRequest);
}
public void testCreateUser() throws SecurityException, NoSuchMethodException, IOException {
Method method = OpscodePlatformAsyncClient.class.getMethod("createUser", User.class);
GeneratedHttpRequest<OpscodePlatformAsyncClient> httpRequest = processor
.createRequest(method, new User("myuser"));
.createRequest(method, new User("myuser"));
assertRequestLineEquals(httpRequest, "POST https://api.opscode.com/users HTTP/1.1");
assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\n");
@ -110,18 +177,15 @@ public class OpscodePlatformAsyncClientTest extends RestClientTest<OpscodePlatfo
assertRequestLineEquals(httpRequest, "POST https://api.opscode.com/users HTTP/1.1");
assertNonPayloadHeadersEqual(httpRequest, new StringBuilder("Accept: application/json").append("\n").append(
"X-Ops-Authorization-1: kfrkDpfgNU26k70R1vl1bEWk0Q0f9Fs/3kxOX7gHd7iNoJq03u7RrcrAOSgL").append("\n")
.append("X-Ops-Authorization-2: ETj5JNeCk18BmFkHMAbCA9hXVo1T4rlHCpbuzAzFlFxUGAT4wj8UoO7V886X").append(
"\n").append(
"X-Ops-Authorization-3: Kf8DvihP6ElthCNuu1xuhN0B4GEmWC9+ut7UMLe0L2T34VzkbCtuInGbf42/").append(
"\n").append(
"X-Ops-Authorization-4: G7iu94/xFOT1gN9cex4pNyTnRCHzob4JVU1usxt/2g5grN2SyYwRS5+4MNLN").append(
"\n").append(
"X-Ops-Authorization-5: WY/iLUPb/9dwtiIQsnUOXqDrs28zNswZulQW4AzYRd7MczJVKU4y4+4XRcB4").append(
"\n").append("X-Ops-Authorization-6: 2+BFLT5o6P6G0D+eCu3zSuaqEJRucPJPaDGWdKIMag==")
.append("\n").append("X-Ops-Content-Hash: yLHOxvgIEtNw5UrZDxslOeMw1gw=").append("\n").append(
"X-Ops-Sign: version=1.0").append("\n").append("X-Ops-Timestamp: timestamp").append("\n")
.append("X-Ops-Userid: user").append("\n").toString());
"X-Ops-Authorization-1: kfrkDpfgNU26k70R1vl1bEWk0Q0f9Fs/3kxOX7gHd7iNoJq03u7RrcrAOSgL").append("\n").append(
"X-Ops-Authorization-2: ETj5JNeCk18BmFkHMAbCA9hXVo1T4rlHCpbuzAzFlFxUGAT4wj8UoO7V886X").append("\n").append(
"X-Ops-Authorization-3: Kf8DvihP6ElthCNuu1xuhN0B4GEmWC9+ut7UMLe0L2T34VzkbCtuInGbf42/").append("\n").append(
"X-Ops-Authorization-4: G7iu94/xFOT1gN9cex4pNyTnRCHzob4JVU1usxt/2g5grN2SyYwRS5+4MNLN").append("\n").append(
"X-Ops-Authorization-5: WY/iLUPb/9dwtiIQsnUOXqDrs28zNswZulQW4AzYRd7MczJVKU4y4+4XRcB4").append("\n").append(
"X-Ops-Authorization-6: 2+BFLT5o6P6G0D+eCu3zSuaqEJRucPJPaDGWdKIMag==").append("\n").append(
"X-Ops-Content-Hash: yLHOxvgIEtNw5UrZDxslOeMw1gw=").append("\n").append("X-Ops-Sign: version=1.0").append(
"\n").append("X-Ops-Timestamp: timestamp").append("\n").append("X-Ops-Userid: user").append("\n")
.toString());
assertPayloadEquals(httpRequest, "{\"username\":\"myuser\"}", "application/json", false);
assertResponseParserClassEquals(method, httpRequest, ParseJson.class);
@ -135,7 +199,7 @@ public class OpscodePlatformAsyncClientTest extends RestClientTest<OpscodePlatfo
public void testUpdateUser() throws SecurityException, NoSuchMethodException, IOException {
Method method = OpscodePlatformAsyncClient.class.getMethod("updateUser", User.class);
GeneratedHttpRequest<OpscodePlatformAsyncClient> httpRequest = processor
.createRequest(method, new User("myuser"));
.createRequest(method, new User("myuser"));
assertRequestLineEquals(httpRequest, "PUT https://api.opscode.com/users/myuser HTTP/1.1");
assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\n");
@ -182,9 +246,9 @@ public class OpscodePlatformAsyncClientTest extends RestClientTest<OpscodePlatfo
}
public void testCreateOrg() throws SecurityException, NoSuchMethodException, IOException {
Method method = OpscodePlatformAsyncClient.class.getMethod("createOrg", Organization.class);
Method method = OpscodePlatformAsyncClient.class.getMethod("createOrganization", Organization.class);
GeneratedHttpRequest<OpscodePlatformAsyncClient> httpRequest = processor.createRequest(method, new Organization(
"myorganization"));
"myorganization"));
assertRequestLineEquals(httpRequest, "POST https://api.opscode.com/organizations HTTP/1.1");
assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\n");
@ -199,9 +263,9 @@ public class OpscodePlatformAsyncClientTest extends RestClientTest<OpscodePlatfo
}
public void testUpdateOrg() throws SecurityException, NoSuchMethodException, IOException {
Method method = OpscodePlatformAsyncClient.class.getMethod("updateOrg", Organization.class);
Method method = OpscodePlatformAsyncClient.class.getMethod("updateOrganization", Organization.class);
GeneratedHttpRequest<OpscodePlatformAsyncClient> httpRequest = processor.createRequest(method, new Organization(
"myorganization"));
"myorganization"));
assertRequestLineEquals(httpRequest, "PUT https://api.opscode.com/organizations/myorganization HTTP/1.1");
assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\n");
@ -216,7 +280,7 @@ public class OpscodePlatformAsyncClientTest extends RestClientTest<OpscodePlatfo
}
public void testGetOrg() throws SecurityException, NoSuchMethodException, IOException {
Method method = OpscodePlatformAsyncClient.class.getMethod("getOrg", String.class);
Method method = OpscodePlatformAsyncClient.class.getMethod("getOrganization", String.class);
GeneratedHttpRequest<OpscodePlatformAsyncClient> httpRequest = processor.createRequest(method, "myorganization");
assertRequestLineEquals(httpRequest, "GET https://api.opscode.com/organizations/myorganization HTTP/1.1");
@ -232,7 +296,7 @@ public class OpscodePlatformAsyncClientTest extends RestClientTest<OpscodePlatfo
}
public void testDeleteOrg() throws SecurityException, NoSuchMethodException, IOException {
Method method = OpscodePlatformAsyncClient.class.getMethod("deleteOrg", String.class);
Method method = OpscodePlatformAsyncClient.class.getMethod("deleteOrganization", String.class);
GeneratedHttpRequest<OpscodePlatformAsyncClient> httpRequest = processor.createRequest(method, "myorganization");
assertRequestLineEquals(httpRequest, "DELETE https://api.opscode.com/organizations/myorganization HTTP/1.1");
@ -293,6 +357,6 @@ public class OpscodePlatformAsyncClientTest extends RestClientTest<OpscodePlatfo
@Override
public ContextSpec<OpscodePlatformClient, OpscodePlatformAsyncClient> createContextSpec() {
return new RestContextFactory().createContextSpec("opscodeplatform", "user", SignedHeaderAuthTest.PRIVATE_KEY,
new Properties());
new Properties());
}
}

View File

@ -24,6 +24,7 @@
package org.jclouds.opscodeplatform;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
import java.io.File;
@ -31,19 +32,26 @@ import java.io.IOException;
import java.util.Properties;
import java.util.Set;
import org.jclouds.chef.domain.User;
import org.jclouds.crypto.Pems;
import org.jclouds.chef.BaseChefClientLiveTest;
import org.jclouds.chef.ChefClient;
import org.jclouds.chef.config.ChefParserModule;
import org.jclouds.http.HttpResponseException;
import org.jclouds.json.Json;
import org.jclouds.json.config.GsonModule;
import org.jclouds.logging.log4j.config.Log4JLoggingModule;
import org.jclouds.rest.AuthorizationException;
import org.jclouds.rest.RestContext;
import org.jclouds.opscodeplatform.domain.Organization;
import org.jclouds.opscodeplatform.domain.User;
import org.jclouds.rest.HttpClient;
import org.jclouds.rest.RestContextFactory;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import com.google.common.base.Charsets;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.io.Files;
import com.google.inject.Guice;
import com.google.inject.Module;
/**
@ -52,122 +60,163 @@ import com.google.inject.Module;
* @author Adrian Cole
*/
@Test(groups = "live", testName = "chef.OpscodePlatformClientLiveTest")
public class OpscodePlatformClientLiveTest {
public class OpscodePlatformClientLiveTest extends BaseChefClientLiveTest {
private RestContext<OpscodePlatformClient, OpscodePlatformAsyncClient> validatorConnection;
private RestContext<OpscodePlatformClient, OpscodePlatformAsyncClient> clientConnection;
private OpscodePlatformContext validatorConnection;
private OpscodePlatformContext clientConnection;
private OpscodePlatformContext adminConnection;
private String orgname;
private String clientKey;
public static final String PREFIX = System.getProperty("user.name") + "-jcloudstest";
private String validator;
@Override
@BeforeClass(groups = { "live" })
public void setupClient() throws IOException {
orgname = checkNotNull(System.getProperty("jclouds.test.identity"), "jclouds.test.identity");
validator = checkNotNull(System.getProperty("jclouds.test.validator"), "jclouds.test.validator");
orgname = Iterables.get(Splitter.on('-').split(validator), 0);
String validatorKey = System.getProperty("jclouds.test.validator.key");
if (validatorKey == null || validatorKey.equals(""))
validatorKey = System.getProperty("user.home") + "/.chef/" + orgname + "-validator.pem";
user = checkNotNull(System.getProperty("jclouds.test.identity"), "jclouds.test.identity");
String keyfile = System.getProperty("jclouds.test.credential");
if (keyfile == null || keyfile.equals(""))
keyfile = "/etc/chef/validation.pem";
validatorConnection = createConnection(orgname + "-validator", Files.toString(new File(keyfile), Charsets.UTF_8));
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 RestContext<OpscodePlatformClient, OpscodePlatformAsyncClient> createConnection(String identity, String key)
throws IOException {
private OpscodePlatformContext createConnection(String identity, String key) throws IOException {
Properties props = new Properties();
return new RestContextFactory().createContext("opscodeplatform", identity, key, ImmutableSet
.<Module> of(new Log4JLoggingModule()), props);
return (OpscodePlatformContext) new RestContextFactory()
.<OpscodePlatformClient, OpscodePlatformAsyncClient> createContext("opscodeplatform", identity, key,
ImmutableSet.<Module> of(new Log4JLoggingModule()), props);
}
@Test
public void testListClientsInOrg() throws Exception {
Set<String> clients = validatorConnection.getApi().getChefClientForOrg(orgname).listClients();
assertNotNull(clients);
assert clients.contains(orgname + "-validator");
@Override
protected HttpClient getHttp() {
return adminConnection.utils().http();
}
@Test(dependsOnMethods = "testListClientsInOrg")
public void testCreateClientInOrg() throws Exception {
validatorConnection.getApi().getChefClientForOrg(orgname).deleteClient(PREFIX);
clientKey = Pems.pem(validatorConnection.getApi().getChefClientForOrg(orgname).createClient(PREFIX)
.getPrivateKey());
assertNotNull(clientKey);
System.out.println(clientKey);
@Override
protected ChefClient getAdminConnection() {
return adminConnection.getApi().getChefClientForOrganization(orgname);
}
@Override
protected ChefClient getValidatorConnection() {
return validatorConnection.getApi().getChefClientForOrganization(orgname);
}
@Override
protected ChefClient getClientConnection() {
return clientConnection.getApi().getChefClientForOrganization(orgname);
}
@Override
protected void recreateClientConnection() throws IOException {
if (clientConnection != null)
clientConnection.close();
clientConnection = createConnection(PREFIX, clientKey);
clientConnection.getApi().getChefClientForOrg(orgname).clientExists(PREFIX);
}
@Test(dependsOnMethods = "testCreateClientInOrg")
public void testGenerateKeyForClientInOrg() throws Exception {
clientKey = Pems.pem(validatorConnection.getApi().getChefClientForOrg(orgname).createClient(PREFIX)
.getPrivateKey());
assertNotNull(clientKey);
clientConnection.close();
clientConnection = createConnection(PREFIX, clientKey);
clientConnection.getApi().getChefClientForOrg(orgname).clientExists(PREFIX);
}
@Test(dependsOnMethods = "testCreateClientInOrg")
public void testClientExistsInOrg() throws Exception {
assertNotNull(validatorConnection.getApi().getChefClientForOrg(orgname).clientExists(PREFIX));
}
@Test(expectedExceptions = AuthorizationException.class)
public void testGetOrgFailsForValidationKey() throws Exception {
validatorConnection.getApi().getOrg(orgname);
}
@Test(dependsOnMethods = "testGenerateKeyForClientInOrg", expectedExceptions = AuthorizationException.class)
public void testGetOrgFailsForClient() throws Exception {
clientConnection.getApi().getOrg(orgname);
}
@Test(enabled = false)
public void testGetUser() throws Exception {
User user = validatorConnection.getApi().getUser(orgname);
assertNotNull(user);
}
@Test(enabled = false)
public void testCreateUser() throws Exception {
// TODO
}
@Test(enabled = false)
public void testUpdateUser() throws Exception {
// TODO
}
@Test(enabled = false)
public void testDeleteUser() throws Exception {
// TODO
}
@Test(enabled = false)
public void testCreateOrg() throws Exception {
// TODO
}
@Test(enabled = false)
public void testUpdateOrg() throws Exception {
// TODO
}
@Test(enabled = false)
public void testDeleteOrg() throws Exception {
// TODO
}
@Test(dependsOnMethods = "testGenerateKeyForClientInOrg")
public void testListCookbooksInOrg() throws Exception {
System.err.println(clientConnection.getApi().getChefClientForOrg(orgname).listCookbooks());
}
@AfterClass(groups = { "live" })
public void teardownClient() throws IOException {
@Override
protected void closeContexts() {
if (orgUser != null)
adminConnection.getApi().deleteUser(PREFIX);
if (org != null)
adminConnection.getApi().deleteOrganization(PREFIX);
if (clientConnection != null)
clientConnection.close();
if (validatorConnection != null)
validatorConnection.close();
if (adminConnection != null)
adminConnection.close();
}
private String orgname;
private Organization org;
private User orgUser;
// http://tickets.corp.opscode.com/browse/PL-524
@Test(expectedExceptions = HttpResponseException.class)
public void testListOrganizations() throws Exception {
Set<String> orgs = adminConnection.getApi().listOrganizations();
assertNotNull(orgs);
}
// http://tickets.corp.opscode.com/browse/PL-524
@Test(expectedExceptions = HttpResponseException.class)
public void testCreateOrganization() throws Exception {
adminConnection.getApi().deleteOrganization(PREFIX);
adminConnection.getApi().createOrganization(new Organization(PREFIX));
org = adminConnection.getApi().getOrganization(PREFIX);
assertNotNull(org);
assertEquals(org.getName(), PREFIX);
assertEquals(org.getClientname(), PREFIX + "-validator");
}
// http://tickets.corp.opscode.com/browse/PL-524
@Test(expectedExceptions = HttpResponseException.class)
public void testOrganizationExists() throws Exception {
assertNotNull(adminConnection.getApi().organizationExists(orgname));
}
@Test(enabled = false, dependsOnMethods = "testCreateOrganization")
public void testUpdateOrganization() throws Exception {
Organization org = adminConnection.getApi().getOrganization(PREFIX);
adminConnection.getApi().updateOrganization(org);
}
// http://tickets.corp.opscode.com/browse/PL-524
@Test(expectedExceptions = HttpResponseException.class)
public void testGetOrganization() throws Exception {
adminConnection.getApi().getOrganization(orgname);
}
// http://tickets.corp.opscode.com/browse/PL-524
@Test(expectedExceptions = HttpResponseException.class)
public void testListUsers() throws Exception {
Set<String> orgs = adminConnection.getApi().listUsers();
assertNotNull(orgs);
}
// http://tickets.corp.opscode.com/browse/PL-524
@Test(expectedExceptions = HttpResponseException.class)
public void testCreateUser() throws Exception {
adminConnection.getApi().deleteUser(PREFIX);
adminConnection.getApi().createUser(new User(PREFIX));
orgUser = adminConnection.getApi().getUser(PREFIX);
assertNotNull(orgUser);
assertEquals(orgUser.getUsername(), PREFIX);
assertNotNull(orgUser.getPrivateKey());
}
// http://tickets.corp.opscode.com/browse/PL-524
@Test(expectedExceptions = HttpResponseException.class)
public void testUserExists() throws Exception {
assertNotNull(adminConnection.getApi().userExists(user));
}
// http://tickets.corp.opscode.com/browse/PL-524
@Test(expectedExceptions = HttpResponseException.class)
public void testGetUser() throws Exception {
adminConnection.getApi().getUser(user);
}
@Test(enabled = false, dependsOnMethods = "testCreateUser")
public void testUpdateUser() throws Exception {
User user = adminConnection.getApi().getUser(PREFIX);
adminConnection.getApi().updateUser(user);
}
@Test(expectedExceptions = HttpResponseException.class)
public void testGetOrganizationFailsForValidationKey() throws Exception {
validatorConnection.getApi().getOrganization(orgname);
}
@Test(dependsOnMethods = "testGenerateKeyForClient", expectedExceptions = HttpResponseException.class)
public void testGetOrganizationFailsForClient() throws Exception {
clientConnection.getApi().getOrganization(orgname);
}
}

View File

@ -16,18 +16,18 @@
* limitations under the License.
* ====================================================================
*/
package org.jclouds.chef.functions;
package org.jclouds.opscodeplatform.functions;
import static org.testng.Assert.assertEquals;
import java.io.IOException;
import org.jclouds.chef.config.ChefParserModule;
import org.jclouds.chef.domain.Organization;
import org.jclouds.http.HttpResponse;
import org.jclouds.http.functions.ParseJson;
import org.jclouds.io.Payloads;
import org.jclouds.json.config.GsonModule;
import org.jclouds.opscodeplatform.domain.Organization;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;

View File

@ -1,15 +1,15 @@
package org.jclouds.chef.functions;
package org.jclouds.opscodeplatform.functions;
import static org.testng.Assert.assertEquals;
import java.io.IOException;
import org.jclouds.chef.config.ChefParserModule;
import org.jclouds.chef.domain.User;
import org.jclouds.http.HttpResponse;
import org.jclouds.http.functions.ParseJson;
import org.jclouds.io.Payloads;
import org.jclouds.json.config.GsonModule;
import org.jclouds.opscodeplatform.domain.User;
import org.jclouds.util.Utils;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;