Issue 191: updated to provide cookbook creation support

This commit is contained in:
Adrian Cole 2010-07-06 22:47:57 -07:00
parent 47a843dd24
commit 99e14159a0
24 changed files with 810 additions and 400 deletions

View File

@ -35,16 +35,19 @@ import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.core.MediaType;
import org.jclouds.chef.binders.BindChecksumsToJsonPayload;
import org.jclouds.chef.binders.BindClientnameToJsonPayload;
import org.jclouds.chef.binders.BindGenerateKeyForClientToJsonPayload;
import org.jclouds.chef.domain.Cookbook;
import org.jclouds.chef.binders.BindIsCompletedToJsonPayload;
import org.jclouds.chef.binders.BindMD5sToJsonPayload;
import org.jclouds.chef.domain.CookbookVersion;
import org.jclouds.chef.domain.Sandbox;
import org.jclouds.chef.domain.UploadSite;
import org.jclouds.chef.filters.SignedHeaderAuth;
import org.jclouds.chef.functions.ParseCookbookFromJson;
import org.jclouds.chef.functions.ParseCookbookVersionFromJson;
import org.jclouds.chef.functions.ParseKeyFromJson;
import org.jclouds.chef.functions.ParseKeySetFromJson;
import org.jclouds.chef.functions.ParseSandboxFromJson;
import org.jclouds.chef.functions.ParseUploadSiteFromJson;
import org.jclouds.chef.functions.ParseValueSetFromJson;
import org.jclouds.rest.annotations.BinderParam;
import org.jclouds.rest.annotations.ExceptionParser;
@ -70,16 +73,25 @@ import com.google.common.util.concurrent.ListenableFuture;
@Consumes(MediaType.APPLICATION_JSON)
@Headers(keys = "X-Chef-Version", values = ChefAsyncClient.VERSION)
public interface ChefAsyncClient {
public static final String VERSION = "0.9.0";
public static final String VERSION = "0.9.6";
/**
* @see ChefClient#getUploadUrisForContent
* @see ChefClient#getUploadUrisForChecksums
*/
@POST
@Path("sandboxes")
@ResponseParser(ParseUploadSiteFromJson.class)
ListenableFuture<UploadSite> getUploadSiteForChecksums(
@BinderParam(BindMD5sToJsonPayload.class) Set<byte[]> md5s);
/**
* @see ChefClient#closeSandbox
*/
@PUT
@Path("sandboxes/{id}")
@ResponseParser(ParseSandboxFromJson.class)
ListenableFuture<Sandbox> getUploadUrisForContent(
@BinderParam(BindChecksumsToJsonPayload.class) Set<String> checksums);
ListenableFuture<Sandbox> closeSandbox(@PathParam("id") String id,
@BinderParam(BindIsCompletedToJsonPayload.class) boolean isCompleted);
/**
* @see ChefCookbooks#listCookbooks
@ -94,10 +106,9 @@ public interface ChefAsyncClient {
*/
@PUT
@Path("cookbooks/{cookbookname}/{version}")
ListenableFuture<Void> updateCookbook(
@PathParam("cookbookname") String cookbookName,
@PathParam("version") String version,
@BinderParam(BindToJsonPayload.class) Cookbook cookbook);
ListenableFuture<Void> updateCookbook(@PathParam("cookbookname") String cookbookName,
@PathParam("version") String version,
@BinderParam(BindToJsonPayload.class) CookbookVersion cookbook);
/**
* @see ChefCookbook#deleteCookbook(String)
@ -105,9 +116,8 @@ public interface ChefAsyncClient {
@DELETE
@Path("cookbooks/{cookbookname}/{version}")
@ExceptionParser(ReturnVoidOnNotFoundOr404.class)
ListenableFuture<Void> deleteCookbook(
@PathParam("cookbookname") String cookbookName,
@PathParam("version") String version);
ListenableFuture<Void> deleteCookbook(@PathParam("cookbookname") String cookbookName,
@PathParam("version") String version);
/**
* @see ChefCookbook#getVersionsOfCookbook
@ -117,18 +127,17 @@ public interface ChefAsyncClient {
@ResponseParser(ParseValueSetFromJson.class)
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
ListenableFuture<Set<String>> getVersionsOfCookbook(
@PathParam("cookbookname") String cookbookName);
@PathParam("cookbookname") String cookbookName);
/**
* @see ChefCookbook#getCookbook
*/
@GET
@Path("cookbooks/{cookbookname}/{version}")
@ResponseParser(ParseCookbookFromJson.class)
@ResponseParser(ParseCookbookVersionFromJson.class)
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
ListenableFuture<Cookbook> getCookbook(
@PathParam("cookbookname") String cookbookName,
@PathParam("version") String version);
ListenableFuture<CookbookVersion> getCookbook(@PathParam("cookbookname") String cookbookName,
@PathParam("version") String version);
/**
* @see ChefClient#createClient
@ -137,7 +146,7 @@ public interface ChefAsyncClient {
@Path("clients")
@ResponseParser(ParseKeyFromJson.class)
ListenableFuture<String> createClient(
@BinderParam(BindClientnameToJsonPayload.class) String clientname);
@BinderParam(BindClientnameToJsonPayload.class) String clientname);
/**
* @see ChefClient#generateKeyForClient
@ -146,7 +155,7 @@ public interface ChefAsyncClient {
@Path("clients/{clientname}")
@ResponseParser(ParseKeyFromJson.class)
ListenableFuture<String> generateKeyForClient(
@PathParam("clientname") @BinderParam(BindGenerateKeyForClientToJsonPayload.class) String clientname);
@PathParam("clientname") @BinderParam(BindGenerateKeyForClientToJsonPayload.class) String clientname);
/**
* @see ChefClient#clientExists
@ -154,8 +163,7 @@ public interface ChefAsyncClient {
@HEAD
@Path("clients/{clientname}")
@ExceptionParser(ReturnFalseOnNotFoundOr404.class)
ListenableFuture<Boolean> clientExists(
@PathParam("clientname") String clientname);
ListenableFuture<Boolean> clientExists(@PathParam("clientname") String clientname);
/**
* @see ChefClient#getClient
@ -163,8 +171,7 @@ public interface ChefAsyncClient {
@GET
@Path("clients/{clientname}")
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
ListenableFuture<Boolean> getClient(
@PathParam("clientname") String clientname);
ListenableFuture<Boolean> getClient(@PathParam("clientname") String clientname);
/**
* @see ChefClient#deleteClient
@ -172,8 +179,7 @@ public interface ChefAsyncClient {
@DELETE
@Path("clients/{clientname}")
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
ListenableFuture<String> deleteClient(
@PathParam("clientname") String clientname);
ListenableFuture<String> deleteClient(@PathParam("clientname") String clientname);
/**
* @see ChefClient#listClients

View File

@ -44,8 +44,9 @@ package org.jclouds.chef;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import org.jclouds.chef.domain.Cookbook;
import org.jclouds.chef.domain.CookbookVersion;
import org.jclouds.chef.domain.Sandbox;
import org.jclouds.chef.domain.UploadSite;
import org.jclouds.concurrent.Timeout;
import org.jclouds.http.HttpResponseException;
import org.jclouds.rest.AuthorizationException;
@ -60,7 +61,9 @@ import org.jclouds.rest.AuthorizationException;
*/
@Timeout(duration = 30, timeUnit = TimeUnit.SECONDS)
public interface ChefClient {
Sandbox getUploadUrisForContent(Set<String> checksums);
UploadSite getUploadSiteForChecksums(Set<byte[]> md5s);
Sandbox closeSandbox(String id, boolean isCompleted);
/**
*
@ -69,14 +72,12 @@ 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();
/**
* Creates or updates (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
* matches the root directory path of the archive
@ -85,13 +86,12 @@ public interface ChefClient {
* <p/>
* "401 Unauthorized" if the caller is not a recognized user.
* <p/>
* "403 Forbidden" if you do not have permission to create
* cookbooks.
* "403 Forbidden" if you do not have permission to create cookbooks.
* @throws HttpResponseException
* "409 Conflict" if the cookbook already exists
*/
@Timeout(duration = 10, timeUnit = TimeUnit.MINUTES)
void updateCookbook(String cookbookName, String version, Cookbook cookbook);
void updateCookbook(String cookbookName, String version, CookbookVersion cookbook);
/**
* deletes an existing cookbook.
@ -101,8 +101,7 @@ 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.
*/
String deleteCookbook(String cookbookName, String version);
@ -114,14 +113,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 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
*
@ -129,22 +127,20 @@ 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.
*/
Cookbook getCookbook(String cookbookName, String version);
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
*/
@ -152,8 +148,7 @@ public interface ChefClient {
String 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,8 +156,7 @@ 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)
String generateKeyForClient(String name);

View File

@ -23,6 +23,7 @@
*/
package org.jclouds.chef.binders;
import javax.inject.Singleton;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
@ -36,6 +37,7 @@ import com.google.common.collect.ImmutableSet;
* @author Adrian Cole
*
*/
@Singleton
public class BindClientnameToJsonPayload extends BindToStringPayload {
@Override

View File

@ -23,6 +23,7 @@
*/
package org.jclouds.chef.binders;
import javax.inject.Singleton;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
@ -36,6 +37,7 @@ import com.google.common.collect.ImmutableSet;
* @author Adrian Cole
*
*/
@Singleton
public class BindGenerateKeyForClientToJsonPayload extends BindToStringPayload {
@Override

View File

@ -0,0 +1,50 @@
/**
*
* 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.HttpHeaders;
import javax.ws.rs.core.MediaType;
import org.jclouds.http.HttpRequest;
import org.jclouds.rest.binders.BindToStringPayload;
import com.google.common.collect.ImmutableSet;
/**
*
* @author Adrian Cole
*
*/
@Singleton
public class BindIsCompletedToJsonPayload extends BindToStringPayload {
@Override
public void bindToRequest(HttpRequest request, Object value) {
request.getHeaders().replaceValues(HttpHeaders.CONTENT_TYPE,
ImmutableSet.of(MediaType.APPLICATION_JSON));
super.bindToRequest(request, String.format("{\"is_completed\":\"%s\"}", value));
}
}

View File

@ -28,10 +28,12 @@ import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Set;
import javax.inject.Inject;
import javax.inject.Singleton;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import org.jclouds.encryption.EncryptionService;
import org.jclouds.http.HttpRequest;
import org.jclouds.rest.binders.BindToStringPayload;
@ -43,24 +45,30 @@ import com.google.common.collect.ImmutableSet;
* @author Adrian Cole
*/
@Singleton
public class BindChecksumsToJsonPayload extends BindToStringPayload {
public class BindMD5sToJsonPayload extends BindToStringPayload {
private final EncryptionService encryptionService;
@Inject
BindMD5sToJsonPayload(EncryptionService encryptionService) {
this.encryptionService = encryptionService;
}
@SuppressWarnings("unchecked")
public void bindToRequest(HttpRequest request, Object input) {
checkArgument(checkNotNull(input, "input") instanceof Set,
"this binder is only valid for Set!");
"this binder is only valid for Set!");
Set<String> sums = (Set<String>) input;
Set<byte[]> md5s = (Set<byte[]>) input;
StringBuilder builder = new StringBuilder();
builder.append("{\"checksums\":{");
for (String sum : sums)
builder.append(String.format("\"%s\":null,", sum));
for (byte[] md5 : md5s)
builder.append(String.format("\"%s\":null,", encryptionService.hex(md5)));
builder.deleteCharAt(builder.length() - 1);
builder.append("}}");
request.getHeaders().replaceValues(HttpHeaders.CONTENT_TYPE,
ImmutableSet.of(MediaType.APPLICATION_JSON));
ImmutableSet.of(MediaType.APPLICATION_JSON));
super.bindToRequest(request, builder.toString());
}

View File

@ -66,6 +66,8 @@ import org.jclouds.http.RequiresHttp;
import org.jclouds.http.annotation.ClientError;
import org.jclouds.http.annotation.Redirection;
import org.jclouds.http.annotation.ServerError;
import org.jclouds.http.functions.config.ParserModule.DateAdapter;
import org.jclouds.http.functions.config.ParserModule.Iso8601DateAdapter;
import org.jclouds.rest.ConfiguresRestClient;
import org.jclouds.rest.config.RestClientModule;
@ -126,4 +128,10 @@ public class BaseChefRestClientModule<S, A> extends RestClientModule<S, A> {
bind(HttpErrorHandler.class).annotatedWith(ServerError.class).to(ChefErrorHandler.class);
}
@Override
protected void configure() {
bind(DateAdapter.class).to(Iso8601DateAdapter.class);
super.configure();
}
}

View File

@ -0,0 +1,83 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ====================================================================
*/
package org.jclouds.chef.domain;
import java.net.URI;
import com.google.gson.annotations.SerializedName;
/**
*
* @author Adrian Cole
*/
public class ChecksumStatus {
private URI url;
@SerializedName("needs_upload")
private boolean needsUpload;
public ChecksumStatus(URI url, boolean needsUpload) {
this.url = url;
this.needsUpload = needsUpload;
}
public ChecksumStatus() {
}
public URI getUrl() {
return url;
}
public boolean needsUpload() {
return needsUpload;
}
@Override
public String toString() {
return "ChecksumStatus [needsUpload=" + needsUpload + ", url=" + url + "]";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (needsUpload ? 1231 : 1237);
result = prime * result + ((url == null) ? 0 : url.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
ChecksumStatus other = (ChecksumStatus) obj;
if (needsUpload != other.needsUpload)
return false;
if (url == null) {
if (other.url != null)
return false;
} else if (!url.equals(other.url))
return false;
return true;
}
}

View File

@ -29,12 +29,10 @@ import com.google.gson.annotations.SerializedName;
*
* @author Adrian Cole
*/
public class Cookbook {
public class CookbookVersion {
private String name;
private Set<Resource> definitions = Sets.newLinkedHashSet();
@SerializedName("json_class")
private String jsonClass;
private Set<Resource> attributes = Sets.newLinkedHashSet();
private Set<Resource> files = Sets.newLinkedHashSet();
private Metadata metadata;
@ -48,17 +46,28 @@ public class Cookbook {
private Set<Resource> recipes = Sets.newLinkedHashSet();
@SerializedName("root_files")
private Set<Resource> rootFiles = Sets.newLinkedHashSet();
@SerializedName("chef_type")
private String chefType;
public Cookbook(String name, Set<Resource> definitions, String jsonClass,
Set<Resource> attributes, Set<Resource> files, Metadata metadata,
Set<Resource> providers, String cookbookName, Set<Resource> resources,
Set<Resource> templates, Set<Resource> libraries, String version,
Set<Resource> recipes, Set<Resource> rootFiles, String chefType) {
// internal
@SuppressWarnings("unused")
@SerializedName("json_class")
private String _jsonClass = "Chef::CookbookVersion";
@SerializedName("chef_type")
@SuppressWarnings("unused")
private String _chefType = "cookbook_version";
public CookbookVersion(String cookbookName, String version) {
this.cookbookName = cookbookName;
this.version = version;
this.name = cookbookName + "-" + version;
}
public CookbookVersion(String name, Set<Resource> definitions, Set<Resource> attributes,
Set<Resource> files, Metadata metadata, Set<Resource> providers, String cookbookName,
Set<Resource> resources, Set<Resource> templates, Set<Resource> libraries,
String version, Set<Resource> recipes, Set<Resource> rootFiles) {
this.name = name;
Iterables.addAll(this.definitions, definitions);
this.jsonClass = jsonClass;
Iterables.addAll(this.attributes, attributes);
Iterables.addAll(this.files, files);
this.metadata = metadata;
@ -70,10 +79,9 @@ public class Cookbook {
this.version = version;
Iterables.addAll(this.recipes, recipes);
Iterables.addAll(this.rootFiles, rootFiles);
this.chefType = chefType;
}
public Cookbook() {
public CookbookVersion() {
}
@ -85,10 +93,6 @@ public class Cookbook {
return definitions;
}
public String getJsonClass() {
return jsonClass;
}
public Set<Resource> getAttributes() {
return attributes;
}
@ -133,37 +137,22 @@ public class Cookbook {
return rootFiles;
}
public String getChefType() {
return chefType;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((attributes == null) ? 0 : attributes.hashCode());
result = prime * result + ((chefType == null) ? 0 : chefType.hashCode());
result = prime * result
+ ((cookbookName == null) ? 0 : cookbookName.hashCode());
result = prime * result
+ ((definitions == null) ? 0 : definitions.hashCode());
result = prime * result + ((attributes == null) ? 0 : attributes.hashCode());
result = prime * result + ((cookbookName == null) ? 0 : cookbookName.hashCode());
result = prime * result + ((definitions == null) ? 0 : definitions.hashCode());
result = prime * result + ((files == null) ? 0 : files.hashCode());
result = prime * result
+ ((jsonClass == null) ? 0 : jsonClass.hashCode());
result = prime * result
+ ((libraries == null) ? 0 : libraries.hashCode());
result = prime * result + ((libraries == null) ? 0 : libraries.hashCode());
result = prime * result + ((metadata == null) ? 0 : metadata.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result
+ ((providers == null) ? 0 : providers.hashCode());
result = prime * result + ((providers == null) ? 0 : providers.hashCode());
result = prime * result + ((recipes == null) ? 0 : recipes.hashCode());
result = prime * result
+ ((resources == null) ? 0 : resources.hashCode());
result = prime * result
+ ((rootFiles == null) ? 0 : rootFiles.hashCode());
result = prime * result
+ ((templates == null) ? 0 : templates.hashCode());
result = prime * result + ((resources == null) ? 0 : resources.hashCode());
result = prime * result + ((rootFiles == null) ? 0 : rootFiles.hashCode());
result = prime * result + ((templates == null) ? 0 : templates.hashCode());
result = prime * result + ((version == null) ? 0 : version.hashCode());
return result;
}
@ -176,17 +165,12 @@ public class Cookbook {
return false;
if (getClass() != obj.getClass())
return false;
Cookbook other = (Cookbook) obj;
CookbookVersion other = (CookbookVersion) obj;
if (attributes == null) {
if (other.attributes != null)
return false;
} else if (!attributes.equals(other.attributes))
return false;
if (chefType == null) {
if (other.chefType != null)
return false;
} else if (!chefType.equals(other.chefType))
return false;
if (cookbookName == null) {
if (other.cookbookName != null)
return false;
@ -202,11 +186,6 @@ public class Cookbook {
return false;
} else if (!files.equals(other.files))
return false;
if (jsonClass == null) {
if (other.jsonClass != null)
return false;
} else if (!jsonClass.equals(other.jsonClass))
return false;
if (libraries == null) {
if (other.libraries != null)
return false;
@ -257,13 +236,11 @@ public class Cookbook {
@Override
public String toString() {
return "Cookbook [attributes=" + attributes + ", chefType=" + chefType
+ ", cookbookName=" + cookbookName + ", definitions=" + definitions
+ ", files=" + files + ", jsonClass=" + jsonClass + ", libraries="
+ libraries + ", metadata=" + metadata + ", name=" + name
+ ", providers=" + providers + ", recipes=" + recipes
+ ", resources=" + resources + ", rootFiles=" + rootFiles
+ ", templates=" + templates + ", version=" + version + "]";
return "Cookbook [attributes=" + attributes + ", cookbookName=" + cookbookName
+ ", definitions=" + definitions + ", files=" + files + ", libraries=" + libraries
+ ", metadata=" + metadata + ", name=" + name + ", providers=" + providers
+ ", recipes=" + recipes + ", resources=" + resources + ", rootFiles=" + rootFiles
+ ", templates=" + templates + ", version=" + version + "]";
}
}

View File

@ -33,8 +33,11 @@ public class Resource {
private String path;
private String specificity;
public Resource(String name, URI url, String checksum, String path,
String specificity) {
public Resource(String name, String checksum, String path) {
this(name, null, checksum, path, "default");
}
public Resource(String name, URI url, String checksum, String path, String specificity) {
this.name = name;
this.url = url;
this.checksum = checksum;
@ -52,6 +55,7 @@ public class Resource {
public URI getUrl() {
return url;
}
public String getChecksum() {
return checksum;
}
@ -71,8 +75,7 @@ public class Resource {
result = prime * result + ((checksum == null) ? 0 : checksum.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + ((path == null) ? 0 : path.hashCode());
result = prime * result
+ ((specificity == null) ? 0 : specificity.hashCode());
result = prime * result + ((specificity == null) ? 0 : specificity.hashCode());
result = prime * result + ((url == null) ? 0 : url.hashCode());
return result;
}
@ -116,8 +119,8 @@ public class Resource {
@Override
public String toString() {
return "Resource [checksum=" + checksum + ", name=" + name + ", path="
+ path + ", specificity=" + specificity + ", url=" + url + "]";
return "Resource [checksum=" + checksum + ", name=" + name + ", path=" + path
+ ", specificity=" + specificity + ", url=" + url + "]";
}
}

View File

@ -18,53 +18,86 @@
*/
package org.jclouds.chef.domain;
import java.net.URI;
import java.util.Map;
import java.util.Date;
import java.util.Set;
import com.google.common.collect.Maps;
import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;
import com.google.gson.annotations.SerializedName;
/**
* Cookbook object.
* Sandbox object.
*
* @author Adrian Cole
*/
public class Sandbox {
private URI uri;
private Map<String, ChecksumStatus> checksums = Maps.newLinkedHashMap();
@SerializedName("sandbox_id")
private String id;
public Sandbox(URI uri, Map<String, ChecksumStatus> checksums, String id) {
this.uri = uri;
this.checksums.putAll(checksums);
this.id = id;
@SerializedName("_rev")
private String rev;
@SerializedName("is_completed")
private boolean isCompleted;
@SerializedName("create_time")
private Date createTime;
private Set<String> checksums = Sets.newLinkedHashSet();
private String name;
private String guid;
// internal
@SuppressWarnings("unused")
@SerializedName("json_class")
private String _jsonClass = "Chef::Sandbox";
@SerializedName("chef_type")
@SuppressWarnings("unused")
private String _chefType = "sandbox";
public Sandbox(String rev, boolean isCompleted, Date createTime, Iterable<String> checksums,
String name, String guid) {
this.rev = rev;
this.isCompleted = isCompleted;
this.createTime = createTime;
Iterables.addAll(this.checksums, checksums);
this.name = name;
this.guid = guid;
}
public Sandbox() {
}
public URI getUri() {
return uri;
public String getRev() {
return rev;
}
public Map<String, ChecksumStatus> getChecksums() {
public boolean isCompleted() {
return isCompleted;
}
public Date getCreateTime() {
return createTime;
}
public Set<String> getChecksums() {
return checksums;
}
public String getId() {
return id;
public String getName() {
return name;
}
public String getGuid() {
return guid;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((checksums == null) ? 0 : checksums.hashCode());
result = prime * result + ((id == null) ? 0 : id.hashCode());
result = prime * result + ((uri == null) ? 0 : uri.hashCode());
result = prime * result + ((checksums == null) ? 0 : checksums.hashCode());
result = prime * result + ((createTime == null) ? 0 : createTime.hashCode());
result = prime * result + ((guid == null) ? 0 : guid.hashCode());
result = prime * result + (isCompleted ? 1231 : 1237);
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + ((rev == null) ? 0 : rev.hashCode());
return result;
}
@ -82,80 +115,34 @@ public class Sandbox {
return false;
} else if (!checksums.equals(other.checksums))
return false;
if (id == null) {
if (other.id != null)
if (createTime == null) {
if (other.createTime != null)
return false;
} else if (!id.equals(other.id))
} else if (!createTime.equals(other.createTime))
return false;
if (uri == null) {
if (other.uri != null)
if (guid == null) {
if (other.guid != null)
return false;
} else if (!uri.equals(other.uri))
} else if (!guid.equals(other.guid))
return false;
if (isCompleted != other.isCompleted)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (rev == null) {
if (other.rev != null)
return false;
} else if (!rev.equals(other.rev))
return false;
return true;
}
public static class ChecksumStatus {
private URI url;
@SerializedName("needs_upload")
private boolean needsUpload;
public ChecksumStatus(URI url, boolean needsUpload) {
this.url = url;
this.needsUpload = needsUpload;
}
public ChecksumStatus() {
}
public URI getUrl() {
return url;
}
public boolean needsUpload() {
return needsUpload;
}
@Override
public String toString() {
return "ChecksumStatus [needsUpload=" + needsUpload + ", url=" + url
+ "]";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (needsUpload ? 1231 : 1237);
result = prime * result + ((url == null) ? 0 : url.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
ChecksumStatus other = (ChecksumStatus) obj;
if (needsUpload != other.needsUpload)
return false;
if (url == null) {
if (other.url != null)
return false;
} else if (!url.equals(other.url))
return false;
return true;
}
}
@Override
public String toString() {
return "Sandbox [checksums=" + checksums + ", id=" + id + ", uri=" + uri
+ "]";
return "Sandbox [checksums=" + checksums + ", createTime=" + createTime + ", guid=" + guid
+ ", isCompleted=" + isCompleted + ", name=" + name + ", rev=" + rev + "]";
}
}

View File

@ -0,0 +1,103 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ====================================================================
*/
package org.jclouds.chef.domain;
import java.net.URI;
import java.util.Map;
import com.google.common.collect.Maps;
import com.google.gson.annotations.SerializedName;
/**
*
* @author Adrian Cole
*/
public class UploadSite {
private URI uri;
private Map<String, ChecksumStatus> checksums = Maps.newLinkedHashMap();
@SerializedName("sandbox_id")
private String sandboxId;
public UploadSite(URI uri, Map<String, ChecksumStatus> checksums, String sandboxId) {
this.uri = uri;
this.checksums.putAll(checksums);
this.sandboxId = sandboxId;
}
public UploadSite() {
}
public URI getUri() {
return uri;
}
public Map<String, ChecksumStatus> getChecksums() {
return checksums;
}
public String getSandboxId() {
return sandboxId;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((checksums == null) ? 0 : checksums.hashCode());
result = prime * result + ((sandboxId == null) ? 0 : sandboxId.hashCode());
result = prime * result + ((uri == null) ? 0 : uri.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
UploadSite other = (UploadSite) obj;
if (checksums == null) {
if (other.checksums != null)
return false;
} else if (!checksums.equals(other.checksums))
return false;
if (sandboxId == null) {
if (other.sandboxId != null)
return false;
} else if (!sandboxId.equals(other.sandboxId))
return false;
if (uri == null) {
if (other.uri != null)
return false;
} else if (!uri.equals(other.uri))
return false;
return true;
}
@Override
public String toString() {
return "UploadSite [checksums=" + checksums + ", id=" + sandboxId + ", uri=" + uri
+ "]";
}
}

View File

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

View File

@ -50,8 +50,7 @@ public class ParseSandboxFromJson extends ParseJson<Sandbox> {
@Override
protected Sandbox apply(InputStream stream) {
try {
return gson.fromJson(new InputStreamReader(stream, "UTF-8"),
Sandbox.class);
return gson.fromJson(new InputStreamReader(stream, "UTF-8"), Sandbox.class);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("jclouds requires UTF-8 encoding", e);
}

View File

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

View File

@ -31,14 +31,16 @@ import java.util.Properties;
import java.util.Set;
import org.jclouds.chef.config.ChefRestClientModule;
import org.jclouds.chef.domain.Cookbook;
import org.jclouds.chef.domain.CookbookVersion;
import org.jclouds.chef.filters.SignedHeaderAuth;
import org.jclouds.chef.filters.SignedHeaderAuthTest;
import org.jclouds.chef.functions.ParseCookbookFromJson;
import org.jclouds.chef.functions.ParseCookbookVersionFromJson;
import org.jclouds.chef.functions.ParseKeyFromJson;
import org.jclouds.chef.functions.ParseKeySetFromJson;
import org.jclouds.chef.functions.ParseSandboxFromJson;
import org.jclouds.chef.functions.ParseUploadSiteFromJson;
import org.jclouds.date.TimeStamp;
import org.jclouds.encryption.EncryptionService;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.RequiresHttp;
import org.jclouds.http.functions.CloseContentAndReturn;
@ -68,22 +70,44 @@ import com.google.inject.TypeLiteral;
@Test(groups = "unit", testName = "chef.ChefAsyncClientTest")
public class ChefAsyncClientTest extends RestClientTest<ChefAsyncClient> {
public void testGetUploadUrisForContent() throws SecurityException, NoSuchMethodException,
IOException {
Method method = ChefAsyncClient.class.getMethod("getUploadUrisForContent", Set.class);
GeneratedHttpRequest<ChefAsyncClient> httpRequest = processor.createRequest(method,
ImmutableSet.of("0189e76ccc476701d6b374e5a1a27347",
"0c5ecd7788cf4f6c7de2a57193897a6c", "1dda05ed139664f1f89b9dec482b77c0"));
public void testCloseSandbox() throws SecurityException, NoSuchMethodException, IOException {
Method method = ChefAsyncClient.class.getMethod("closeSandbox", String.class, boolean.class);
GeneratedHttpRequest<ChefAsyncClient> httpRequest = processor.createRequest(method,
"0189e76ccc476701d6b374e5a1a27347", true);
assertRequestLineEquals(httpRequest,
"PUT http://localhost:4000/sandboxes/0189e76ccc476701d6b374e5a1a27347 HTTP/1.1");
assertHeadersEqual(
httpRequest,
"Accept: application/json\nContent-Length: 23\nContent-Type: application/json\nX-Chef-Version: 0.9.6\n");
assertPayloadEquals(httpRequest, "{\"is_completed\":\"true\"}");
assertResponseParserClassEquals(method, httpRequest, ParseSandboxFromJson.class);
assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, null);
checkFilters(httpRequest);
}
public void testGetUploadSiteForChecksums() throws SecurityException, NoSuchMethodException,
IOException {
EncryptionService encservice = injector.getInstance(EncryptionService.class);
Method method = ChefAsyncClient.class.getMethod("getUploadSiteForChecksums", Set.class);
GeneratedHttpRequest<ChefAsyncClient> httpRequest = processor.createRequest(method,
ImmutableSet.of(encservice.fromHex("0189e76ccc476701d6b374e5a1a27347"), encservice
.fromHex("0c5ecd7788cf4f6c7de2a57193897a6c"), encservice
.fromHex("1dda05ed139664f1f89b9dec482b77c0")));
assertRequestLineEquals(httpRequest, "POST http://localhost:4000/sandboxes HTTP/1.1");
assertHeadersEqual(
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.6\n");
assertPayloadEquals(
httpRequest,
"{\"checksums\":{\"0189e76ccc476701d6b374e5a1a27347\":null,\"0c5ecd7788cf4f6c7de2a57193897a6c\":null,\"1dda05ed139664f1f89b9dec482b77c0\":null}}");
assertResponseParserClassEquals(method, httpRequest, ParseSandboxFromJson.class);
assertResponseParserClassEquals(method, httpRequest, ParseUploadSiteFromJson.class);
assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, null);
@ -97,10 +121,10 @@ public class ChefAsyncClientTest extends RestClientTest<ChefAsyncClient> {
"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");
assertHeadersEqual(httpRequest, "Accept: application/json\nX-Chef-Version: 0.9.6\n");
assertPayloadEquals(httpRequest, null);
assertResponseParserClassEquals(method, httpRequest, ParseCookbookFromJson.class);
assertResponseParserClassEquals(method, httpRequest, ParseCookbookVersionFromJson.class);
assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, ReturnNullOnNotFoundOr404.class);
@ -114,7 +138,7 @@ public class ChefAsyncClientTest extends RestClientTest<ChefAsyncClient> {
"cookbook", "1.0.0");
assertRequestLineEquals(httpRequest,
"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.6\n");
assertPayloadEquals(httpRequest, null);
assertResponseParserClassEquals(method, httpRequest, CloseContentAndReturn.class);
@ -127,18 +151,18 @@ public class ChefAsyncClientTest extends RestClientTest<ChefAsyncClient> {
public void testUpdateCookbook() throws SecurityException, NoSuchMethodException, IOException {
Method method = ChefAsyncClient.class.getMethod("updateCookbook", String.class, String.class,
Cookbook.class);
CookbookVersion.class);
GeneratedHttpRequest<ChefAsyncClient> httpRequest = processor.createRequest(method,
"cookbook", "1.0.1", new Cookbook());
"cookbook", "1.0.1", new CookbookVersion());
assertRequestLineEquals(httpRequest,
"PUT http://localhost:4000/cookbooks/cookbook/1.0.1 HTTP/1.1");
assertHeadersEqual(
httpRequest,
"Accept: application/json\nContent-Length: 134\nContent-Type: application/json\nX-Chef-Version: 0.9.0\n");
"Accept: application/json\nContent-Length: 202\nContent-Type: application/json\nX-Chef-Version: 0.9.6\n");
assertPayloadEquals(
httpRequest,
"{\"definitions\":[],\"attributes\":[],\"files\":[],\"providers\":[],\"resources\":[],\"templates\":[],\"libraries\":[],\"recipes\":[],\"root_files\":[]}");
"{\"definitions\":[],\"attributes\":[],\"files\":[],\"providers\":[],\"resources\":[],\"templates\":[],\"libraries\":[],\"recipes\":[],\"root_files\":[],\"json_class\":\"Chef::CookbookVersion\",\"chef_type\":\"cookbook_version\"}");
assertResponseParserClassEquals(method, httpRequest, CloseContentAndReturn.class);
assertSaxResponseParserClassEquals(method, null);
@ -153,7 +177,7 @@ public class ChefAsyncClientTest extends RestClientTest<ChefAsyncClient> {
GeneratedHttpRequest<ChefAsyncClient> httpRequest = processor.createRequest(method);
assertRequestLineEquals(httpRequest, "GET http://localhost:4000/cookbooks 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.6\n");
assertPayloadEquals(httpRequest, null);
assertResponseParserClassEquals(method, httpRequest, ParseKeySetFromJson.class);
@ -168,7 +192,7 @@ public class ChefAsyncClientTest extends RestClientTest<ChefAsyncClient> {
Method method = ChefAsyncClient.class.getMethod("clientExists", String.class);
GeneratedHttpRequest<ChefAsyncClient> httpRequest = processor.createRequest(method, "client");
assertRequestLineEquals(httpRequest, "HEAD http://localhost:4000/clients/client HTTP/1.1");
assertHeadersEqual(httpRequest, "Accept: application/json\nX-Chef-Version: 0.9.0\n");
assertHeadersEqual(httpRequest, "Accept: application/json\nX-Chef-Version: 0.9.6\n");
assertPayloadEquals(httpRequest, null);
assertResponseParserClassEquals(method, httpRequest, ReturnTrueIf2xx.class);
@ -183,7 +207,7 @@ public class ChefAsyncClientTest extends RestClientTest<ChefAsyncClient> {
Method method = ChefAsyncClient.class.getMethod("deleteClient", String.class);
GeneratedHttpRequest<ChefAsyncClient> httpRequest = processor.createRequest(method, "client");
assertRequestLineEquals(httpRequest, "DELETE http://localhost:4000/clients/client HTTP/1.1");
assertHeadersEqual(httpRequest, "Accept: application/json\nX-Chef-Version: 0.9.0\n");
assertHeadersEqual(httpRequest, "Accept: application/json\nX-Chef-Version: 0.9.6\n");
assertPayloadEquals(httpRequest, null);
assertResponseParserClassEquals(method, httpRequest, ReturnStringIf200.class);
@ -201,7 +225,7 @@ public class ChefAsyncClientTest extends RestClientTest<ChefAsyncClient> {
assertRequestLineEquals(httpRequest, "PUT http://localhost:4000/clients/client HTTP/1.1");
assertHeadersEqual(
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.6\n");
assertPayloadEquals(httpRequest, "{\"clientname\":\"client\", \"private_key\": true}");
assertResponseParserClassEquals(method, httpRequest, ParseKeyFromJson.class);
@ -219,7 +243,7 @@ public class ChefAsyncClientTest extends RestClientTest<ChefAsyncClient> {
assertRequestLineEquals(httpRequest, "POST http://localhost:4000/clients HTTP/1.1");
assertHeadersEqual(
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.6\n");
assertPayloadEquals(httpRequest, "{\"clientname\":\"client\"}");
assertResponseParserClassEquals(method, httpRequest, ParseKeyFromJson.class);
@ -235,7 +259,7 @@ public class ChefAsyncClientTest extends RestClientTest<ChefAsyncClient> {
GeneratedHttpRequest<ChefAsyncClient> httpRequest = processor.createRequest(method);
assertRequestLineEquals(httpRequest, "GET http://localhost:4000/clients 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.6\n");
assertPayloadEquals(httpRequest, null);
assertResponseParserClassEquals(method, httpRequest, ParseKeySetFromJson.class);

View File

@ -32,8 +32,15 @@ import java.io.InputStream;
import java.util.Properties;
import java.util.Set;
import org.jclouds.chef.domain.Cookbook;
import javax.ws.rs.core.HttpHeaders;
import org.jclouds.chef.domain.ChecksumStatus;
import org.jclouds.chef.domain.CookbookVersion;
import org.jclouds.chef.domain.Resource;
import org.jclouds.chef.domain.UploadSite;
import org.jclouds.http.Payload;
import org.jclouds.http.Payloads;
import org.jclouds.http.options.BaseHttpRequestOptions;
import org.jclouds.logging.log4j.config.Log4JLoggingModule;
import org.jclouds.rest.RestContext;
import org.jclouds.rest.RestContextFactory;
@ -109,6 +116,43 @@ public class ChefClientLiveTest {
clientConnection.getApi().clientExists(PREFIX);
}
@Test(dependsOnMethods = "testCreateClient")
public void testCreateNewCookbook() throws Exception {
Payload pom = Payloads.newFilePayload(new File(System.getProperty("user.dir"), "pom.xml"));
byte[] md5 = adminConnection.utils().encryption().md5(pom.getInput());
UploadSite site = adminConnection.getApi().getUploadSiteForChecksums(ImmutableSet.of(md5));
String md5Hex = adminConnection.utils().encryption().hex(md5);
try {
assert site.getChecksums().containsKey(md5Hex) : md5Hex + " not in " + site.getChecksums();
ChecksumStatus status = site.getChecksums().get(md5Hex);
if (status.needsUpload()) {
adminConnection.utils().http().put(status.getUrl(), pom,
new PutContentOptions(adminConnection.utils().encryption().base64(md5)));
}
adminConnection.getApi().closeSandbox(site.getSandboxId(), true);
} catch (RuntimeException e) {
adminConnection.getApi().closeSandbox(site.getSandboxId(), false);
}
CookbookVersion cookbook = new CookbookVersion("test", "0.0.0");
cookbook.getRootFiles().add(new Resource("pom.xml", md5Hex, "pom.xml"));
adminConnection.getApi().updateCookbook("test", "0.0.0", cookbook);
}
static class PutContentOptions extends BaseHttpRequestOptions {
public PutContentOptions(String md5Base64) {
super();
this.headers.replaceValues(HttpHeaders.ACCEPT, ImmutableSet.of("application/json"));
this.headers.replaceValues(HttpHeaders.CONTENT_TYPE, ImmutableSet
.of("application/x-binary"));
this.headers.replaceValues("Content-MD5", ImmutableSet.of(md5Base64));
}
}
@Test(dependsOnMethods = "testCreateClient")
public void testGenerateKeyForClient() throws Exception {
clientKey = validatorConnection.getApi().generateKeyForClient(PREFIX);
@ -123,19 +167,18 @@ public class ChefClientLiveTest {
assertNotNull(validatorConnection.getApi().clientExists(PREFIX));
}
@Test
@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);
Cookbook cookbookO = adminConnection.getApi().getCookbook(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 = adminConnection.utils().encryption().md5(stream);
String md5Hex = adminConnection.utils().encryption().hex(md5);
@ -155,10 +198,9 @@ public class ChefClientLiveTest {
for (String cookbook : adminConnection.getApi().listCookbooks())
for (String version : adminConnection.getApi().getVersionsOfCookbook(cookbook)) {
System.err.printf("%s/%s:%n", cookbook, version);
Cookbook cook = adminConnection.getApi().getCookbook(cookbook, version);
CookbookVersion cook = adminConnection.getApi().getCookbook(cookbook, version);
adminConnection.getApi().updateCookbook(cookbook, version, cook);
}
}
@Test(dependsOnMethods = "testUpdateCookbook")
@ -166,7 +208,7 @@ public class ChefClientLiveTest {
for (String cookbook : adminConnection.getApi().listCookbooks())
for (String version : adminConnection.getApi().getVersionsOfCookbook(cookbook)) {
System.err.printf("%s/%s:%n", cookbook, version);
Cookbook cook = adminConnection.getApi().getCookbook(cookbook, version);
CookbookVersion cook = adminConnection.getApi().getCookbook(cookbook, version);
adminConnection.getApi().deleteCookbook(cookbook, version);
assert adminConnection.getApi().getCookbook(cookbook, version) == null : cookbook
+ version;

View File

@ -30,6 +30,7 @@ import java.net.URI;
import javax.ws.rs.HttpMethod;
import org.jclouds.encryption.EncryptionService;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.functions.config.ParserModule;
import org.testng.annotations.Test;
@ -41,14 +42,15 @@ import com.google.inject.Injector;
/**
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "chef.BindChecksumsToJsonPayloadTest")
public class BindChecksumsToJsonPayloadTest {
@Test(groups = "unit", testName = "chef.BindMD5sToJsonPayloadTest")
public class BindMD5sToJsonPayloadTest {
Injector injector = Guice.createInjector(new ParserModule());
EncryptionService encservice = injector.getInstance(EncryptionService.class);
@Test(expectedExceptions = IllegalArgumentException.class)
public void testMustBeIterable() {
BindChecksumsToJsonPayload binder = new BindChecksumsToJsonPayload();
BindMD5sToJsonPayload binder = new BindMD5sToJsonPayload(encservice);
injector.injectMembers(binder);
HttpRequest request = new HttpRequest(HttpMethod.POST, URI
.create("http://localhost"));
@ -57,19 +59,19 @@ public class BindChecksumsToJsonPayloadTest {
@Test
public void testCorrect() {
BindChecksumsToJsonPayload binder = new BindChecksumsToJsonPayload();
BindMD5sToJsonPayload binder = new BindMD5sToJsonPayload(encservice);
injector.injectMembers(binder);
HttpRequest request = new HttpRequest(HttpMethod.POST, URI
.create("http://localhost"));
binder.bindToRequest(request, ImmutableSet.of("abddef", "12345"));
binder.bindToRequest(request, ImmutableSet.of(encservice.fromHex("abddef"), encservice.fromHex("1234")));
assertEquals(request.getPayload().getRawContent(),
"{\"checksums\":{\"abddef\":null,\"12345\":null}}");
"{\"checksums\":{\"abddef\":null,\"1234\":null}}");
}
@Test(expectedExceptions = { NullPointerException.class,
IllegalStateException.class })
public void testNullIsBad() {
BindChecksumsToJsonPayload binder = new BindChecksumsToJsonPayload();
BindMD5sToJsonPayload binder = new BindMD5sToJsonPayload(encservice);
injector.injectMembers(binder);
HttpRequest request = new HttpRequest(HttpMethod.POST, URI
.create("http://localhost"));

View File

@ -1,113 +0,0 @@
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,110 @@
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.CookbookVersion;
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 ParseCookbookVersionFromJson}
*
* @author Adrian Cole
*/
@Test(groups = "unit", sequential = true, testName = "chef.ParseCookbookVersionFromJsonTest")
public class ParseCookbookVersionFromJsonTest {
private ParseCookbookVersionFromJson handler;
@BeforeTest
protected void setUpInjector() throws IOException {
Injector injector = Guice.createInjector(new ParserModule());
handler = injector.getInstance(ParseCookbookVersionFromJson.class);
}
public void testBrew() throws IOException {
CookbookVersion cookbook = handler.apply(new HttpResponse(
ParseCookbookVersionFromJsonTest.class.getResourceAsStream("/brew-cookbook.json")));
assertEquals(cookbook, handler.apply(new HttpResponse(Utils.toInputStream(new Gson()
.toJson(cookbook)))));
}
public void testTomcat() {
CookbookVersion cookbook = handler
.apply(new HttpResponse(ParseCookbookVersionFromJsonTest.class
.getResourceAsStream("/tomcat-cookbook.json")));
assertEquals(cookbook, handler.apply(new HttpResponse(Utils.toInputStream(new Gson()
.toJson(cookbook)))));
}
public void testMysql() throws IOException {
CookbookVersion cookbook = handler.apply(new HttpResponse(
ParseCookbookVersionFromJsonTest.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(ParseCookbookVersionFromJsonTest.class
.getResourceAsStream("/apache-chef-demo-cookbook.json"))),
new CookbookVersion(
"apache-chef-demo-0.0.0",
ImmutableSet.<Resource> of(),
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"))));
}
}

View File

@ -3,16 +3,18 @@ package org.jclouds.chef.functions;
import static org.testng.Assert.assertEquals;
import java.io.IOException;
import java.net.URI;
import org.jclouds.chef.domain.Sandbox;
import org.jclouds.chef.domain.Sandbox.ChecksumStatus;
import org.jclouds.date.DateService;
import org.jclouds.http.HttpResponse;
import org.jclouds.http.functions.config.ParserModule;
import org.jclouds.http.functions.config.ParserModule.DateAdapter;
import org.jclouds.http.functions.config.ParserModule.Iso8601DateAdapter;
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.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Injector;
@ -25,30 +27,28 @@ import com.google.inject.Injector;
public class ParseSandboxFromJsonTest {
private ParseSandboxFromJson handler;
private DateService dateService;
@BeforeTest
protected void setUpInjector() throws IOException {
Injector injector = Guice.createInjector(new ParserModule());
Injector injector = Guice.createInjector(new ParserModule(), new AbstractModule() {
@Override
protected void configure() {
bind(DateAdapter.class).to(Iso8601DateAdapter.class);
}
});
handler = injector.getInstance(ParseSandboxFromJson.class);
dateService = injector.getInstance(DateService.class);
}
public void test() {
assertEquals(
handler.apply(new HttpResponse(ParseSandboxFromJsonTest.class
.getResourceAsStream("/sandbox.json"))),
new Sandbox(
URI
.create("https://api.opscode.com/organizations/jclouds/sandboxes/d454f71e2a5f400c808d0c5d04c2c88c"),
ImmutableMap
.<String, ChecksumStatus> of(
"0c5ecd7788cf4f6c7de2a57193897a6c",
new ChecksumStatus(
URI
.create("https://s3.amazonaws.com/opscode-platform-production-data/organization-486ca3ac66264fea926aa0b4ff74341c/sandbox-d454f71e2a5f400c808d0c5d04c2c88c/checksum-0c5ecd7788cf4f6c7de2a57193897a6c?AWSAccessKeyId=AKIAJOZTD2N26S7W6APA&Expires=1277344702&Signature=FtKyqvYEjhhEKmRY%2B0M8aGPMM7g%3D"),
true), "0189e76ccc476701d6b374e5a1a27347",
new ChecksumStatus(),
"1dda05ed139664f1f89b9dec482b77c0",
new ChecksumStatus()),
"d454f71e2a5f400c808d0c5d04c2c88c"));
assertEquals(handler.apply(new HttpResponse(ParseSandboxFromJsonTest.class
.getResourceAsStream("/sandbox.json"))), new Sandbox(
"1-8c27b0ea4c2b7aaedbb44cfbdfcc11b2", false, dateService
.iso8601SecondsDateParse("2010-07-07T03:36:00+00:00"), ImmutableSet
.<String> of(), "f9d6d9b72bae465890aae87969f98a9c",
"f9d6d9b72bae465890aae87969f98a9c"));
}
}

View File

@ -0,0 +1,52 @@
package org.jclouds.chef.functions;
import static org.testng.Assert.assertEquals;
import java.io.IOException;
import java.net.URI;
import org.jclouds.chef.domain.ChecksumStatus;
import org.jclouds.chef.domain.UploadSite;
import org.jclouds.http.HttpResponse;
import org.jclouds.http.functions.config.ParserModule;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableMap;
import com.google.inject.Guice;
import com.google.inject.Injector;
/**
* Tests behavior of {@code ParseUploadSiteFromJson}
*
* @author Adrian Cole
*/
@Test(groups = "unit", sequential = true, testName = "chef.ParseUploadSiteFromJsonTest")
public class ParseUploadSiteFromJsonTest {
private ParseUploadSiteFromJson handler;
@BeforeTest
protected void setUpInjector() throws IOException {
Injector injector = Guice.createInjector(new ParserModule());
handler = injector.getInstance(ParseUploadSiteFromJson.class);
}
public void test() {
assertEquals(
handler.apply(new HttpResponse(ParseUploadSiteFromJsonTest.class
.getResourceAsStream("/upload-site.json"))),
new UploadSite(
URI
.create("https://api.opscode.com/organizations/jclouds/sandboxes/d454f71e2a5f400c808d0c5d04c2c88c"),
ImmutableMap
.<String, ChecksumStatus> of(
"0c5ecd7788cf4f6c7de2a57193897a6c",
new ChecksumStatus(
URI
.create("https://s3.amazonaws.com/opscode-platform-production-data/organization-486ca3ac66264fea926aa0b4ff74341c/sandbox-d454f71e2a5f400c808d0c5d04c2c88c/checksum-0c5ecd7788cf4f6c7de2a57193897a6c?AWSAccessKeyId=AKIAJOZTD2N26S7W6APA&Expires=1277344702&Signature=FtKyqvYEjhhEKmRY%2B0M8aGPMM7g%3D"),
true), "0189e76ccc476701d6b374e5a1a27347",
new ChecksumStatus(), "1dda05ed139664f1f89b9dec482b77c0",
new ChecksumStatus()), "d454f71e2a5f400c808d0c5d04c2c88c"));
}
}

View File

@ -1,13 +1,12 @@
{
"uri": "https://api.opscode.com/organizations/jclouds/sandboxes/d454f71e2a5f400c808d0c5d04c2c88c",
"checksums": {
"0c5ecd7788cf4f6c7de2a57193897a6c": {
"url": "https://s3.amazonaws.com/opscode-platform-production-data/organization-486ca3ac66264fea926aa0b4ff74341c/sandbox-d454f71e2a5f400c808d0c5d04c2c88c/checksum-0c5ecd7788cf4f6c7de2a57193897a6c?AWSAccessKeyId=AKIAJOZTD2N26S7W6APA&Expires=1277344702&Signature=FtKyqvYEjhhEKmRY%2B0M8aGPMM7g%3D",
"needs_upload": true
}, "0189e76ccc476701d6b374e5a1a27347": {
"needs_upload": false
}, "1dda05ed139664f1f89b9dec482b77c0": {
"needs_upload": false
}
}, "sandbox_id": "d454f71e2a5f400c808d0c5d04c2c88c"
}
"_rev": "1-8c27b0ea4c2b7aaedbb44cfbdfcc11b2",
"json_class": "Chef::Sandbox",
"is_completed": false,
"create_time": "2010-07-07T03:36:00+00:00",
"chef_type": "sandbox",
"checksums": [],
"name": "f9d6d9b72bae465890aae87969f98a9c",
"guid": "f9d6d9b72bae465890aae87969f98a9c"
}

View File

@ -0,0 +1,13 @@
{
"uri": "https://api.opscode.com/organizations/jclouds/sandboxes/d454f71e2a5f400c808d0c5d04c2c88c",
"checksums": {
"0c5ecd7788cf4f6c7de2a57193897a6c": {
"url": "https://s3.amazonaws.com/opscode-platform-production-data/organization-486ca3ac66264fea926aa0b4ff74341c/sandbox-d454f71e2a5f400c808d0c5d04c2c88c/checksum-0c5ecd7788cf4f6c7de2a57193897a6c?AWSAccessKeyId=AKIAJOZTD2N26S7W6APA&Expires=1277344702&Signature=FtKyqvYEjhhEKmRY%2B0M8aGPMM7g%3D",
"needs_upload": true
}, "0189e76ccc476701d6b374e5a1a27347": {
"needs_upload": false
}, "1dda05ed139664f1f89b9dec482b77c0": {
"needs_upload": false
}
}, "sandbox_id": "d454f71e2a5f400c808d0c5d04c2c88c"
}