diff --git a/apis/chef/src/main/java/org/jclouds/chef/ChefAsyncClient.java b/apis/chef/src/main/java/org/jclouds/chef/ChefAsyncClient.java index 0a6406ce8d..bd265e4f17 100644 --- a/apis/chef/src/main/java/org/jclouds/chef/ChefAsyncClient.java +++ b/apis/chef/src/main/java/org/jclouds/chef/ChefAsyncClient.java @@ -32,6 +32,7 @@ import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.core.MediaType; +import org.jclouds.chef.binders.AdminFlagFromCreateClientOptions; import org.jclouds.chef.binders.BindAdminClientToJsonPayload; import org.jclouds.chef.binders.BindChecksumsToJsonPayload; import org.jclouds.chef.binders.BindClientnameToJsonPayload; @@ -55,10 +56,13 @@ import org.jclouds.chef.functions.ParseSearchClientsFromJson; import org.jclouds.chef.functions.ParseSearchDatabagFromJson; import org.jclouds.chef.functions.ParseSearchNodesFromJson; import org.jclouds.chef.functions.ParseSearchRolesFromJson; +import org.jclouds.chef.options.CreateClientOptions; import org.jclouds.rest.annotations.BinderParam; import org.jclouds.rest.annotations.ExceptionParser; import org.jclouds.rest.annotations.Headers; +import org.jclouds.rest.annotations.MapBinder; import org.jclouds.rest.annotations.ParamParser; +import org.jclouds.rest.annotations.PayloadParam; import org.jclouds.rest.annotations.RequestFilters; import org.jclouds.rest.annotations.ResponseParser; import org.jclouds.rest.annotations.Unwrap; @@ -153,14 +157,14 @@ public interface ChefAsyncClient { */ @POST @Path("/clients") - ListenableFuture createClient(@BinderParam(BindNameToJsonPayload.class) String clientname); - - /** - * @see ChefClient#createAdminClient(String) - */ + @MapBinder(BindToJsonPayload.class) + ListenableFuture createClient(@PayloadParam("name") String clientname); + @POST @Path("/clients") - ListenableFuture createAdminClient(@BinderParam(BindAdminClientToJsonPayload.class) String clientname); + @MapBinder(BindToJsonPayload.class) + ListenableFuture createClient(@PayloadParam("name") String clientname, + @PayloadParam("admin") @ParamParser(AdminFlagFromCreateClientOptions.class) CreateClientOptions options); /** * @see ChefClient#generateKeyForClient diff --git a/apis/chef/src/main/java/org/jclouds/chef/ChefClient.java b/apis/chef/src/main/java/org/jclouds/chef/ChefClient.java index db2781696b..43eba7d37d 100644 --- a/apis/chef/src/main/java/org/jclouds/chef/ChefClient.java +++ b/apis/chef/src/main/java/org/jclouds/chef/ChefClient.java @@ -23,6 +23,10 @@ import java.util.List; import java.util.Set; import java.util.concurrent.TimeUnit; +import javax.ws.rs.POST; +import javax.ws.rs.Path; + +import org.jclouds.chef.binders.AdminFlagFromCreateClientOptions; import org.jclouds.chef.domain.Client; import org.jclouds.chef.domain.CookbookVersion; import org.jclouds.chef.domain.DatabagItem; @@ -31,12 +35,18 @@ import org.jclouds.chef.domain.Role; import org.jclouds.chef.domain.Sandbox; import org.jclouds.chef.domain.SearchResult; import org.jclouds.chef.domain.UploadSandbox; +import org.jclouds.chef.options.CreateClientOptions; import org.jclouds.concurrent.Timeout; import org.jclouds.http.HttpResponseException; import org.jclouds.rest.AuthorizationException; import org.jclouds.rest.annotations.BinderParam; +import org.jclouds.rest.annotations.MapBinder; +import org.jclouds.rest.annotations.ParamParser; +import org.jclouds.rest.annotations.PayloadParam; import org.jclouds.rest.binders.BindToJsonPayload; +import com.google.common.util.concurrent.ListenableFuture; + /** * Provides synchronous access to Chef. *

@@ -155,7 +165,7 @@ public interface ChefClient { * "409 Conflict" if the client already exists */ @Timeout(duration = 120, timeUnit = TimeUnit.SECONDS) - Client createAdminClient(String name); + Client createClient(String name, CreateClientOptions options); /** * generate a new key-pair for this client, and return the new private key in diff --git a/apis/chef/src/main/java/org/jclouds/chef/binders/AdminFlagFromCreateClientOptions.java b/apis/chef/src/main/java/org/jclouds/chef/binders/AdminFlagFromCreateClientOptions.java new file mode 100644 index 0000000000..5ab1a9f3ca --- /dev/null +++ b/apis/chef/src/main/java/org/jclouds/chef/binders/AdminFlagFromCreateClientOptions.java @@ -0,0 +1,38 @@ +/** + * + * Copyright (C) 2010 Cloud Conscious, LLC. + * + * ==================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ==================================================================== + */ + +package org.jclouds.chef.binders; + +import javax.inject.Singleton; + +import org.jclouds.chef.options.CreateClientOptions; + +import com.google.common.base.Function; + +/** + * @author Ignasi Barrera + */ +@Singleton +public class AdminFlagFromCreateClientOptions implements Function { + + public String apply(Object from) { + return String.valueOf(((CreateClientOptions) from).isAdmin()); + } + +} \ No newline at end of file diff --git a/apis/chef/src/main/java/org/jclouds/chef/options/CreateClientOptions.java b/apis/chef/src/main/java/org/jclouds/chef/options/CreateClientOptions.java new file mode 100644 index 0000000000..0b9b278380 --- /dev/null +++ b/apis/chef/src/main/java/org/jclouds/chef/options/CreateClientOptions.java @@ -0,0 +1,71 @@ +/** + * + * Copyright (C) 2010 Cloud Conscious, LLC. + * + * ==================================================================== + * 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.options; + + +/** + * Options for the create client method. + * + * @author Ignasi Barrera + */ +public class CreateClientOptions implements Cloneable +{ + /** Administrator flag. This flag will be ignored in Opscode Hosted Chef. */ + private boolean admin; + + public CreateClientOptions() { + } + + CreateClientOptions(final boolean admin) { + super(); + this.admin = admin; + } + + public boolean isAdmin() { + return admin; + } + + public CreateClientOptions admin() { + this.admin = true; + return this; + } + + @Override + protected Object clone() throws CloneNotSupportedException { + return new CreateClientOptions(admin); + } + + @Override + public String toString() { + return "[admin=" + admin + "]"; + } + + public static class Builder + { + /** + * @see CreateClientOptions#admin() + */ + public static CreateClientOptions admin() { + CreateClientOptions options = new CreateClientOptions(); + return options.admin(); + } + + } + +} diff --git a/apis/chef/src/main/java/org/jclouds/chef/test/TransientChefAsyncClient.java b/apis/chef/src/main/java/org/jclouds/chef/test/TransientChefAsyncClient.java index c75cd3a1c4..d6fc9488e8 100644 --- a/apis/chef/src/main/java/org/jclouds/chef/test/TransientChefAsyncClient.java +++ b/apis/chef/src/main/java/org/jclouds/chef/test/TransientChefAsyncClient.java @@ -48,6 +48,7 @@ import org.jclouds.chef.domain.Role; import org.jclouds.chef.domain.Sandbox; import org.jclouds.chef.domain.SearchResult; import org.jclouds.chef.domain.UploadSandbox; +import org.jclouds.chef.options.CreateClientOptions; import org.jclouds.util.Utils; import com.google.common.base.Function; @@ -121,9 +122,9 @@ public class TransientChefAsyncClient implements ChefAsyncClient { // TODO Auto-generated method stub return null; } - + @Override - public ListenableFuture createAdminClient(String clientname) { + public ListenableFuture createClient(String clientname, CreateClientOptions options) { // TODO Auto-generated method stub return null; } diff --git a/apis/chef/src/test/java/org/jclouds/chef/BaseChefClientLiveTest.java b/apis/chef/src/test/java/org/jclouds/chef/BaseChefClientLiveTest.java index 99ae51d4ff..ba778a08f7 100644 --- a/apis/chef/src/test/java/org/jclouds/chef/BaseChefClientLiveTest.java +++ b/apis/chef/src/test/java/org/jclouds/chef/BaseChefClientLiveTest.java @@ -39,6 +39,7 @@ import org.jclouds.chef.domain.Resource; import org.jclouds.chef.domain.Role; import org.jclouds.chef.domain.SearchResult; import org.jclouds.chef.domain.UploadSandbox; +import org.jclouds.chef.options.CreateClientOptions; import org.jclouds.crypto.CryptoStreams; import org.jclouds.crypto.Pems; import org.jclouds.io.InputSuppliers; @@ -211,6 +212,19 @@ public abstract class BaseChefClientLiveTest { assert clients.contains(PREFIX) : String.format("client %s not in %s", PREFIX, clients); assertNotNull(getClientConnection().getClient(PREFIX)); } + + @Test + public void testCreateAdminClient() throws Exception { + getAdminConnection().deleteClient(PREFIX); + + clientKey = Pems.pem(getAdminConnection().createClient(PREFIX, CreateClientOptions.Builder.admin()).getPrivateKey()); + + recreateClientConnection(); + getClientConnection().clientExists(PREFIX); + Set clients = getAdminConnection().listClients(); + assert clients.contains(PREFIX) : String.format("client %s not in %s", PREFIX, clients); + assertNotNull(getClientConnection().getClient(PREFIX)); + } @Test(dependsOnMethods = "testCreateClient") public void testClientExists() throws Exception { diff --git a/apis/chef/src/test/java/org/jclouds/chef/ChefAsyncClientTest.java b/apis/chef/src/test/java/org/jclouds/chef/ChefAsyncClientTest.java index b814f1d45d..d75d784b6e 100644 --- a/apis/chef/src/test/java/org/jclouds/chef/ChefAsyncClientTest.java +++ b/apis/chef/src/test/java/org/jclouds/chef/ChefAsyncClientTest.java @@ -38,6 +38,7 @@ import org.jclouds.chef.functions.ParseSearchClientsFromJson; import org.jclouds.chef.functions.ParseSearchDatabagFromJson; import org.jclouds.chef.functions.ParseSearchNodesFromJson; import org.jclouds.chef.functions.ParseSearchRolesFromJson; +import org.jclouds.chef.options.CreateClientOptions; import org.jclouds.crypto.CryptoStreams; import org.jclouds.date.TimeStamp; import org.jclouds.http.HttpRequest; @@ -222,6 +223,22 @@ public class ChefAsyncClientTest extends RestClientTest { checkFilters(httpRequest); } + + public void testCreateAdminClient() throws SecurityException, NoSuchMethodException, IOException { + Method method = ChefAsyncClient.class.getMethod("createClient", String.class); + GeneratedHttpRequest httpRequest = processor.createRequest(method, "client", CreateClientOptions.Builder.admin()); + + assertRequestLineEquals(httpRequest, "POST http://localhost:4000/clients HTTP/1.1"); + assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\nX-Chef-Version: 0.9.8\n"); + assertPayloadEquals(httpRequest, "{\"name\":\"client\", \"admin\": true}", "application/json", false); + + assertResponseParserClassEquals(method, httpRequest, ParseJson.class); + assertSaxResponseParserClassEquals(method, null); + assertExceptionParserClassEquals(method, null); + + checkFilters(httpRequest); + + } public void testListClients() throws SecurityException, NoSuchMethodException, IOException { Method method = ChefAsyncClient.class.getMethod("listClients");