Issue 191: fixed cookbook creation as it was missing metadata section

This commit is contained in:
Adrian Cole 2010-07-07 08:57:57 -07:00
parent 99e14159a0
commit 7efb519de9
7 changed files with 56 additions and 198 deletions

View File

@ -38,7 +38,7 @@ import javax.ws.rs.core.MediaType;
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.binders.BindIsCompletedToJsonPayload; import org.jclouds.chef.binders.BindIsCompletedToJsonPayload;
import org.jclouds.chef.binders.BindMD5sToJsonPayload; import org.jclouds.chef.binders.BindHexEncodedMD5sToJsonPayload;
import org.jclouds.chef.domain.CookbookVersion; import org.jclouds.chef.domain.CookbookVersion;
import org.jclouds.chef.domain.Sandbox; import org.jclouds.chef.domain.Sandbox;
import org.jclouds.chef.domain.UploadSite; import org.jclouds.chef.domain.UploadSite;
@ -81,8 +81,8 @@ public interface ChefAsyncClient {
@POST @POST
@Path("sandboxes") @Path("sandboxes")
@ResponseParser(ParseUploadSiteFromJson.class) @ResponseParser(ParseUploadSiteFromJson.class)
ListenableFuture<UploadSite> getUploadSiteForChecksums( ListenableFuture<UploadSite> getUploadSiteForHexEncodedChecksums(
@BinderParam(BindMD5sToJsonPayload.class) Set<byte[]> md5s); @BinderParam(BindHexEncodedMD5sToJsonPayload.class) Set<String> hexEncodedmd5s);
/** /**
* @see ChefClient#closeSandbox * @see ChefClient#closeSandbox

View File

@ -61,7 +61,7 @@ import org.jclouds.rest.AuthorizationException;
*/ */
@Timeout(duration = 30, timeUnit = TimeUnit.SECONDS) @Timeout(duration = 30, timeUnit = TimeUnit.SECONDS)
public interface ChefClient { public interface ChefClient {
UploadSite getUploadSiteForChecksums(Set<byte[]> md5s); UploadSite getUploadSiteForHexEncodedChecksums(Set<String> hexEncodedmd5s);
Sandbox closeSandbox(String id, boolean isCompleted); Sandbox closeSandbox(String id, boolean isCompleted);

View File

@ -1,75 +0,0 @@
/**
*
* 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 static com.google.common.base.Preconditions.checkArgument;
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;
import com.google.common.collect.ImmutableSet;
/**
*
*
* @author Adrian Cole
*/
@Singleton
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!");
Set<byte[]> md5s = (Set<byte[]>) input;
StringBuilder builder = new StringBuilder();
builder.append("{\"checksums\":{");
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));
super.bindToRequest(request, builder.toString());
}
}

View File

@ -35,7 +35,7 @@ public class CookbookVersion {
private Set<Resource> definitions = Sets.newLinkedHashSet(); private Set<Resource> definitions = Sets.newLinkedHashSet();
private Set<Resource> attributes = Sets.newLinkedHashSet(); private Set<Resource> attributes = Sets.newLinkedHashSet();
private Set<Resource> files = Sets.newLinkedHashSet(); private Set<Resource> files = Sets.newLinkedHashSet();
private Metadata metadata; private Metadata metadata = new Metadata();
private Set<Resource> providers = Sets.newLinkedHashSet(); private Set<Resource> providers = Sets.newLinkedHashSet();
@SerializedName("cookbook_name") @SerializedName("cookbook_name")
private String cookbookName; private String cookbookName;

View File

@ -40,7 +40,6 @@ import org.jclouds.chef.functions.ParseKeySetFromJson;
import org.jclouds.chef.functions.ParseSandboxFromJson; import org.jclouds.chef.functions.ParseSandboxFromJson;
import org.jclouds.chef.functions.ParseUploadSiteFromJson; import org.jclouds.chef.functions.ParseUploadSiteFromJson;
import org.jclouds.date.TimeStamp; import org.jclouds.date.TimeStamp;
import org.jclouds.encryption.EncryptionService;
import org.jclouds.http.HttpRequest; import org.jclouds.http.HttpRequest;
import org.jclouds.http.RequiresHttp; import org.jclouds.http.RequiresHttp;
import org.jclouds.http.functions.CloseContentAndReturn; import org.jclouds.http.functions.CloseContentAndReturn;
@ -90,15 +89,14 @@ public class ChefAsyncClientTest extends RestClientTest<ChefAsyncClient> {
} }
public void testGetUploadSiteForChecksums() throws SecurityException, NoSuchMethodException, public void testGetUploadSiteForHexEncodedChecksums() throws SecurityException,
IOException { NoSuchMethodException, IOException {
EncryptionService encservice = injector.getInstance(EncryptionService.class);
Method method = ChefAsyncClient.class.getMethod("getUploadSiteForChecksums", Set.class); Method method = ChefAsyncClient.class.getMethod("getUploadSiteForHexEncodedChecksums",
Set.class);
GeneratedHttpRequest<ChefAsyncClient> httpRequest = processor.createRequest(method, GeneratedHttpRequest<ChefAsyncClient> httpRequest = processor.createRequest(method,
ImmutableSet.of(encservice.fromHex("0189e76ccc476701d6b374e5a1a27347"), encservice ImmutableSet.of("0189e76ccc476701d6b374e5a1a27347",
.fromHex("0c5ecd7788cf4f6c7de2a57193897a6c"), encservice "0c5ecd7788cf4f6c7de2a57193897a6c", "1dda05ed139664f1f89b9dec482b77c0"));
.fromHex("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,
@ -153,17 +151,16 @@ public class ChefAsyncClientTest extends RestClientTest<ChefAsyncClient> {
Method method = ChefAsyncClient.class.getMethod("updateCookbook", String.class, String.class, Method method = ChefAsyncClient.class.getMethod("updateCookbook", String.class, String.class,
CookbookVersion.class); CookbookVersion.class);
GeneratedHttpRequest<ChefAsyncClient> httpRequest = processor.createRequest(method, GeneratedHttpRequest<ChefAsyncClient> httpRequest = processor.createRequest(method,
"cookbook", "1.0.1", new CookbookVersion()); "cookbook", "1.0.1", new CookbookVersion("cookbook", "1.0.1"));
assertRequestLineEquals(httpRequest, assertRequestLineEquals(httpRequest,
"PUT http://localhost:4000/cookbooks/cookbook/1.0.1 HTTP/1.1"); "PUT http://localhost:4000/cookbooks/cookbook/1.0.1 HTTP/1.1");
assertHeadersEqual( assertHeadersEqual(
httpRequest, httpRequest,
"Accept: application/json\nContent-Length: 202\nContent-Type: application/json\nX-Chef-Version: 0.9.6\n"); "Accept: application/json\nContent-Length: 446\nContent-Type: application/json\nX-Chef-Version: 0.9.6\n");
assertPayloadEquals( assertPayloadEquals(
httpRequest, httpRequest,
"{\"definitions\":[],\"attributes\":[],\"files\":[],\"providers\":[],\"resources\":[],\"templates\":[],\"libraries\":[],\"recipes\":[],\"root_files\":[],\"json_class\":\"Chef::CookbookVersion\",\"chef_type\":\"cookbook_version\"}"); "{\"name\":\"cookbook-1.0.1\",\"definitions\":[],\"attributes\":[],\"files\":[],\"metadata\":{\"suggestions\":{},\"dependencies\":{},\"conflicting\":{},\"providing\":{},\"platforms\":{},\"recipes\":{},\"replacing\":{},\"groupings\":{},\"attributes\":{},\"recommendations\":{}},\"providers\":[],\"cookbook_name\":\"cookbook\",\"resources\":[],\"templates\":[],\"libraries\":[],\"version\":\"1.0.1\",\"recipes\":[],\"root_files\":[],\"json_class\":\"Chef::CookbookVersion\",\"chef_type\":\"cookbook_version\"}");
assertResponseParserClassEquals(method, httpRequest, CloseContentAndReturn.class); assertResponseParserClassEquals(method, httpRequest, CloseContentAndReturn.class);
assertSaxResponseParserClassEquals(method, null); assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, null); assertExceptionParserClassEquals(method, null);

View File

@ -116,31 +116,9 @@ public class ChefClientLiveTest {
clientConnection.getApi().clientExists(PREFIX); clientConnection.getApi().clientExists(PREFIX);
} }
@Test(dependsOnMethods = "testCreateClient") // TODO when uploading files, there are a few headers that are needed or else request signing
public void testCreateNewCookbook() throws Exception { // fails
Payload pom = Payloads.newFilePayload(new File(System.getProperty("user.dir"), "pom.xml")); // make this a method on ChefClient to avoid exposing these details to the api users
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 { static class PutContentOptions extends BaseHttpRequestOptions {
public PutContentOptions(String md5Base64) { public PutContentOptions(String md5Base64) {
@ -153,6 +131,45 @@ public class ChefClientLiveTest {
} }
// TODO: clean up this api so that it is simpler
public void testCreateNewCookbook() throws Exception {
// define the file you want in the cookbook
Payload pom = Payloads.newFilePayload(new File(System.getProperty("user.dir"), "pom.xml"));
// get an md5 so that you can see if the server already has it or not
byte[] md5 = adminConnection.utils().encryption().md5(pom.getInput());
String md5Hex = adminConnection.utils().encryption().hex(md5);
// request an upload site for this file
// TODO: this json ball is not named, and is different than SandBox, using UploadSite for now
UploadSite site = adminConnection.getApi().getUploadSiteForHexEncodedChecksums(ImmutableSet.of(md5Hex));
try {
assert site.getChecksums().containsKey(md5Hex) : md5Hex + " not in " + site.getChecksums();
ChecksumStatus status = site.getChecksums().get(md5Hex);
if (status.needsUpload()) {
// upload the file, adding a few other headers it was signed with
// note that we need to convert the md5 to base64
adminConnection.utils().http().put(status.getUrl(), pom,
new PutContentOptions(adminConnection.utils().encryption().base64(md5)));
}
// if we were able to get here, close the sandbox
adminConnection.getApi().closeSandbox(site.getSandboxId(), true);
} catch (RuntimeException e) {
adminConnection.getApi().closeSandbox(site.getSandboxId(), false);
}
// create a new cookbook
CookbookVersion cookbook = new CookbookVersion("test3", "0.0.0");
cookbook.getRootFiles().add(new Resource("pom.xml", md5Hex, "pom.xml"));
// upload the cookbook to the remote server
adminConnection.getApi().updateCookbook("test3", "0.0.0", cookbook);
}
@Test(dependsOnMethods = "testCreateClient") @Test(dependsOnMethods = "testCreateClient")
public void testGenerateKeyForClient() throws Exception { public void testGenerateKeyForClient() throws Exception {
clientKey = validatorConnection.getApi().generateKeyForClient(PREFIX); clientKey = validatorConnection.getApi().generateKeyForClient(PREFIX);

View File

@ -1,81 +0,0 @@
/**
*
* 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 static org.testng.Assert.assertEquals;
import java.io.File;
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;
import com.google.common.collect.ImmutableSet;
import com.google.inject.Guice;
import com.google.inject.Injector;
/**
* @author Adrian Cole
*/
@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() {
BindMD5sToJsonPayload binder = new BindMD5sToJsonPayload(encservice);
injector.injectMembers(binder);
HttpRequest request = new HttpRequest(HttpMethod.POST, URI
.create("http://localhost"));
binder.bindToRequest(request, new File("foo"));
}
@Test
public void testCorrect() {
BindMD5sToJsonPayload binder = new BindMD5sToJsonPayload(encservice);
injector.injectMembers(binder);
HttpRequest request = new HttpRequest(HttpMethod.POST, URI
.create("http://localhost"));
binder.bindToRequest(request, ImmutableSet.of(encservice.fromHex("abddef"), encservice.fromHex("1234")));
assertEquals(request.getPayload().getRawContent(),
"{\"checksums\":{\"abddef\":null,\"1234\":null}}");
}
@Test(expectedExceptions = { NullPointerException.class,
IllegalStateException.class })
public void testNullIsBad() {
BindMD5sToJsonPayload binder = new BindMD5sToJsonPayload(encservice);
injector.injectMembers(binder);
HttpRequest request = new HttpRequest(HttpMethod.POST, URI
.create("http://localhost"));
binder.bindToRequest(request, null);
}
}