Issue 191: updated to version 0.9 for cookbook commands

This commit is contained in:
Adrian Cole 2010-06-28 19:13:49 -07:00
parent 360af6f42c
commit 7c719f206f
16 changed files with 608 additions and 763 deletions

View File

@ -23,12 +23,10 @@
*/ */
package org.jclouds.chef; package org.jclouds.chef;
import java.io.File;
import java.util.Set; import java.util.Set;
import javax.ws.rs.Consumes; import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE; import javax.ws.rs.DELETE;
import javax.ws.rs.FormParam;
import javax.ws.rs.GET; import javax.ws.rs.GET;
import javax.ws.rs.HEAD; import javax.ws.rs.HEAD;
import javax.ws.rs.POST; import javax.ws.rs.POST;
@ -40,17 +38,20 @@ import javax.ws.rs.core.MediaType;
import org.jclouds.chef.binders.BindChecksumsToJsonPayload; import org.jclouds.chef.binders.BindChecksumsToJsonPayload;
import org.jclouds.chef.binders.BindClientnameToJsonPayload; import org.jclouds.chef.binders.BindClientnameToJsonPayload;
import org.jclouds.chef.binders.BindGenerateKeyForClientToJsonPayload; import org.jclouds.chef.binders.BindGenerateKeyForClientToJsonPayload;
import org.jclouds.chef.domain.Cookbook;
import org.jclouds.chef.domain.Sandbox; import org.jclouds.chef.domain.Sandbox;
import org.jclouds.chef.filters.SignedHeaderAuth; import org.jclouds.chef.filters.SignedHeaderAuth;
import org.jclouds.chef.functions.ParseCookbookFromJson;
import org.jclouds.chef.functions.ParseKeyFromJson; import org.jclouds.chef.functions.ParseKeyFromJson;
import org.jclouds.chef.functions.ParseKeySetFromJson; import org.jclouds.chef.functions.ParseKeySetFromJson;
import org.jclouds.chef.functions.ParseSandboxFromJson; import org.jclouds.chef.functions.ParseSandboxFromJson;
import org.jclouds.chef.functions.ParseValueSetFromJson;
import org.jclouds.rest.annotations.BinderParam; import org.jclouds.rest.annotations.BinderParam;
import org.jclouds.rest.annotations.ExceptionParser; import org.jclouds.rest.annotations.ExceptionParser;
import org.jclouds.rest.annotations.Headers; import org.jclouds.rest.annotations.Headers;
import org.jclouds.rest.annotations.PartParam;
import org.jclouds.rest.annotations.RequestFilters; import org.jclouds.rest.annotations.RequestFilters;
import org.jclouds.rest.annotations.ResponseParser; import org.jclouds.rest.annotations.ResponseParser;
import org.jclouds.rest.binders.BindToJsonPayload;
import org.jclouds.rest.functions.ReturnFalseOnNotFoundOr404; import org.jclouds.rest.functions.ReturnFalseOnNotFoundOr404;
import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404; import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
import org.jclouds.rest.functions.ReturnVoidOnNotFoundOr404; import org.jclouds.rest.functions.ReturnVoidOnNotFoundOr404;
@ -78,7 +79,7 @@ public interface ChefAsyncClient {
@Path("sandboxes") @Path("sandboxes")
@ResponseParser(ParseSandboxFromJson.class) @ResponseParser(ParseSandboxFromJson.class)
ListenableFuture<Sandbox> getUploadUrisForContent( ListenableFuture<Sandbox> getUploadUrisForContent(
@BinderParam(BindChecksumsToJsonPayload.class) Set<String> checksums); @BinderParam(BindChecksumsToJsonPayload.class) Set<String> checksums);
/** /**
* @see ChefCookbooks#listCookbooks * @see ChefCookbooks#listCookbooks
@ -89,55 +90,45 @@ public interface ChefAsyncClient {
ListenableFuture<Set<String>> listCookbooks(); ListenableFuture<Set<String>> listCookbooks();
/** /**
* @see ChefClient#createCookbook(String,File) * @see ChefClient#updateCookbook
*/
@POST
@Path("cookbooks")
ListenableFuture<Void> createCookbook(@FormParam("name") String cookbookName,
@PartParam(name = "file", contentType = MediaType.APPLICATION_OCTET_STREAM) File content);
/**
* @see ChefClient#createCookbook(String,byte[])
*/
@POST
@Path("cookbooks")
ListenableFuture<Void> createCookbook(
@FormParam("name") String cookbookName,
@PartParam(name = "file", contentType = MediaType.APPLICATION_OCTET_STREAM, filename = "{name}.tar.gz") byte[] content);
/**
* @see ChefClient#updateCookbook(String,File)
*/ */
@PUT @PUT
@Path("cookbooks/{cookbookname}/_content") @Path("cookbooks/{cookbookname}/{version}")
ListenableFuture<Void> updateCookbook( ListenableFuture<Void> updateCookbook(
@PathParam("cookbookname") @FormParam("name") String cookbookName, @PathParam("cookbookname") String cookbookName,
@PartParam(name = "file", contentType = MediaType.APPLICATION_OCTET_STREAM) File content); @PathParam("version") String version,
@BinderParam(BindToJsonPayload.class) Cookbook cookbook);
/** /**
* @see ChefClient#updateCookbook(String,byte[]) * @see ChefCookbook#deleteCookbook(String)
*/
@PUT
@Path("cookbooks/{cookbookname}/_content")
ListenableFuture<Void> updateCookbook(
@PathParam("cookbookname") @FormParam("name") String cookbookName,
@PartParam(name = "file", contentType = MediaType.APPLICATION_OCTET_STREAM, filename = "{name}.tar.gz") byte[] content);
/**
* @see ChefCookbook#deleteCookbook
*/ */
@DELETE @DELETE
@Path("cookbooks/{cookbookname}") @Path("cookbooks/{cookbookname}/{version}")
@ExceptionParser(ReturnVoidOnNotFoundOr404.class) @ExceptionParser(ReturnVoidOnNotFoundOr404.class)
ListenableFuture<Void> deleteCookbook(@PathParam("cookbookname") String cookbookName); ListenableFuture<Void> deleteCookbook(
@PathParam("cookbookname") String cookbookName,
@PathParam("version") String version);
/**
* @see ChefCookbook#getVersionsOfCookbook
*/
@GET
@Path("cookbooks/{cookbookname}")
@ResponseParser(ParseValueSetFromJson.class)
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
ListenableFuture<Set<String>> getVersionsOfCookbook(
@PathParam("cookbookname") String cookbookName);
/** /**
* @see ChefCookbook#getCookbook * @see ChefCookbook#getCookbook
*/ */
@GET @GET
@Path("cookbooks/{cookbookname}") @Path("cookbooks/{cookbookname}/{version}")
@ResponseParser(ParseCookbookFromJson.class)
@ExceptionParser(ReturnNullOnNotFoundOr404.class) @ExceptionParser(ReturnNullOnNotFoundOr404.class)
ListenableFuture<String> getCookbook(@PathParam("cookbookname") String cookbookName); ListenableFuture<Cookbook> getCookbook(
@PathParam("cookbookname") String cookbookName,
@PathParam("version") String version);
/** /**
* @see ChefClient#createClient * @see ChefClient#createClient
@ -146,7 +137,7 @@ public interface ChefAsyncClient {
@Path("clients") @Path("clients")
@ResponseParser(ParseKeyFromJson.class) @ResponseParser(ParseKeyFromJson.class)
ListenableFuture<String> createClient( ListenableFuture<String> createClient(
@BinderParam(BindClientnameToJsonPayload.class) String clientname); @BinderParam(BindClientnameToJsonPayload.class) String clientname);
/** /**
* @see ChefClient#generateKeyForClient * @see ChefClient#generateKeyForClient
@ -155,7 +146,7 @@ public interface ChefAsyncClient {
@Path("clients/{clientname}") @Path("clients/{clientname}")
@ResponseParser(ParseKeyFromJson.class) @ResponseParser(ParseKeyFromJson.class)
ListenableFuture<String> generateKeyForClient( ListenableFuture<String> generateKeyForClient(
@PathParam("clientname") @BinderParam(BindGenerateKeyForClientToJsonPayload.class) String clientname); @PathParam("clientname") @BinderParam(BindGenerateKeyForClientToJsonPayload.class) String clientname);
/** /**
* @see ChefClient#clientExists * @see ChefClient#clientExists
@ -163,7 +154,8 @@ public interface ChefAsyncClient {
@HEAD @HEAD
@Path("clients/{clientname}") @Path("clients/{clientname}")
@ExceptionParser(ReturnFalseOnNotFoundOr404.class) @ExceptionParser(ReturnFalseOnNotFoundOr404.class)
ListenableFuture<Boolean> clientExists(@PathParam("clientname") String clientname); ListenableFuture<Boolean> clientExists(
@PathParam("clientname") String clientname);
/** /**
* @see ChefClient#getClient * @see ChefClient#getClient
@ -171,7 +163,8 @@ public interface ChefAsyncClient {
@GET @GET
@Path("clients/{clientname}") @Path("clients/{clientname}")
@ExceptionParser(ReturnNullOnNotFoundOr404.class) @ExceptionParser(ReturnNullOnNotFoundOr404.class)
ListenableFuture<Boolean> getClient(@PathParam("clientname") String clientname); ListenableFuture<Boolean> getClient(
@PathParam("clientname") String clientname);
/** /**
* @see ChefClient#deleteClient * @see ChefClient#deleteClient
@ -179,7 +172,8 @@ public interface ChefAsyncClient {
@DELETE @DELETE
@Path("clients/{clientname}") @Path("clients/{clientname}")
@ExceptionParser(ReturnNullOnNotFoundOr404.class) @ExceptionParser(ReturnNullOnNotFoundOr404.class)
ListenableFuture<String> deleteClient(@PathParam("clientname") String clientname); ListenableFuture<String> deleteClient(
@PathParam("clientname") String clientname);
/** /**
* @see ChefClient#listClients * @see ChefClient#listClients

View File

@ -41,15 +41,14 @@
*/ */
package org.jclouds.chef; package org.jclouds.chef;
import java.io.File;
import java.util.Set; import java.util.Set;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import org.jclouds.chef.domain.Cookbook;
import org.jclouds.chef.domain.Sandbox; import org.jclouds.chef.domain.Sandbox;
import org.jclouds.concurrent.Timeout; import org.jclouds.concurrent.Timeout;
import org.jclouds.http.HttpResponseException; import org.jclouds.http.HttpResponseException;
import org.jclouds.rest.AuthorizationException; import org.jclouds.rest.AuthorizationException;
import org.jclouds.rest.ResourceNotFoundException;
/** /**
* Provides synchronous access to Chef. * Provides synchronous access to Chef.
@ -76,7 +75,8 @@ public interface ChefClient {
Set<String> listCookbooks(); Set<String> listCookbooks();
/** /**
* Creates (uploads) a cookbook with the name present from the tar/gz file. * Creates or updates (uploads) a cookbook with the name present from the
* tar/gz file.
* *
* @param cookbookName * @param cookbookName
* matches the root directory path of the archive * matches the root directory path of the archive
@ -91,39 +91,7 @@ public interface ChefClient {
* "409 Conflict" if the cookbook already exists * "409 Conflict" if the cookbook already exists
*/ */
@Timeout(duration = 10, timeUnit = TimeUnit.MINUTES) @Timeout(duration = 10, timeUnit = TimeUnit.MINUTES)
void createCookbook(String cookbookName, File tgzArchive); void updateCookbook(String cookbookName, String version, Cookbook cookbook);
/**
* like {@link #createCookbook(String, File)}, except that a byte stream is
* allowed.
*/
@Timeout(duration = 10, timeUnit = TimeUnit.MINUTES)
void createCookbook(String cookbookName, byte[] tgzArchive);
/**
* Overrides (uploads) a cookbook with the content in the tar/gz file.
*
* @param cookbookName
* matches the root directory path of the archive
* @param tgzArchive
* tar gz archive, with a base path of {@code cookbookName}
* <p/>
* "401 Unauthorized" if the caller is not a recognized user.
* <p/>
* "403 Forbidden" if you do not have permission to update
* cookbooks.
* @throws ResourceNotFoundException
* if the cookbook does not exist
*/
@Timeout(duration = 10, timeUnit = TimeUnit.MINUTES)
void updateCookbook(String cookbookName, File tgzArchive);
/**
* like {@link #updateCookbook(String, File)}, except that a byte stream is
* allowed.
*/
@Timeout(duration = 10, timeUnit = TimeUnit.MINUTES)
void updateCookbook(String cookbookName, byte[] tgzArchive);
/** /**
* deletes an existing cookbook. * deletes an existing cookbook.
@ -136,7 +104,20 @@ public interface ChefClient {
* "403 Forbidden" if you do not have Delete rights on the * "403 Forbidden" if you do not have Delete rights on the
* cookbook. * cookbook.
*/ */
String deleteCookbook(String cookbookName); String deleteCookbook(String cookbookName, String version);
/**
*
* @return the versions of a cookbook or null, if not found
*
* @throws AuthorizationException
* <p/>
* "401 Unauthorized" if the caller is not a recognized user.
* <p/>
* "403 Forbidden" if the caller is not authorized to view the
* cookbook.
*/
Set<String> getVersionsOfCookbook(String cookbookName);
/** /**
* Returns a description of the cookbook, with links to all of its component * Returns a description of the cookbook, with links to all of its component
@ -151,7 +132,7 @@ public interface ChefClient {
* "403 Forbidden" if the caller is not authorized to view the * "403 Forbidden" if the caller is not authorized to view the
* cookbook. * cookbook.
*/ */
String getCookbook(String cookbookName); Cookbook getCookbook(String cookbookName, String version);
/** /**
* creates a new client * creates a new client

View File

@ -39,7 +39,7 @@ public class Attribute {
private String required; private String required;
private boolean calculated; private boolean calculated;
private Set<String> choice; private List<String> choice = Lists.newArrayList();
@SerializedName("default") @SerializedName("default")
private String defaultValue; private String defaultValue;
private String type; private String type;
@ -72,7 +72,7 @@ public class Attribute {
return calculated; return calculated;
} }
public Set<String> getChoice() { public List<String> getChoice() {
return choice; return choice;
} }
@ -170,5 +170,5 @@ public class Attribute {
+ ", displayName=" + displayName + ", recipes=" + recipes + ", displayName=" + displayName + ", recipes=" + recipes
+ ", required=" + required + ", type=" + type + "]"; + ", required=" + required + ", type=" + type + "]";
} }
} }

View File

@ -34,17 +34,16 @@ public class Metadata {
private String license; private String license;
private String maintainer; private String maintainer;
private Map<String, String> suggestions = Maps.newLinkedHashMap(); private Map<String, String> suggestions = Maps.newLinkedHashMap();
private Map<String, String> dependencies = Maps.newLinkedHashMap(); private Map<String, Set<String>> dependencies = Maps.newLinkedHashMap();
@SerializedName("maintainer_email") @SerializedName("maintainer_email")
private String maintainerEmail; private String maintainerEmail;
private Map<String, String> conflicting = Maps.newLinkedHashMap(); private Map<String, Set<String>> conflicting = Maps.newLinkedHashMap();
private String description; private String description;
private Map<String, String> providing = Maps.newLinkedHashMap(); private Map<String, Set<String>> providing = Maps.newLinkedHashMap();
private Map<String, Map<String, Set<String>>> platforms = Maps private Map<String, Set<String>> platforms = Maps.newLinkedHashMap();
.newLinkedHashMap();
private String version; private String version;
private Map<String, Map<String, String>> recipes = Maps.newLinkedHashMap(); private Map<String, String> recipes = Maps.newLinkedHashMap();
private Map<String, String> replacing = Maps.newLinkedHashMap(); private Map<String, Set<String>> replacing = Maps.newLinkedHashMap();
private String name; private String name;
private Map<String, String> groupings = Maps.newLinkedHashMap(); private Map<String, String> groupings = Maps.newLinkedHashMap();
@SerializedName("long_description") @SerializedName("long_description")
@ -53,13 +52,13 @@ public class Metadata {
private Map<String, String> recommendations = Maps.newLinkedHashMap(); private Map<String, String> recommendations = Maps.newLinkedHashMap();
public Metadata(String license, String maintainer, public Metadata(String license, String maintainer,
Map<String, String> suggestions, Map<String, String> dependencies, Map<String, String> suggestions,
String maintainerEmail, Map<String, String> conflicting, Map<String, Set<String>> dependencies, String maintainerEmail,
String description, Map<String, String> providing, Map<String, Set<String>> conflicting, String description,
Map<String, Map<String, Set<String>>> platforms, String version, Map<String, Set<String>> providing,
Map<String, Map<String, String>> recipes, Map<String, Set<String>> platforms, String version,
Map<String, String> replacing, String name, Map<String, String> recipes, Map<String, Set<String>> replacing,
Map<String, String> groupings, String longDescription, String name, Map<String, String> groupings, String longDescription,
Map<String, Attribute> attributes, Map<String, String> recommendations) { Map<String, Attribute> attributes, Map<String, String> recommendations) {
this.license = license; this.license = license;
this.maintainer = maintainer; this.maintainer = maintainer;
@ -95,7 +94,7 @@ public class Metadata {
return suggestions; return suggestions;
} }
public Map<String, String> getDependencies() { public Map<String, Set<String>> getDependencies() {
return dependencies; return dependencies;
} }
@ -103,7 +102,7 @@ public class Metadata {
return maintainerEmail; return maintainerEmail;
} }
public Map<String, String> getConflicting() { public Map<String, Set<String>> getConflicting() {
return conflicting; return conflicting;
} }
@ -111,11 +110,11 @@ public class Metadata {
return description; return description;
} }
public Map<String, String> getProviding() { public Map<String, Set<String>> getProviding() {
return providing; return providing;
} }
public Map<String, Map<String, Set<String>>> getPlatforms() { public Map<String, Set<String>> getPlatforms() {
return platforms; return platforms;
} }
@ -123,11 +122,11 @@ public class Metadata {
return version; return version;
} }
public Map<String, Map<String, String>> getRecipes() { public Map<String, String> getRecipes() {
return recipes; return recipes;
} }
public Map<String, String> getReplacing() { public Map<String, Set<String>> getReplacing() {
return replacing; return replacing;
} }
@ -297,5 +296,5 @@ public class Metadata {
+ ", replacing=" + replacing + ", suggestions=" + suggestions + ", replacing=" + replacing + ", suggestions=" + suggestions
+ ", version=" + version + "]"; + ", version=" + version + "]";
} }
} }

View File

@ -18,6 +18,8 @@
*/ */
package org.jclouds.chef.domain; package org.jclouds.chef.domain;
import java.net.URI;
/** /**
* Cookbook object. * Cookbook object.
* *
@ -26,12 +28,15 @@ package org.jclouds.chef.domain;
public class Resource { public class Resource {
private String name; private String name;
private URI url;
private String checksum; private String checksum;
private String path; private String path;
private String specificity; private String specificity;
public Resource(String name, String checksum, String path, String specificity) { public Resource(String name, URI url, String checksum, String path,
String specificity) {
this.name = name; this.name = name;
this.url = url;
this.checksum = checksum; this.checksum = checksum;
this.path = path; this.path = path;
this.specificity = specificity; this.specificity = specificity;
@ -44,6 +49,9 @@ public class Resource {
return name; return name;
} }
public URI getUrl() {
return url;
}
public String getChecksum() { public String getChecksum() {
return checksum; return checksum;
} }
@ -65,6 +73,7 @@ public class Resource {
result = prime * result + ((path == null) ? 0 : path.hashCode()); result = prime * result + ((path == null) ? 0 : path.hashCode());
result = prime * result result = prime * result
+ ((specificity == null) ? 0 : specificity.hashCode()); + ((specificity == null) ? 0 : specificity.hashCode());
result = prime * result + ((url == null) ? 0 : url.hashCode());
return result; return result;
} }
@ -97,14 +106,18 @@ public class Resource {
return false; return false;
} else if (!specificity.equals(other.specificity)) } else if (!specificity.equals(other.specificity))
return false; return false;
if (url == null) {
if (other.url != null)
return false;
} else if (!url.equals(other.url))
return false;
return true; return true;
} }
@Override @Override
public String toString() { public String toString() {
return "Resource [checksum=" + checksum + ", name=" + name + ", path=" return "Resource [checksum=" + checksum + ", name=" + name + ", path="
+ path + ", specificity=" + specificity + "]"; + path + ", specificity=" + specificity + ", url=" + url + "]";
} }
} }

View File

@ -0,0 +1,59 @@
/**
*
* 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.functions;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.chef.domain.Cookbook;
import org.jclouds.http.functions.ParseJson;
import com.google.gson.Gson;
/**
*
*
* @author Adrian Cole
*/
@Singleton
public class ParseCookbookFromJson extends ParseJson<Cookbook> {
@Inject
public ParseCookbookFromJson(Gson gson) {
super(gson);
}
@Override
protected Cookbook apply(InputStream stream) {
try {
return gson.fromJson(new InputStreamReader(stream, "UTF-8"),
Cookbook.class);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("jclouds requires UTF-8 encoding", e);
}
}
}

View File

@ -0,0 +1,83 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ====================================================================
*/
/**
*
* Copyright (C) 2009 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.functions;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Type;
import java.util.Map;
import java.util.Set;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.http.functions.ParseJson;
import com.google.common.collect.Iterables;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
/**
* @author Adrian Cole
*/
@Singleton
public class ParseValueSetFromJson extends ParseJson<Set<String>> {
@Inject
public ParseValueSetFromJson(Gson gson) {
super(gson);
}
@SuppressWarnings("unchecked")
@Override
protected Set<String> apply(InputStream stream) {
try {
Type map = new TypeToken<Map<String, Set<String>>>() {
}.getType();
return Iterables.get(
((Map<String, Set<String>>) gson.fromJson(new InputStreamReader(
stream, "UTF-8"), map)).entrySet(), 0).getValue();
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("jclouds requires UTF-8 encoding", e);
}
}
}

View File

@ -25,15 +25,16 @@ package org.jclouds.chef;
import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertEquals;
import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.Properties; import java.util.Properties;
import java.util.Set; import java.util.Set;
import org.jclouds.chef.config.ChefRestClientModule; import org.jclouds.chef.config.ChefRestClientModule;
import org.jclouds.chef.domain.Cookbook;
import org.jclouds.chef.filters.SignedHeaderAuth; import org.jclouds.chef.filters.SignedHeaderAuth;
import org.jclouds.chef.filters.SignedHeaderAuthTest; import org.jclouds.chef.filters.SignedHeaderAuthTest;
import org.jclouds.chef.functions.ParseCookbookFromJson;
import org.jclouds.chef.functions.ParseKeyFromJson; import org.jclouds.chef.functions.ParseKeyFromJson;
import org.jclouds.chef.functions.ParseKeySetFromJson; import org.jclouds.chef.functions.ParseKeySetFromJson;
import org.jclouds.chef.functions.ParseSandboxFromJson; import org.jclouds.chef.functions.ParseSandboxFromJson;
@ -55,7 +56,6 @@ import org.testng.annotations.Test;
import com.google.common.base.Supplier; import com.google.common.base.Supplier;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.common.io.Files;
import com.google.inject.Module; import com.google.inject.Module;
import com.google.inject.TypeLiteral; import com.google.inject.TypeLiteral;
@ -67,22 +67,27 @@ import com.google.inject.TypeLiteral;
@Test(groups = "unit", testName = "chef.ChefAsyncClientTest") @Test(groups = "unit", testName = "chef.ChefAsyncClientTest")
public class ChefAsyncClientTest extends RestClientTest<ChefAsyncClient> { public class ChefAsyncClientTest extends RestClientTest<ChefAsyncClient> {
public void testGetUploadUrisForContent() throws SecurityException, NoSuchMethodException, public void testGetUploadUrisForContent() throws SecurityException,
IOException { NoSuchMethodException, IOException {
Method method = ChefAsyncClient.class.getMethod("getUploadUrisForContent", Set.class); Method method = ChefAsyncClient.class.getMethod(
GeneratedHttpRequest<ChefAsyncClient> httpRequest = processor.createRequest(method, "getUploadUrisForContent", Set.class);
ImmutableSet.of("0189e76ccc476701d6b374e5a1a27347", GeneratedHttpRequest<ChefAsyncClient> httpRequest = processor
"0c5ecd7788cf4f6c7de2a57193897a6c", "1dda05ed139664f1f89b9dec482b77c0")); .createRequest(method, ImmutableSet.of(
"0189e76ccc476701d6b374e5a1a27347",
"0c5ecd7788cf4f6c7de2a57193897a6c",
"1dda05ed139664f1f89b9dec482b77c0"));
assertRequestLineEquals(httpRequest, "POST http://localhost:4000/sandboxes HTTP/1.1"); assertRequestLineEquals(httpRequest,
"POST http://localhost:4000/sandboxes HTTP/1.1");
assertHeadersEqual( assertHeadersEqual(
httpRequest, httpRequest,
"Accept: application/json\nContent-Length: 135\nContent-Type: application/json\nX-Chef-Version: 0.9.0\n"); "Accept: application/json\nContent-Length: 135\nContent-Type: application/json\nX-Chef-Version: 0.9.0\n");
assertPayloadEquals( assertPayloadEquals(
httpRequest, httpRequest,
"{\"checksums\":{\"0189e76ccc476701d6b374e5a1a27347\":null,\"0c5ecd7788cf4f6c7de2a57193897a6c\":null,\"1dda05ed139664f1f89b9dec482b77c0\":null}}"); "{\"checksums\":{\"0189e76ccc476701d6b374e5a1a27347\":null,\"0c5ecd7788cf4f6c7de2a57193897a6c\":null,\"1dda05ed139664f1f89b9dec482b77c0\":null}}");
assertResponseParserClassEquals(method, httpRequest, ParseSandboxFromJson.class); assertResponseParserClassEquals(method, httpRequest,
ParseSandboxFromJson.class);
assertSaxResponseParserClassEquals(method, null); assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, null); assertExceptionParserClassEquals(method, null);
@ -90,15 +95,20 @@ public class ChefAsyncClientTest extends RestClientTest<ChefAsyncClient> {
} }
public void testGetCookbook() throws SecurityException, NoSuchMethodException, IOException { public void testGetCookbook() throws SecurityException,
Method method = ChefAsyncClient.class.getMethod("getCookbook", String.class); NoSuchMethodException, IOException {
GeneratedHttpRequest<ChefAsyncClient> httpRequest = processor.createRequest(method, Method method = ChefAsyncClient.class.getMethod("getCookbook",
"cookbook"); String.class, String.class);
assertRequestLineEquals(httpRequest, "GET http://localhost:4000/cookbooks/cookbook HTTP/1.1"); GeneratedHttpRequest<ChefAsyncClient> httpRequest = processor
assertHeadersEqual(httpRequest, "Accept: application/json\nX-Chef-Version: 0.9.0\n"); .createRequest(method, "cookbook", "1.0.0");
assertRequestLineEquals(httpRequest,
"GET http://localhost:4000/cookbooks/cookbook/1.0.0 HTTP/1.1");
assertHeadersEqual(httpRequest,
"Accept: application/json\nX-Chef-Version: 0.9.0\n");
assertPayloadEquals(httpRequest, null); assertPayloadEquals(httpRequest, null);
assertResponseParserClassEquals(method, httpRequest, ReturnStringIf200.class); assertResponseParserClassEquals(method, httpRequest,
ParseCookbookFromJson.class);
assertSaxResponseParserClassEquals(method, null); assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, ReturnNullOnNotFoundOr404.class); assertExceptionParserClassEquals(method, ReturnNullOnNotFoundOr404.class);
@ -106,16 +116,20 @@ public class ChefAsyncClientTest extends RestClientTest<ChefAsyncClient> {
} }
public void testDeleteCookbook() throws SecurityException, NoSuchMethodException, IOException { public void testDeleteCookbook() throws SecurityException,
Method method = ChefAsyncClient.class.getMethod("deleteCookbook", String.class); NoSuchMethodException, IOException {
GeneratedHttpRequest<ChefAsyncClient> httpRequest = processor.createRequest(method, Method method = ChefAsyncClient.class.getMethod("deleteCookbook",
"cookbook"); String.class, String.class);
GeneratedHttpRequest<ChefAsyncClient> httpRequest = processor
.createRequest(method, "cookbook", "1.0.0");
assertRequestLineEquals(httpRequest, assertRequestLineEquals(httpRequest,
"DELETE http://localhost:4000/cookbooks/cookbook HTTP/1.1"); "DELETE http://localhost:4000/cookbooks/cookbook/1.0.0 HTTP/1.1");
assertHeadersEqual(httpRequest, "Accept: application/json\nX-Chef-Version: 0.9.0\n"); assertHeadersEqual(httpRequest,
"Accept: application/json\nX-Chef-Version: 0.9.0\n");
assertPayloadEquals(httpRequest, null); assertPayloadEquals(httpRequest, null);
assertResponseParserClassEquals(method, httpRequest, CloseContentAndReturn.class); assertResponseParserClassEquals(method, httpRequest,
CloseContentAndReturn.class);
assertSaxResponseParserClassEquals(method, null); assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, ReturnVoidOnNotFoundOr404.class); assertExceptionParserClassEquals(method, ReturnVoidOnNotFoundOr404.class);
@ -123,79 +137,24 @@ public class ChefAsyncClientTest extends RestClientTest<ChefAsyncClient> {
} }
private static final String COOOKBOOK_BODY = public void testUpdateCookbook() throws SecurityException,
NoSuchMethodException, IOException {
"----JCLOUDS--\r\n" + "Content-Disposition: form-data; name=\"name\"\r\n\r\n" + "cookbook\r\n" Method method = ChefAsyncClient.class.getMethod("updateCookbook",
+ "----JCLOUDS--\r\n" String.class, String.class, Cookbook.class);
+ "Content-Disposition: form-data; name=\"file\"; filename=\"cookbook.tar.gz\"\r\n" GeneratedHttpRequest<ChefAsyncClient> httpRequest = processor
+ "Content-Type: application/octet-stream\r\n\r\n\r\n" + "----JCLOUDS----\r\n"; .createRequest(method, "cookbook", "1.0.1", new Cookbook());
public void testCreateCookbookFile() throws SecurityException, NoSuchMethodException,
IOException {
Method method = ChefAsyncClient.class.getMethod("createCookbook", String.class, File.class);
File file = File.createTempFile("jclouds-chef=test", ".tar.gz");
file.deleteOnExit();
Files.write("".getBytes(), file);
GeneratedHttpRequest<ChefAsyncClient> httpRequest = processor.createRequest(method,
"cookbook", file);
assertRequestLineEquals(httpRequest, "POST http://localhost:4000/cookbooks HTTP/1.1");
assertHeadersEqual(
httpRequest,
"Accept: application/json\nContent-Length: "
+ (file.getName().length() + 206)
+ "\nContent-Type: multipart/form-data; boundary=--JCLOUDS--\nX-Chef-Version: 0.9.0\n");
assertPayloadEquals(httpRequest, COOOKBOOK_BODY.replace("cookbook.tar.gz", file.getName()));
assertResponseParserClassEquals(method, httpRequest, CloseContentAndReturn.class);
assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, null);
checkFilters(httpRequest);
}
public void testCreateCookbookByte() throws SecurityException, NoSuchMethodException,
IOException {
Method method = ChefAsyncClient.class.getMethod("createCookbook", String.class, byte[].class);
GeneratedHttpRequest<ChefAsyncClient> httpRequest = processor.createRequest(method,
"cookbook", "".getBytes());
assertRequestLineEquals(httpRequest, "POST http://localhost:4000/cookbooks HTTP/1.1");
assertHeadersEqual(
httpRequest,
"Accept: application/json\nContent-Length: 221\nContent-Type: multipart/form-data; boundary=--JCLOUDS--\nX-Chef-Version: 0.9.0\n");
assertPayloadEquals(httpRequest, COOOKBOOK_BODY);
assertResponseParserClassEquals(method, httpRequest, CloseContentAndReturn.class);
assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, null);
checkFilters(httpRequest);
}
public void testUpdateCookbookFile() throws SecurityException, NoSuchMethodException,
IOException {
Method method = ChefAsyncClient.class.getMethod("updateCookbook", String.class, File.class);
File file = File.createTempFile("jclouds-chef=test", ".tar.gz");
file.deleteOnExit();
Files.write("".getBytes(), file);
GeneratedHttpRequest<ChefAsyncClient> httpRequest = processor.createRequest(method,
"cookbook", file);
assertRequestLineEquals(httpRequest, assertRequestLineEquals(httpRequest,
"PUT http://localhost:4000/cookbooks/cookbook/_content HTTP/1.1"); "PUT http://localhost:4000/cookbooks/cookbook/1.0.1 HTTP/1.1");
assertHeadersEqual( assertHeadersEqual(
httpRequest, httpRequest,
"Accept: application/json\nContent-Length: " "Accept: application/json\nContent-Length: 134\nContent-Type: application/json\nX-Chef-Version: 0.9.0\n");
+ (file.getName().length() + 206) assertPayloadEquals(
+ "\nContent-Type: multipart/form-data; boundary=--JCLOUDS--\nX-Chef-Version: 0.9.0\n"); httpRequest,
assertPayloadEquals(httpRequest, COOOKBOOK_BODY.replace("cookbook.tar.gz", file.getName())); "{\"definitions\":[],\"attributes\":[],\"files\":[],\"providers\":[],\"resources\":[],\"templates\":[],\"libraries\":[],\"recipes\":[],\"root_files\":[]}");
assertResponseParserClassEquals(method, httpRequest, CloseContentAndReturn.class); assertResponseParserClassEquals(method, httpRequest,
CloseContentAndReturn.class);
assertSaxResponseParserClassEquals(method, null); assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, null); assertExceptionParserClassEquals(method, null);
@ -203,36 +162,20 @@ public class ChefAsyncClientTest extends RestClientTest<ChefAsyncClient> {
} }
public void testUpdateCookbookByte() throws SecurityException, NoSuchMethodException, public void testListCookbooks() throws SecurityException,
IOException { NoSuchMethodException, IOException {
Method method = ChefAsyncClient.class.getMethod("updateCookbook", String.class, byte[].class);
GeneratedHttpRequest<ChefAsyncClient> httpRequest = processor.createRequest(method,
"cookbook", "".getBytes());
assertRequestLineEquals(httpRequest,
"PUT http://localhost:4000/cookbooks/cookbook/_content HTTP/1.1");
assertHeadersEqual(
httpRequest,
"Accept: application/json\nContent-Length: 221\nContent-Type: multipart/form-data; boundary=--JCLOUDS--\nX-Chef-Version: 0.9.0\n");
assertPayloadEquals(httpRequest, COOOKBOOK_BODY);
assertResponseParserClassEquals(method, httpRequest, CloseContentAndReturn.class);
assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, null);
checkFilters(httpRequest);
}
public void testListCookbooks() throws SecurityException, NoSuchMethodException, IOException {
Method method = ChefAsyncClient.class.getMethod("listCookbooks"); Method method = ChefAsyncClient.class.getMethod("listCookbooks");
GeneratedHttpRequest<ChefAsyncClient> httpRequest = processor.createRequest(method); GeneratedHttpRequest<ChefAsyncClient> httpRequest = processor
.createRequest(method);
assertRequestLineEquals(httpRequest, "GET http://localhost:4000/cookbooks HTTP/1.1"); assertRequestLineEquals(httpRequest,
assertHeadersEqual(httpRequest, "Accept: application/json\nX-Chef-Version: 0.9.0\n"); "GET http://localhost:4000/cookbooks HTTP/1.1");
assertHeadersEqual(httpRequest,
"Accept: application/json\nX-Chef-Version: 0.9.0\n");
assertPayloadEquals(httpRequest, null); assertPayloadEquals(httpRequest, null);
assertResponseParserClassEquals(method, httpRequest, ParseKeySetFromJson.class); assertResponseParserClassEquals(method, httpRequest,
ParseKeySetFromJson.class);
assertSaxResponseParserClassEquals(method, null); assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, null); assertExceptionParserClassEquals(method, null);
@ -240,14 +183,20 @@ public class ChefAsyncClientTest extends RestClientTest<ChefAsyncClient> {
} }
public void testClientExists() throws SecurityException, NoSuchMethodException, IOException { public void testClientExists() throws SecurityException,
Method method = ChefAsyncClient.class.getMethod("clientExists", String.class); NoSuchMethodException, IOException {
GeneratedHttpRequest<ChefAsyncClient> httpRequest = processor.createRequest(method, "client"); Method method = ChefAsyncClient.class.getMethod("clientExists",
assertRequestLineEquals(httpRequest, "HEAD http://localhost:4000/clients/client HTTP/1.1"); String.class);
assertHeadersEqual(httpRequest, "Accept: application/json\nX-Chef-Version: 0.9.0\n"); GeneratedHttpRequest<ChefAsyncClient> httpRequest = processor
.createRequest(method, "client");
assertRequestLineEquals(httpRequest,
"HEAD http://localhost:4000/clients/client HTTP/1.1");
assertHeadersEqual(httpRequest,
"Accept: application/json\nX-Chef-Version: 0.9.0\n");
assertPayloadEquals(httpRequest, null); assertPayloadEquals(httpRequest, null);
assertResponseParserClassEquals(method, httpRequest, ReturnTrueIf2xx.class); assertResponseParserClassEquals(method, httpRequest,
ReturnTrueIf2xx.class);
assertSaxResponseParserClassEquals(method, null); assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, ReturnFalseOnNotFoundOr404.class); assertExceptionParserClassEquals(method, ReturnFalseOnNotFoundOr404.class);
@ -255,14 +204,20 @@ public class ChefAsyncClientTest extends RestClientTest<ChefAsyncClient> {
} }
public void testDeleteClient() throws SecurityException, NoSuchMethodException, IOException { public void testDeleteClient() throws SecurityException,
Method method = ChefAsyncClient.class.getMethod("deleteClient", String.class); NoSuchMethodException, IOException {
GeneratedHttpRequest<ChefAsyncClient> httpRequest = processor.createRequest(method, "client"); Method method = ChefAsyncClient.class.getMethod("deleteClient",
assertRequestLineEquals(httpRequest, "DELETE http://localhost:4000/clients/client HTTP/1.1"); String.class);
assertHeadersEqual(httpRequest, "Accept: application/json\nX-Chef-Version: 0.9.0\n"); GeneratedHttpRequest<ChefAsyncClient> httpRequest = processor
.createRequest(method, "client");
assertRequestLineEquals(httpRequest,
"DELETE http://localhost:4000/clients/client HTTP/1.1");
assertHeadersEqual(httpRequest,
"Accept: application/json\nX-Chef-Version: 0.9.0\n");
assertPayloadEquals(httpRequest, null); assertPayloadEquals(httpRequest, null);
assertResponseParserClassEquals(method, httpRequest, ReturnStringIf200.class); assertResponseParserClassEquals(method, httpRequest,
ReturnStringIf200.class);
assertSaxResponseParserClassEquals(method, null); assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, ReturnNullOnNotFoundOr404.class); assertExceptionParserClassEquals(method, ReturnNullOnNotFoundOr404.class);
@ -270,17 +225,22 @@ public class ChefAsyncClientTest extends RestClientTest<ChefAsyncClient> {
} }
public void testGenerateKeyForClient() throws SecurityException, NoSuchMethodException, public void testGenerateKeyForClient() throws SecurityException,
IOException { NoSuchMethodException, IOException {
Method method = ChefAsyncClient.class.getMethod("generateKeyForClient", String.class); Method method = ChefAsyncClient.class.getMethod("generateKeyForClient",
GeneratedHttpRequest<ChefAsyncClient> httpRequest = processor.createRequest(method, "client"); String.class);
assertRequestLineEquals(httpRequest, "PUT http://localhost:4000/clients/client HTTP/1.1"); GeneratedHttpRequest<ChefAsyncClient> httpRequest = processor
.createRequest(method, "client");
assertRequestLineEquals(httpRequest,
"PUT http://localhost:4000/clients/client HTTP/1.1");
assertHeadersEqual( assertHeadersEqual(
httpRequest, httpRequest,
"Accept: application/json\nContent-Length: 44\nContent-Type: application/json\nX-Chef-Version: 0.9.0\n"); "Accept: application/json\nContent-Length: 44\nContent-Type: application/json\nX-Chef-Version: 0.9.0\n");
assertPayloadEquals(httpRequest, "{\"clientname\":\"client\", \"private_key\": true}"); assertPayloadEquals(httpRequest,
"{\"clientname\":\"client\", \"private_key\": true}");
assertResponseParserClassEquals(method, httpRequest, ParseKeyFromJson.class); assertResponseParserClassEquals(method, httpRequest,
ParseKeyFromJson.class);
assertSaxResponseParserClassEquals(method, null); assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, null); assertExceptionParserClassEquals(method, null);
@ -288,17 +248,22 @@ public class ChefAsyncClientTest extends RestClientTest<ChefAsyncClient> {
} }
public void testCreateClient() throws SecurityException, NoSuchMethodException, IOException { public void testCreateClient() throws SecurityException,
Method method = ChefAsyncClient.class.getMethod("createClient", String.class); NoSuchMethodException, IOException {
GeneratedHttpRequest<ChefAsyncClient> httpRequest = processor.createRequest(method, "client"); Method method = ChefAsyncClient.class.getMethod("createClient",
String.class);
GeneratedHttpRequest<ChefAsyncClient> httpRequest = processor
.createRequest(method, "client");
assertRequestLineEquals(httpRequest, "POST http://localhost:4000/clients HTTP/1.1"); assertRequestLineEquals(httpRequest,
"POST http://localhost:4000/clients HTTP/1.1");
assertHeadersEqual( assertHeadersEqual(
httpRequest, httpRequest,
"Accept: application/json\nContent-Length: 23\nContent-Type: application/json\nX-Chef-Version: 0.9.0\n"); "Accept: application/json\nContent-Length: 23\nContent-Type: application/json\nX-Chef-Version: 0.9.0\n");
assertPayloadEquals(httpRequest, "{\"clientname\":\"client\"}"); assertPayloadEquals(httpRequest, "{\"clientname\":\"client\"}");
assertResponseParserClassEquals(method, httpRequest, ParseKeyFromJson.class); assertResponseParserClassEquals(method, httpRequest,
ParseKeyFromJson.class);
assertSaxResponseParserClassEquals(method, null); assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, null); assertExceptionParserClassEquals(method, null);
@ -306,15 +271,20 @@ public class ChefAsyncClientTest extends RestClientTest<ChefAsyncClient> {
} }
public void testListClients() throws SecurityException, NoSuchMethodException, IOException { public void testListClients() throws SecurityException,
NoSuchMethodException, IOException {
Method method = ChefAsyncClient.class.getMethod("listClients"); Method method = ChefAsyncClient.class.getMethod("listClients");
GeneratedHttpRequest<ChefAsyncClient> httpRequest = processor.createRequest(method); GeneratedHttpRequest<ChefAsyncClient> httpRequest = processor
.createRequest(method);
assertRequestLineEquals(httpRequest, "GET http://localhost:4000/clients HTTP/1.1"); assertRequestLineEquals(httpRequest,
assertHeadersEqual(httpRequest, "Accept: application/json\nX-Chef-Version: 0.9.0\n"); "GET http://localhost:4000/clients HTTP/1.1");
assertHeadersEqual(httpRequest,
"Accept: application/json\nX-Chef-Version: 0.9.0\n");
assertPayloadEquals(httpRequest, null); assertPayloadEquals(httpRequest, null);
assertResponseParserClassEquals(method, httpRequest, ParseKeySetFromJson.class); assertResponseParserClassEquals(method, httpRequest,
ParseKeySetFromJson.class);
assertSaxResponseParserClassEquals(method, null); assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, null); assertExceptionParserClassEquals(method, null);
@ -325,7 +295,8 @@ public class ChefAsyncClientTest extends RestClientTest<ChefAsyncClient> {
@Override @Override
protected void checkFilters(GeneratedHttpRequest<ChefAsyncClient> httpRequest) { protected void checkFilters(GeneratedHttpRequest<ChefAsyncClient> httpRequest) {
assertEquals(httpRequest.getFilters().size(), 1); assertEquals(httpRequest.getFilters().size(), 1);
assertEquals(httpRequest.getFilters().get(0).getClass(), SignedHeaderAuth.class); assertEquals(httpRequest.getFilters().get(0).getClass(),
SignedHeaderAuth.class);
} }
@Override @Override
@ -352,6 +323,6 @@ public class ChefAsyncClientTest extends RestClientTest<ChefAsyncClient> {
@Override @Override
public ContextSpec<ChefClient, ChefAsyncClient> createContextSpec() { public ContextSpec<ChefClient, ChefAsyncClient> createContextSpec() {
return new RestContextFactory().createContextSpec("chef", "user", return new RestContextFactory().createContextSpec("chef", "user",
SignedHeaderAuthTest.PRIVATE_KEY, new Properties()); SignedHeaderAuthTest.PRIVATE_KEY, new Properties());
} }
} }

View File

@ -28,11 +28,10 @@ import static org.testng.Assert.assertNotNull;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.util.Properties; import java.util.Properties;
import java.util.Set; import java.util.Set;
import org.jclouds.chef.domain.Cookbook;
import org.jclouds.logging.log4j.config.Log4JLoggingModule; import org.jclouds.logging.log4j.config.Log4JLoggingModule;
import org.jclouds.rest.RestContext; import org.jclouds.rest.RestContext;
import org.jclouds.rest.RestContextFactory; import org.jclouds.rest.RestContextFactory;
@ -42,7 +41,6 @@ import org.testng.annotations.Test;
import com.google.common.base.Charsets; import com.google.common.base.Charsets;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.common.io.ByteStreams;
import com.google.common.io.Files; import com.google.common.io.Files;
import com.google.inject.Module; import com.google.inject.Module;
@ -54,7 +52,7 @@ import com.google.inject.Module;
@Test(groups = "live", testName = "chef.ChefClientLiveTest") @Test(groups = "live", testName = "chef.ChefClientLiveTest")
public class ChefClientLiveTest { public class ChefClientLiveTest {
private static final String COOKBOOK_NAME = "runit"; private static final String COOKBOOK_NAME = "brew";
private static final String COOKBOOK_URI = "https://s3.amazonaws.com/opscode-community/cookbook_versions/tarballs/195/original/runit.tar.gz"; private static final String COOKBOOK_URI = "https://s3.amazonaws.com/opscode-community/cookbook_versions/tarballs/195/original/runit.tar.gz";
private RestContext<ChefClient, ChefAsyncClient> validatorConnection; private RestContext<ChefClient, ChefAsyncClient> validatorConnection;
private RestContext<ChefClient, ChefAsyncClient> clientConnection; private RestContext<ChefClient, ChefAsyncClient> clientConnection;
@ -67,39 +65,45 @@ public class ChefClientLiveTest {
private byte[] cookbookContent; private byte[] cookbookContent;
private File cookbookFile; private File cookbookFile;
public static final String PREFIX = System.getProperty("user.name") + "-jcloudstest"; public static final String PREFIX = System.getProperty("user.name")
+ "-jcloudstest";
@BeforeClass(groups = { "live" }) @BeforeClass(groups = { "live" })
public void setupClient() throws IOException { public void setupClient() throws IOException {
endpoint = checkNotNull(System.getProperty("jclouds.test.endpoint"), "jclouds.test.endpoint"); endpoint = checkNotNull(System.getProperty("jclouds.test.endpoint"),
"jclouds.test.endpoint");
validator = System.getProperty("jclouds.test.validator"); validator = System.getProperty("jclouds.test.validator");
if (validator == null || validator.equals("")) if (validator == null || validator.equals(""))
validator = "chef-validator"; validator = "chef-validator";
String validatorKey = System.getProperty("jclouds.test.validator.key"); String validatorKey = System.getProperty("jclouds.test.validator.key");
if (validatorKey == null || validatorKey.equals("")) if (validatorKey == null || validatorKey.equals(""))
validatorKey = System.getProperty("user.home") + "/.chef/validation.pem"; validatorKey = System.getProperty("user.home")
user = checkNotNull(System.getProperty("jclouds.test.identity")); + "/.chef/validation.pem";
user = checkNotNull(System.getProperty("jclouds.test.identity"),
"jclouds.test.identity");
String keyfile = System.getProperty("jclouds.test.credential"); String keyfile = System.getProperty("jclouds.test.credential");
if (keyfile == null || keyfile.equals("")) if (keyfile == null || keyfile.equals(""))
keyfile = System.getProperty("user.home") + "/.chef/" + user + ".pem"; keyfile = System.getProperty("user.home") + "/.chef/" + user + ".pem";
validatorConnection = createConnection(validator, Files.toString(new File(validatorKey), validatorConnection = createConnection(validator, Files.toString(
Charsets.UTF_8)); new File(validatorKey), Charsets.UTF_8));
adminConnection = createConnection(user, Files.toString(new File(keyfile), Charsets.UTF_8)); adminConnection = createConnection(user, Files.toString(
new File(keyfile), Charsets.UTF_8));
} }
private RestContext<ChefClient, ChefAsyncClient> createConnection(String identity, String key) private RestContext<ChefClient, ChefAsyncClient> createConnection(
throws IOException { String identity, String key) throws IOException {
Properties props = new Properties(); Properties props = new Properties();
props.setProperty("chef.endpoint", endpoint); props.setProperty("chef.endpoint", endpoint);
return new RestContextFactory().createContext("chef", identity, key, ImmutableSet return new RestContextFactory().createContext("chef", identity, key,
.<Module> of(new Log4JLoggingModule()), props); ImmutableSet.<Module> of(new Log4JLoggingModule()), props);
} }
@Test @Test
public void testListClients() throws Exception { public void testListClients() throws Exception {
Set<String> clients = validatorConnection.getApi().listClients(); Set<String> clients = validatorConnection.getApi().listClients();
assertNotNull(clients); assertNotNull(clients);
assert clients.contains(validator) : "validator: " + validator + " not in: " + clients; assert clients.contains(validator) : "validator: " + validator
+ " not in: " + clients;
} }
@Test(dependsOnMethods = "testListClients") @Test(dependsOnMethods = "testListClients")
@ -127,39 +131,43 @@ public class ChefClientLiveTest {
} }
@Test @Test
public void testCreateCookbook() throws Exception { public void testListCookbooks() throws Exception {
adminConnection.getApi().deleteCookbook(COOKBOOK_NAME); for (String cookbook : adminConnection.getApi().listCookbooks())
InputStream in = null; for (String version : adminConnection.getApi().getVersionsOfCookbook(
try { cookbook)) {
in = URI.create(COOKBOOK_URI).toURL().openStream(); System.err.printf("%s/%s:%n", cookbook, version);
System.err.printf("%s%n", adminConnection.getApi().getCookbook(
cookbookContent = ByteStreams.toByteArray(in); cookbook, version));
}
cookbookFile = File.createTempFile("foo", ".tar.gz");
Files.write(cookbookContent, cookbookFile);
cookbookFile.deleteOnExit();
adminConnection.getApi().createCookbook(COOKBOOK_NAME, cookbookFile);
adminConnection.getApi().deleteCookbook(COOKBOOK_NAME);
adminConnection.getApi().createCookbook(COOKBOOK_NAME, cookbookContent);
} finally {
if (in != null)
in.close();
}
} }
@Test(dependsOnMethods = "testCreateCookbook") @Test(dependsOnMethods = "testListCookbooks")
public void testUpdateCookbook() throws Exception { public void testUpdateCookbook() throws Exception {
adminConnection.getApi().updateCookbook(COOKBOOK_NAME, cookbookFile); for (String cookbook : adminConnection.getApi().listCookbooks())
// TODO verify timestamp or something for (String version : adminConnection.getApi().getVersionsOfCookbook(
adminConnection.getApi().updateCookbook(COOKBOOK_NAME, cookbookContent); cookbook)) {
System.err.printf("%s/%s:%n", cookbook, version);
Cookbook cook = adminConnection.getApi().getCookbook(cookbook,
version);
adminConnection.getApi().updateCookbook(cookbook, version, cook);
}
} }
@Test(dependsOnMethods = "testUpdateCookbook") @Test(dependsOnMethods = "testUpdateCookbook")
public void testListCookbooks() throws Exception { public void testCreateCookbook() throws Exception {
for (String cookbook : adminConnection.getApi().listCookbooks()) for (String cookbook : adminConnection.getApi().listCookbooks())
System.err.println(adminConnection.getApi().getCookbook(cookbook)); for (String version : adminConnection.getApi().getVersionsOfCookbook(
cookbook)) {
System.err.printf("%s/%s:%n", cookbook, version);
Cookbook 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);
}
} }
@AfterClass(groups = { "live" }) @AfterClass(groups = { "live" })

View File

@ -0,0 +1,113 @@
package org.jclouds.chef.functions;
import static org.testng.Assert.assertEquals;
import java.io.IOException;
import java.net.URI;
import java.util.Set;
import org.jclouds.chef.domain.Attribute;
import org.jclouds.chef.domain.Cookbook;
import org.jclouds.chef.domain.Metadata;
import org.jclouds.chef.domain.Resource;
import org.jclouds.http.HttpResponse;
import org.jclouds.http.functions.config.ParserModule;
import org.jclouds.util.Utils;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.gson.Gson;
import com.google.inject.Guice;
import com.google.inject.Injector;
/**
* Tests behavior of {@code ParseCookbookFromJson}
*
* @author Adrian Cole
*/
@Test(groups = "unit", sequential = true, testName = "chef.ParseCookbookFromJsonTest")
public class ParseCookbookFromJsonTest {
private ParseCookbookFromJson handler;
@BeforeTest
protected void setUpInjector() throws IOException {
Injector injector = Guice.createInjector(new ParserModule());
handler = injector.getInstance(ParseCookbookFromJson.class);
}
public void testBrew() throws IOException {
Cookbook cookbook = handler.apply(new HttpResponse(
ParseCookbookFromJsonTest.class
.getResourceAsStream("/brew-cookbook.json")));
assertEquals(cookbook, handler.apply(new HttpResponse(Utils
.toInputStream(new Gson().toJson(cookbook)))));
}
public void testTomcat() {
Cookbook cookbook = handler.apply(new HttpResponse(
ParseCookbookFromJsonTest.class
.getResourceAsStream("/tomcat-cookbook.json")));
assertEquals(cookbook, handler.apply(new HttpResponse(Utils
.toInputStream(new Gson().toJson(cookbook)))));
}
public void testMysql() throws IOException {
Cookbook cookbook = handler.apply(new HttpResponse(
ParseCookbookFromJsonTest.class
.getResourceAsStream("/mysql-cookbook.json")));
assertEquals(cookbook, handler.apply(new HttpResponse(Utils
.toInputStream(new Gson().toJson(cookbook)))));
}
public void testApache() {
assertEquals(
handler.apply(new HttpResponse(ParseCookbookFromJsonTest.class
.getResourceAsStream("/apache-chef-demo-cookbook.json"))),
new Cookbook(
"apache-chef-demo-0.0.0",
ImmutableSet.<Resource> of(),
"Chef::CookbookVersion",
ImmutableSet.<Resource> of(),
ImmutableSet.<Resource> of(),
new Metadata("Apache v2.0", "Your Name", ImmutableMap
.<String, String> of(), ImmutableMap
.<String, Set<String>> of(), "youremail@example.com",
ImmutableMap.<String, Set<String>> of(),
"A fabulous new cookbook", ImmutableMap
.<String, Set<String>> of(), ImmutableMap
.<String, Set<String>> of(), "0.0.0",
ImmutableMap.<String, String> of(), ImmutableMap
.<String, Set<String>> of(), "apache-chef-demo",
ImmutableMap.<String, String> of(), "", ImmutableMap
.<String, Attribute> of(), ImmutableMap
.<String, String> of()),
ImmutableSet.<Resource> of(),
"apache-chef-demo",
ImmutableSet.<Resource> of(),
ImmutableSet.<Resource> of(),
ImmutableSet.<Resource> of(),
"0.0.0",
ImmutableSet.<Resource> of(),
ImmutableSet
.<Resource> of(
new Resource(
"README",
URI
.create("https://s3.amazonaws.com/opscode-platform-production-data/organization-486ca3ac66264fea926aa0b4ff74341c/checksum-11637f98942eafbf49c71b7f2f048b78?AWSAccessKeyId=AKIAJOZTD2N26S7W6APA&Expires=1277766181&Signature=zgpNl6wSxjTNovqZu2nJq0JztU8%3D"),
"11637f98942eafbf49c71b7f2f048b78",
"README", "default"),
new Resource(
"Rakefile",
URI
.create("https://s3.amazonaws.com/opscode-platform-production-data/organization-486ca3ac66264fea926aa0b4ff74341c/checksum-ebcf925a1651b4e04b9cd8aac2bc54eb?AWSAccessKeyId=AKIAJOZTD2N26S7W6APA&Expires=1277766181&Signature=EFzzDSKKytTl7b%2FxrCeNLh05zj4%3D"),
"ebcf925a1651b4e04b9cd8aac2bc54eb",
"Rakefile", "default")), "cookbook_version"));
}
}

View File

@ -0,0 +1,38 @@
package org.jclouds.chef.functions;
import static org.testng.Assert.assertEquals;
import java.io.IOException;
import org.jclouds.http.HttpResponse;
import org.jclouds.http.functions.config.ParserModule;
import org.jclouds.util.Utils;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableSet;
import com.google.inject.Guice;
import com.google.inject.Injector;
/**
* Tests behavior of {@code ParseValueSetFromJson}
*
* @author Adrian Cole
*/
@Test(groups = "unit", sequential = true, testName = "chef.ParseValueSetFromJsonTest")
public class ParseValueSetFromJsonTest {
private ParseValueSetFromJson handler;
@BeforeTest
protected void setUpInjector() throws IOException {
Injector injector = Guice.createInjector(new ParserModule());
handler = injector.getInstance(ParseValueSetFromJson.class);
}
public void testRegex() {
assertEquals(handler.apply(new HttpResponse(Utils
.toInputStream("{\"runit\":[\"0.7.0\",\"0.7.1\"]}"))), ImmutableSet
.of("0.7.0", "0.7.1"));
}
}

View File

@ -0,0 +1,37 @@
{
"definitions": [],
"name": "apache-chef-demo-0.0.0",
"attributes": [],
"files": [],
"json_class": "Chef::CookbookVersion",
"providers": [],
"metadata": {
"dependencies": {}, "name": "apache-chef-demo",
"maintainer_email": "youremail@example.com",
"attributes": {}, "license": "Apache v2.0",
"maintainer": "Your Name",
"suggestions": {}, "platforms": {}, "long_description": "",
"recommendations": {}, "version": "0.0.0",
"groupings": {}, "recipes": {}, "conflicting": {}, "description": "A fabulous new cookbook",
"replacing": {}, "providing": {}
}, "libraries": [],
"resources": [],
"templates": [],
"cookbook_name": "apache-chef-demo",
"version": "0.0.0",
"recipes": [],
"root_files": [{
"name": "README",
"url": "https://s3.amazonaws.com/opscode-platform-production-data/organization-486ca3ac66264fea926aa0b4ff74341c/checksum-11637f98942eafbf49c71b7f2f048b78?AWSAccessKeyId=AKIAJOZTD2N26S7W6APA&Expires=1277766181&Signature=zgpNl6wSxjTNovqZu2nJq0JztU8%3D",
"checksum": "11637f98942eafbf49c71b7f2f048b78",
"path": "README",
"specificity": "default"
}, {
"name": "Rakefile",
"url": "https://s3.amazonaws.com/opscode-platform-production-data/organization-486ca3ac66264fea926aa0b4ff74341c/checksum-ebcf925a1651b4e04b9cd8aac2bc54eb?AWSAccessKeyId=AKIAJOZTD2N26S7W6APA&Expires=1277766181&Signature=EFzzDSKKytTl7b%2FxrCeNLh05zj4%3D",
"checksum": "ebcf925a1651b4e04b9cd8aac2bc54eb",
"path": "Rakefile",
"specificity": "default"
}],
"chef_type": "cookbook_version"
}

View File

@ -0,0 +1 @@
{"name":"brew-0.0.0","definitions":[],"json_class":"Chef::CookbookVersion","attributes":[],"files":[],"metadata":{"dependencies":{},"name":"brew","maintainer_email":"youremail@example.com","license":"Apache v2.0","attributes":{},"maintainer":"Your Name","suggestions":{},"platforms":{},"long_description":"","version":"0.0.0","recommendations":{},"conflicting":{},"recipes":{"brew":""},"groupings":{},"description":"A fabulous new cookbook","replacing":{},"providing":{"brew":[]}},"providers":[{"name":"brew.rb","url":"https://s3.amazonaws.com/opscode-platform-production-data/organization-486ca3ac66264fea926aa0b4ff74341c/checksum-0c5ecd7788cf4f6c7de2a57193897a6c?AWSAccessKeyId=AKIAJOZTD2N26S7W6APA&Expires=1277774465&Signature=brTA3YkBF7iDnjPGCCHxgm7AHko%3D","checksum":"0c5ecd7788cf4f6c7de2a57193897a6c","path":"providers/brew.rb","specificity":"default"}],"cookbook_name":"brew","resources":[{"name":"brew.rb","url":"https://s3.amazonaws.com/opscode-platform-production-data/organization-486ca3ac66264fea926aa0b4ff74341c/checksum-0189e76ccc476701d6b374e5a1a27347?AWSAccessKeyId=AKIAJOZTD2N26S7W6APA&Expires=1277774465&Signature=ufrI1k6pKJ1%2FBRMAaIGr6icJlpc%3D","checksum":"0189e76ccc476701d6b374e5a1a27347","path":"resources/brew.rb","specificity":"default"}],"templates":[],"libraries":[],"version":"0.0.0","recipes":[{"name":"default.rb","url":"https://s3.amazonaws.com/opscode-platform-production-data/organization-486ca3ac66264fea926aa0b4ff74341c/checksum-1dda05ed139664f1f89b9dec482b77c0?AWSAccessKeyId=AKIAJOZTD2N26S7W6APA&Expires=1277774465&Signature=dOzPk64at92zOfZlxt1suDpGuPs%3D","checksum":"1dda05ed139664f1f89b9dec482b77c0","path":"recipes/default.rb","specificity":"default"}],"root_files":[],"chef_type":"cookbook_version"}

File diff suppressed because one or more lines are too long

View File

@ -1,150 +0,0 @@
{
"templates": [
],
"attributes": [
{
"uri": "https://api.opscode.com/organizations/jclouds/cookbooks/runit/attributes?id=default.rb",
"name": "default.rb",
"checksum": "1dffbe14afa3630aa4cb268508bb723b0fba33e2e33a8c517feedad981db3147"
}
],
"definitions": [
{
"uri": "https://api.opscode.com/organizations/jclouds/cookbooks/runit/definitions?id=runit_service.rb",
"name": "runit_service.rb",
"checksum": "32fe6fe902b0dfe1870cfbd4aad475039e0c3d661353b12cd54ed29c5020a9e7"
}
],
"metadata": {
"conflicting": {
},
"attributes": {
"runit/sv_dir": {
"required": "optional",
"calculated": false,
"choice": [
],
"default": "/etc/sv",
"type": "string",
"recipes": [
],
"display_name": "Runit sv directory",
"description": "Location of services managed by runit"
},
"runit/service_dir": {
"required": "optional",
"calculated": false,
"choice": [
],
"default": "/etc/service",
"type": "string",
"recipes": [
],
"display_name": "Runit service directory",
"description": "Symlinks to services managed under runit"
},
"runit": {
"required": "optional",
"calculated": false,
"choice": [
],
"type": "hash",
"recipes": [
],
"display_name": "Runit",
"description": "Hash of runit attributes"
},
"runit/sv_bin": {
"required": "optional",
"calculated": false,
"choice": [
],
"default": "/usr/bin/sv",
"type": "string",
"recipes": [
],
"display_name": "Runit sv bin",
"description": "Location of the sv binary"
}
},
"providing": {
},
"license": "Apache 2.0",
"replacing": {
},
"long_description": "",
"dependencies": {
},
"groupings": {
},
"recommendations": {
},
"platforms": {
"debian": [
],
"ubuntu": [
]
},
"description": "Installs runit and provides runit_service definition",
"version": "0.11.0",
"maintainer": "Opscode, Inc.",
"name": "runit",
"recipes": {
},
"suggestions": {
},
"maintainer_email": "cookbooks@opscode.com"
},
"resources": [
],
"files": [
{
"uri": "https://api.opscode.com/organizations/jclouds/cookbooks/runit/files?version=7.04&id=runsvdir&platform=ubuntu",
"specificity": "ubuntu-7.04",
"name": "runsvdir",
"checksum": "28c55f711453fd9d4fbf7cc747719e7976607f892fa61cfb348421858ef3dd5b"
},
{
"uri": "https://api.opscode.com/organizations/jclouds/cookbooks/runit/files?version=8.04&id=runsvdir&platform=ubuntu",
"specificity": "ubuntu-8.04",
"name": "runsvdir",
"checksum": "28c55f711453fd9d4fbf7cc747719e7976607f892fa61cfb348421858ef3dd5b"
},
{
"uri": "https://api.opscode.com/organizations/jclouds/cookbooks/runit/files?id=runsvdir",
"specificity": "default",
"name": "runsvdir",
"checksum": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"uri": "https://api.opscode.com/organizations/jclouds/cookbooks/runit/files?id=runit.seed",
"specificity": "default",
"name": "runit.seed",
"checksum": "9c675810fd4c0ec4fb8b2788ba8512990f436347834373445a9fb48c46d0aff0"
},
{
"uri": "https://api.opscode.com/organizations/jclouds/cookbooks/runit/files?version=7.10&id=runsvdir&platform=ubuntu",
"specificity": "ubuntu-7.10",
"name": "runsvdir",
"checksum": "28c55f711453fd9d4fbf7cc747719e7976607f892fa61cfb348421858ef3dd5b"
},
{
"uri": "https://api.opscode.com/organizations/jclouds/cookbooks/runit/files?version=6.10&id=runsvdir&platform=ubuntu",
"specificity": "ubuntu-6.10",
"name": "runsvdir",
"checksum": "61e090e43b0ce746bd22e121422d7d05c04e9b9883dac3632418bdf7dc539b38"
}
],
"name": "runit",
"libraries": [
],
"recipes": [
{
"uri": "https://api.opscode.com/organizations/jclouds/cookbooks/runit/recipes?id=default.rb",
"name": "default.rb",
"checksum": "76589110f5db8cf8b0a045ce0b3fc500046f6bb63c2d16d50cee6cfaaaeff29a"
}
],
"providers": [
]
}

File diff suppressed because one or more lines are too long