mirror of https://github.com/apache/jclouds.git
Issue 191: added client and user support
This commit is contained in:
parent
8234c94f37
commit
551a3639b5
|
@ -23,20 +23,26 @@
|
|||
*/
|
||||
package org.jclouds.chef;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.DELETE;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.HEAD;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.PUT;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
|
||||
import org.jclouds.chef.binders.BindClientnameToJsonPayload;
|
||||
import org.jclouds.chef.binders.BindGenerateKeyForClientToJsonPayload;
|
||||
import org.jclouds.chef.domain.Organization;
|
||||
import org.jclouds.chef.domain.User;
|
||||
import org.jclouds.chef.filters.SignedHeaderAuth;
|
||||
import org.jclouds.chef.functions.OrganizationName;
|
||||
import org.jclouds.chef.functions.ParseKeyFromJson;
|
||||
import org.jclouds.chef.functions.ParseKeySetFromJson;
|
||||
import org.jclouds.chef.functions.ParseOrganizationFromJson;
|
||||
import org.jclouds.chef.functions.ParseUserFromJson;
|
||||
import org.jclouds.chef.functions.Username;
|
||||
|
@ -47,7 +53,9 @@ import org.jclouds.rest.annotations.ParamParser;
|
|||
import org.jclouds.rest.annotations.RequestFilters;
|
||||
import org.jclouds.rest.annotations.ResponseParser;
|
||||
import org.jclouds.rest.binders.BindToJsonPayload;
|
||||
import org.jclouds.rest.functions.ReturnFalseOnNotFoundOr404;
|
||||
import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
|
||||
import org.jclouds.rest.functions.ReturnVoidOnNotFoundOr404;
|
||||
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
|
||||
|
@ -63,9 +71,53 @@ import com.google.common.util.concurrent.ListenableFuture;
|
|||
@RequestFilters(SignedHeaderAuth.class)
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public interface ChefAsyncClient {
|
||||
/**
|
||||
* @see ChefClient#createClientInOrganization
|
||||
*/
|
||||
@POST
|
||||
@Path("/organizations/{orgname}/clients")
|
||||
@ResponseParser(ParseKeyFromJson.class)
|
||||
ListenableFuture<String> createClientInOrg(@PathParam("orgname") String orgname,
|
||||
@BinderParam(BindClientnameToJsonPayload.class) String clientname);
|
||||
|
||||
/**
|
||||
* @see ChefAsyncClient#createUser
|
||||
* @see ChefClient#generateKeyForClientInOrg
|
||||
*/
|
||||
@PUT
|
||||
@Path("/organizations/{orgname}/clients/{clientname}")
|
||||
@ResponseParser(ParseKeyFromJson.class)
|
||||
ListenableFuture<String> generateKeyForClientInOrg(
|
||||
@PathParam("orgname") String orgname,
|
||||
@PathParam("clientname") @BinderParam(BindGenerateKeyForClientToJsonPayload.class) String clientname);
|
||||
|
||||
/**
|
||||
* @see ChefClient#clientExistsInOrg
|
||||
*/
|
||||
@HEAD
|
||||
@Path("/organizations/{orgname}/clients/{clientname}")
|
||||
@ExceptionParser(ReturnFalseOnNotFoundOr404.class)
|
||||
ListenableFuture<Boolean> clientExistsInOrg(@PathParam("orgname") String orgname,
|
||||
@PathParam("clientname") String clientname);
|
||||
|
||||
/**
|
||||
* @see ChefClient#deleteClientInOrg
|
||||
*/
|
||||
@DELETE
|
||||
@Path("/organizations/{orgname}/clients/{clientname}")
|
||||
@ExceptionParser(ReturnVoidOnNotFoundOr404.class)
|
||||
ListenableFuture<Void> deleteClientInOrg(@PathParam("orgname") String orgname,
|
||||
@PathParam("clientname") String clientname);
|
||||
|
||||
/**
|
||||
* @see ChefClient#createClientInOrganization
|
||||
*/
|
||||
@GET
|
||||
@Path("/organizations/{orgname}/clients")
|
||||
@ResponseParser(ParseKeySetFromJson.class)
|
||||
ListenableFuture<Set<String>> listClientsInOrg(@PathParam("orgname") String orgname);
|
||||
|
||||
/**
|
||||
* @see ChefClient#createUser
|
||||
*/
|
||||
@POST
|
||||
@Path("/users")
|
||||
|
@ -73,7 +125,7 @@ public interface ChefAsyncClient {
|
|||
ListenableFuture<String> createUser(@BinderParam(BindToJsonPayload.class) User user);
|
||||
|
||||
/**
|
||||
* @see ChefAsyncClient#updateUser
|
||||
* @see ChefClient#updateUser
|
||||
*/
|
||||
@PUT
|
||||
@Path("/users/{username}")
|
||||
|
@ -82,7 +134,7 @@ public interface ChefAsyncClient {
|
|||
@PathParam("username") @ParamParser(Username.class) @BinderParam(BindToJsonPayload.class) User user);
|
||||
|
||||
/**
|
||||
* @see ChefAsyncClient#getUser
|
||||
* @see ChefClient#getUser
|
||||
*/
|
||||
@GET
|
||||
@Path("/users/{username}")
|
||||
|
@ -91,7 +143,7 @@ public interface ChefAsyncClient {
|
|||
ListenableFuture<User> getUser(@PathParam("username") String username);
|
||||
|
||||
/**
|
||||
* @see ChefAsyncClient#deleteUser
|
||||
* @see ChefClient#deleteUser
|
||||
*/
|
||||
@DELETE
|
||||
@Path("/users/{username}")
|
||||
|
@ -99,38 +151,37 @@ public interface ChefAsyncClient {
|
|||
ListenableFuture<User> deleteUser(@PathParam("username") String username);
|
||||
|
||||
/**
|
||||
* @see ChefAsyncClient#createOrganization
|
||||
* @see ChefClient#createOrg
|
||||
*/
|
||||
@POST
|
||||
@Path("/organizations")
|
||||
@ResponseParser(ParseKeyFromJson.class)
|
||||
ListenableFuture<String> createOrganization(
|
||||
@BinderParam(BindToJsonPayload.class) Organization org);
|
||||
ListenableFuture<String> createOrg(@BinderParam(BindToJsonPayload.class) Organization org);
|
||||
|
||||
/**
|
||||
* @see ChefAsyncClient#updateOrganization
|
||||
* @see ChefClient#updateOrg
|
||||
*/
|
||||
@PUT
|
||||
@Path("/organizations/{orgname}")
|
||||
@ResponseParser(ParseOrganizationFromJson.class)
|
||||
ListenableFuture<Organization> updateOrganization(
|
||||
ListenableFuture<Organization> updateOrg(
|
||||
@PathParam("orgname") @ParamParser(OrganizationName.class) @BinderParam(BindToJsonPayload.class) Organization org);
|
||||
|
||||
/**
|
||||
* @see ChefAsyncClient#getOrganization
|
||||
* @see ChefClient#getOrg
|
||||
*/
|
||||
@GET
|
||||
@Path("/organizations/{orgname}")
|
||||
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
|
||||
@ResponseParser(ParseOrganizationFromJson.class)
|
||||
ListenableFuture<Organization> getOrganization(@PathParam("orgname") String orgname);
|
||||
ListenableFuture<Organization> getOrg(@PathParam("orgname") String orgname);
|
||||
|
||||
/**
|
||||
* @see ChefAsyncClient#deleteOrganization
|
||||
* @see ChefClient#deleteOrg
|
||||
*/
|
||||
@DELETE
|
||||
@Path("/organizations/{orgname}")
|
||||
@ResponseParser(ParseOrganizationFromJson.class)
|
||||
ListenableFuture<Organization> deleteOrganization(@PathParam("orgname") String orgname);
|
||||
ListenableFuture<Organization> deleteOrg(@PathParam("orgname") String orgname);
|
||||
|
||||
}
|
||||
|
|
|
@ -41,11 +41,13 @@
|
|||
*/
|
||||
package org.jclouds.chef;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.jclouds.chef.domain.Organization;
|
||||
import org.jclouds.chef.domain.User;
|
||||
import org.jclouds.concurrent.Timeout;
|
||||
import org.jclouds.http.HttpResponseException;
|
||||
import org.jclouds.rest.AuthorizationException;
|
||||
import org.jclouds.rest.ResourceNotFoundException;
|
||||
|
||||
|
@ -57,9 +59,34 @@ import org.jclouds.rest.ResourceNotFoundException;
|
|||
* @see <a href="TODO: insert URL of Chef documentation" />
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Timeout(duration = 4, timeUnit = TimeUnit.SECONDS)
|
||||
@Timeout(duration = 30, timeUnit = TimeUnit.SECONDS)
|
||||
public interface ChefClient {
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* @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.
|
||||
* @throws HttpResponseException
|
||||
* "409 Conflict" if the client already exists
|
||||
*/
|
||||
@Timeout(duration = 120, timeUnit = TimeUnit.SECONDS)
|
||||
String createClientInOrg(String orgname, String name);
|
||||
|
||||
@Timeout(duration = 120, timeUnit = TimeUnit.SECONDS)
|
||||
String generateKeyForClientInOrg(String orgname, String name);
|
||||
|
||||
Set<String> listClientsInOrg(String orgname);
|
||||
|
||||
boolean clientExistsInOrg(String orgname, String name);
|
||||
|
||||
void deleteClientInOrg(String orgname, String name);
|
||||
|
||||
/**
|
||||
* creates a new user
|
||||
*
|
||||
|
@ -118,7 +145,7 @@ public interface ChefClient {
|
|||
* <p/>
|
||||
* "403 Forbidden" if the caller is not authorized to create a organization.
|
||||
*/
|
||||
String createOrganization(Organization organization);
|
||||
String createOrg(Organization organization);
|
||||
|
||||
/**
|
||||
* updates an existing organization. Note: you must have update rights on the organization.
|
||||
|
@ -131,14 +158,14 @@ public interface ChefClient {
|
|||
* @throws ResourceNotFoundException
|
||||
* if the organization does not exist.
|
||||
*/
|
||||
Organization updateOrganization(Organization organization);
|
||||
Organization updateOrg(Organization organization);
|
||||
|
||||
/**
|
||||
* retrieves an existing organization. Note: you must have update rights on the organization.
|
||||
*
|
||||
* @return null, if the organization is not found
|
||||
*/
|
||||
Organization getOrganization(String organizationname);
|
||||
Organization getOrg(String organizationname);
|
||||
|
||||
/**
|
||||
* deletes an existing organization. Note: you must have delete rights on the organization.
|
||||
|
@ -153,5 +180,5 @@ public interface ChefClient {
|
|||
* <p/>
|
||||
* “404 Not Found” if the organization does not exist.
|
||||
*/
|
||||
Organization deleteOrganization(String organizationname);
|
||||
Organization deleteOrg(String organizationname);
|
||||
}
|
||||
|
|
|
@ -49,8 +49,8 @@ public class ChefContextBuilder extends RestContextBuilder<ChefAsyncClient, Chef
|
|||
super(providerName, new TypeLiteral<ChefAsyncClient>() {
|
||||
}, new TypeLiteral<ChefClient>() {
|
||||
}, props);
|
||||
checkNotNull(properties.getProperty(ChefConstants.PROPERTY_CHEF_USER_ID));
|
||||
checkNotNull(properties.getProperty(ChefConstants.PROPERTY_CHEF_PRIVATE_KEY));
|
||||
checkNotNull(properties.getProperty(ChefConstants.PROPERTY_CHEF_IDENTITY));
|
||||
checkNotNull(properties.getProperty(ChefConstants.PROPERTY_CHEF_RSA_KEY));
|
||||
}
|
||||
|
||||
protected void addClientModule(List<Module> modules) {
|
||||
|
|
|
@ -49,15 +49,15 @@ import com.google.inject.Module;
|
|||
*/
|
||||
public class ChefContextFactory {
|
||||
|
||||
public static RestContext<ChefAsyncClient, ChefClient> createContext(String user, String password,
|
||||
public static RestContext<ChefAsyncClient, ChefClient> createContext(String identity, String rsaKey,
|
||||
Module... modules) {
|
||||
return new ChefContextBuilder("chef", new ChefPropertiesBuilder(user, password).build())
|
||||
return new ChefContextBuilder("chef", new ChefPropertiesBuilder(identity, rsaKey).build())
|
||||
.withModules(modules).buildContext();
|
||||
}
|
||||
|
||||
public static RestContext<ChefAsyncClient, ChefClient> createContext(URI endpoint, String user, String password,
|
||||
public static RestContext<ChefAsyncClient, ChefClient> createContext(URI endpoint, String identity, String rsaKey,
|
||||
Module... modules) {
|
||||
return new ChefContextBuilder("chef", new ChefPropertiesBuilder(user, password).withEndpoint(endpoint).build())
|
||||
return new ChefContextBuilder("chef", new ChefPropertiesBuilder(identity, rsaKey).withEndpoint(endpoint).build())
|
||||
.withModules(modules).buildContext();
|
||||
}
|
||||
|
||||
|
|
|
@ -25,9 +25,9 @@ package org.jclouds.chef;
|
|||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static org.jclouds.chef.reference.ChefConstants.PROPERTY_CHEF_ENDPOINT;
|
||||
import static org.jclouds.chef.reference.ChefConstants.PROPERTY_CHEF_PRIVATE_KEY;
|
||||
import static org.jclouds.chef.reference.ChefConstants.PROPERTY_CHEF_RSA_KEY;
|
||||
import static org.jclouds.chef.reference.ChefConstants.PROPERTY_CHEF_TIMESTAMP_INTERVAL;
|
||||
import static org.jclouds.chef.reference.ChefConstants.PROPERTY_CHEF_USER_ID;
|
||||
import static org.jclouds.chef.reference.ChefConstants.PROPERTY_CHEF_IDENTITY;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Properties;
|
||||
|
@ -52,14 +52,14 @@ public class ChefPropertiesBuilder extends PropertiesBuilder {
|
|||
super(properties);
|
||||
}
|
||||
|
||||
public ChefPropertiesBuilder(String id, String secret) {
|
||||
public ChefPropertiesBuilder(String identity, String rsaKey) {
|
||||
super();
|
||||
withCredentials(id, secret);
|
||||
withCredentials(identity, rsaKey);
|
||||
}
|
||||
|
||||
public ChefPropertiesBuilder withCredentials(String id, String secret) {
|
||||
properties.setProperty(PROPERTY_CHEF_USER_ID, checkNotNull(id, "user"));
|
||||
properties.setProperty(PROPERTY_CHEF_PRIVATE_KEY, checkNotNull(secret, "password"));
|
||||
public ChefPropertiesBuilder withCredentials(String identity, String rsaKey) {
|
||||
properties.setProperty(PROPERTY_CHEF_IDENTITY, checkNotNull(identity, "identity"));
|
||||
properties.setProperty(PROPERTY_CHEF_RSA_KEY, checkNotNull(rsaKey, "password"));
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
/**
|
||||
*
|
||||
* 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.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
|
||||
*
|
||||
*/
|
||||
public class BindClientnameToJsonPayload extends BindToStringPayload {
|
||||
|
||||
@Override
|
||||
public void bindToRequest(HttpRequest request, Object payload) {
|
||||
request.getHeaders().replaceValues(HttpHeaders.CONTENT_TYPE,
|
||||
ImmutableSet.of(MediaType.APPLICATION_JSON));
|
||||
super.bindToRequest(request, String.format("{\"clientname\":\"%s\"}", payload));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
/**
|
||||
*
|
||||
* 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.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
|
||||
*
|
||||
*/
|
||||
public class BindGenerateKeyForClientToJsonPayload extends BindToStringPayload {
|
||||
|
||||
@Override
|
||||
public void bindToRequest(HttpRequest request, Object payload) {
|
||||
request.getHeaders().replaceValues(HttpHeaders.CONTENT_TYPE,
|
||||
ImmutableSet.of(MediaType.APPLICATION_JSON));
|
||||
super.bindToRequest(request, String.format("{\"clientname\":\"%s\", \"private_key\": true}",
|
||||
payload));
|
||||
}
|
||||
|
||||
}
|
|
@ -77,7 +77,7 @@ public class ChefContextModule extends AbstractModule {
|
|||
@Provides
|
||||
@Singleton
|
||||
RestContext<ChefAsyncClient, ChefClient> provideContext(Closer closer, ChefAsyncClient asyncApi,
|
||||
ChefClient syncApi, @Chef URI endPoint, @Named(ChefConstants.PROPERTY_CHEF_USER_ID) String account) {
|
||||
ChefClient syncApi, @Chef URI endPoint, @Named(ChefConstants.PROPERTY_CHEF_IDENTITY) String account) {
|
||||
return new RestContextImpl<ChefAsyncClient, ChefClient>(closer, asyncApi, syncApi, endPoint, account);
|
||||
}
|
||||
|
||||
|
|
|
@ -57,12 +57,17 @@ import org.bouncycastle.openssl.PEMReader;
|
|||
import org.jclouds.chef.Chef;
|
||||
import org.jclouds.chef.ChefAsyncClient;
|
||||
import org.jclouds.chef.ChefClient;
|
||||
import org.jclouds.chef.handlers.ChefErrorHandler;
|
||||
import org.jclouds.chef.reference.ChefConstants;
|
||||
import org.jclouds.concurrent.ExpirableSupplier;
|
||||
import org.jclouds.concurrent.internal.SyncProxy;
|
||||
import org.jclouds.date.DateService;
|
||||
import org.jclouds.date.TimeStamp;
|
||||
import org.jclouds.http.HttpErrorHandler;
|
||||
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.rest.ConfiguresRestClient;
|
||||
import org.jclouds.rest.RestClientFactory;
|
||||
|
||||
|
@ -95,7 +100,7 @@ public class ChefRestClientModule extends AbstractModule {
|
|||
final DateService dateService) {
|
||||
return new ExpirableSupplier<String>(new Supplier<String>() {
|
||||
public String get() {
|
||||
return dateService.iso8601DateFormat();
|
||||
return dateService.iso8601SecondsDateFormat();
|
||||
}
|
||||
}, seconds, TimeUnit.SECONDS);
|
||||
}
|
||||
|
@ -108,7 +113,7 @@ public class ChefRestClientModule extends AbstractModule {
|
|||
|
||||
@Provides
|
||||
@Singleton
|
||||
public PrivateKey provideKey(@Named(ChefConstants.PROPERTY_CHEF_PRIVATE_KEY) String key)
|
||||
public PrivateKey provideKey(@Named(ChefConstants.PROPERTY_CHEF_RSA_KEY) String key)
|
||||
throws IOException {
|
||||
// TODO do this without adding a provider
|
||||
Security.addProvider(new BouncyCastleProvider());
|
||||
|
@ -135,9 +140,14 @@ public class ChefRestClientModule extends AbstractModule {
|
|||
protected URI provideURI(@Named(ChefConstants.PROPERTY_CHEF_ENDPOINT) String endpoint) {
|
||||
return URI.create(endpoint);
|
||||
}
|
||||
|
||||
|
||||
protected void bindErrorHandlers() {
|
||||
// TODO
|
||||
bind(HttpErrorHandler.class).annotatedWith(Redirection.class).to(
|
||||
ChefErrorHandler.class);
|
||||
bind(HttpErrorHandler.class).annotatedWith(ClientError.class).to(
|
||||
ChefErrorHandler.class);
|
||||
bind(HttpErrorHandler.class).annotatedWith(ServerError.class).to(
|
||||
ChefErrorHandler.class);
|
||||
}
|
||||
|
||||
protected void bindRetryHandlers() {
|
||||
|
|
|
@ -36,6 +36,7 @@ public class User implements Comparable<User> {
|
|||
@SerializedName("display_name")
|
||||
private String displayName;
|
||||
private String email;
|
||||
private String password;
|
||||
|
||||
public User(String username) {
|
||||
this.username = username;
|
||||
|
@ -107,6 +108,7 @@ public class User implements Comparable<User> {
|
|||
result = prime * result + ((firstName == null) ? 0 : firstName.hashCode());
|
||||
result = prime * result + ((lastName == null) ? 0 : lastName.hashCode());
|
||||
result = prime * result + ((middleName == null) ? 0 : middleName.hashCode());
|
||||
result = prime * result + ((password == null) ? 0 : password.hashCode());
|
||||
result = prime * result + ((username == null) ? 0 : username.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
@ -145,6 +147,11 @@ public class User implements Comparable<User> {
|
|||
return false;
|
||||
} else if (!middleName.equals(other.middleName))
|
||||
return false;
|
||||
if (password == null) {
|
||||
if (other.password != null)
|
||||
return false;
|
||||
} else if (!password.equals(other.password))
|
||||
return false;
|
||||
if (username == null) {
|
||||
if (other.username != null)
|
||||
return false;
|
||||
|
@ -159,4 +166,12 @@ public class User implements Comparable<User> {
|
|||
+ firstName + ", middleName=" + middleName + ", lastName=" + lastName + ", email="
|
||||
+ email + "]";
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -77,7 +77,7 @@ public class SignedHeaderAuth implements HttpRequestFilter {
|
|||
|
||||
@Inject
|
||||
public SignedHeaderAuth(SignatureWire signatureWire,
|
||||
@Named(ChefConstants.PROPERTY_CHEF_USER_ID) String userId, PrivateKey privateKey,
|
||||
@Named(ChefConstants.PROPERTY_CHEF_IDENTITY) String userId, PrivateKey privateKey,
|
||||
@TimeStamp Provider<String> timeStampProvider, EncryptionService encryptionService) {
|
||||
this.signatureWire = signatureWire;
|
||||
this.userId = userId;
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
/**
|
||||
*
|
||||
* 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.IOException;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.jclouds.http.HttpResponse;
|
||||
import org.jclouds.util.Utils;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Throwables;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Singleton
|
||||
public class ParseErrorFromJsonOrNull implements Function<HttpResponse, String> {
|
||||
Pattern pattern = Pattern.compile(".*error\": *\"([^\"]+)\".*");
|
||||
|
||||
@Override
|
||||
public String apply(HttpResponse response) {
|
||||
if (response.getContent() == null)
|
||||
return null;
|
||||
try {
|
||||
return parse(Utils.toStringAndClose(response.getContent()));
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
try {
|
||||
response.getContent().close();
|
||||
} catch (IOException e) {
|
||||
Throwables.propagate(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String parse(String in) {
|
||||
Matcher matcher = pattern.matcher(in);
|
||||
while (matcher.find()) {
|
||||
return matcher.group(1);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -42,7 +42,7 @@ import com.google.common.base.Throwables;
|
|||
*/
|
||||
@Singleton
|
||||
public class ParseKeyFromJson implements Function<HttpResponse, String> {
|
||||
Pattern pattern = Pattern.compile(".*private_key\": \"([^\"]+)\".*");
|
||||
Pattern pattern = Pattern.compile(".*private_key\": *\"([^\"]+)\".*");
|
||||
|
||||
@Override
|
||||
public String apply(HttpResponse response) {
|
||||
|
@ -62,7 +62,7 @@ public class ParseKeyFromJson implements Function<HttpResponse, String> {
|
|||
public String parse(String in) {
|
||||
Matcher matcher = pattern.matcher(in);
|
||||
while (matcher.find()) {
|
||||
return matcher.group(1);
|
||||
return matcher.group(1).replaceAll("\\\\n", "\n");
|
||||
}
|
||||
assert false : String.format("pattern: %s didn't match %s", pattern, in);
|
||||
return null;
|
||||
|
|
|
@ -0,0 +1,81 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* ====================================================================
|
||||
*/
|
||||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
* ====================================================================
|
||||
*/
|
||||
package org.jclouds.chef.functions;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.jclouds.http.functions.ParseJson;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
|
||||
/**
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Singleton
|
||||
public class ParseKeySetFromJson extends ParseJson<Set<String>> {
|
||||
@Inject
|
||||
public ParseKeySetFromJson(Gson gson) {
|
||||
super(gson);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
protected Set<String> apply(InputStream stream) {
|
||||
try {
|
||||
Type map = new TypeToken<Map<String, String>>() {
|
||||
}.getType();
|
||||
return ((Map<String, String>) gson.fromJson(new InputStreamReader(stream, "UTF-8"), map))
|
||||
.keySet();
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new RuntimeException("jclouds requires UTF-8 encoding", e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* ====================================================================
|
||||
*/
|
||||
package org.jclouds.chef.handlers;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.jclouds.chef.functions.ParseErrorFromJsonOrNull;
|
||||
import org.jclouds.http.HttpCommand;
|
||||
import org.jclouds.http.HttpErrorHandler;
|
||||
import org.jclouds.http.HttpResponse;
|
||||
import org.jclouds.http.HttpResponseException;
|
||||
import org.jclouds.logging.Logger;
|
||||
import org.jclouds.rest.AuthorizationException;
|
||||
import org.jclouds.rest.ResourceNotFoundException;
|
||||
|
||||
import com.google.common.io.Closeables;
|
||||
|
||||
/**
|
||||
* This will parse and set an appropriate exception on the command object.
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*
|
||||
*/
|
||||
@Singleton
|
||||
public class ChefErrorHandler implements HttpErrorHandler {
|
||||
@Resource
|
||||
protected Logger logger = Logger.NULL;
|
||||
private final ParseErrorFromJsonOrNull errorParser;
|
||||
|
||||
@Inject
|
||||
ChefErrorHandler(ParseErrorFromJsonOrNull errorParser) {
|
||||
this.errorParser = errorParser;
|
||||
}
|
||||
|
||||
public void handleError(HttpCommand command, HttpResponse response) {
|
||||
String message = errorParser.apply(response);
|
||||
Exception exception = message != null ? new HttpResponseException(command, response, message)
|
||||
: new HttpResponseException(command, response);
|
||||
try {
|
||||
message = message != null ? message : String.format("%s -> %s", command.getRequest()
|
||||
.getRequestLine(), response.getStatusLine());
|
||||
switch (response.getStatusCode()) {
|
||||
case 401:
|
||||
case 403:
|
||||
exception = new AuthorizationException(message, exception);
|
||||
break;
|
||||
case 404:
|
||||
if (!command.getRequest().getMethod().equals("DELETE")) {
|
||||
exception = new ResourceNotFoundException(message, exception);
|
||||
}
|
||||
break;
|
||||
}
|
||||
} finally {
|
||||
Closeables.closeQuietly(response.getContent());
|
||||
command.setException(exception);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -48,11 +48,20 @@ package org.jclouds.chef.reference;
|
|||
*/
|
||||
public interface ChefConstants {
|
||||
public static final String PROPERTY_CHEF_ENDPOINT = "jclouds.chef.endpoint";
|
||||
public static final String PROPERTY_CHEF_USER_ID = "jclouds.chef.user-id";
|
||||
/**
|
||||
* There are generally 3 types of identities
|
||||
* <ul>
|
||||
* <li>validator - used to create clients within an organization; {@code orgname}-validator</li>
|
||||
* <li>client - scoped to an organization, used on nodes to run chef</li>
|
||||
* <li>user - used to run commands like knife and access cookbook sites</li>
|
||||
* </ul>
|
||||
*
|
||||
*/
|
||||
public static final String PROPERTY_CHEF_IDENTITY = "jclouds.chef.identity";
|
||||
/**
|
||||
* The PEM-encoded key
|
||||
*/
|
||||
public static final String PROPERTY_CHEF_PRIVATE_KEY = "jclouds.chef.private-key";
|
||||
public static final String PROPERTY_CHEF_RSA_KEY = "jclouds.chef.rsa-key";
|
||||
|
||||
/**
|
||||
* how often to refresh timestamps in seconds.
|
||||
|
|
|
@ -35,12 +35,17 @@ import org.jclouds.chef.domain.User;
|
|||
import org.jclouds.chef.filters.SignedHeaderAuth;
|
||||
import org.jclouds.chef.filters.SignedHeaderAuthTest;
|
||||
import org.jclouds.chef.functions.ParseKeyFromJson;
|
||||
import org.jclouds.chef.functions.ParseKeySetFromJson;
|
||||
import org.jclouds.chef.functions.ParseOrganizationFromJson;
|
||||
import org.jclouds.chef.functions.ParseUserFromJson;
|
||||
import org.jclouds.date.TimeStamp;
|
||||
import org.jclouds.http.functions.CloseContentAndReturn;
|
||||
import org.jclouds.http.functions.ReturnTrueIf2xx;
|
||||
import org.jclouds.logging.config.NullLoggingModule;
|
||||
import org.jclouds.rest.RestClientTest;
|
||||
import org.jclouds.rest.functions.ReturnFalseOnNotFoundOr404;
|
||||
import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
|
||||
import org.jclouds.rest.functions.ReturnVoidOnNotFoundOr404;
|
||||
import org.jclouds.rest.internal.GeneratedHttpRequest;
|
||||
import org.jclouds.rest.internal.RestAnnotationProcessor;
|
||||
import org.jclouds.util.Jsr330;
|
||||
|
@ -58,6 +63,98 @@ import com.google.inject.TypeLiteral;
|
|||
*/
|
||||
@Test(groups = "unit", testName = "chef.ChefAsyncClientTest")
|
||||
public class ChefAsyncClientTest extends RestClientTest<ChefAsyncClient> {
|
||||
public void testClientExistsInOrg() throws SecurityException, NoSuchMethodException, IOException {
|
||||
Method method = ChefAsyncClient.class.getMethod("clientExistsInOrg", String.class,
|
||||
String.class);
|
||||
GeneratedHttpRequest<ChefAsyncClient> httpRequest = processor.createRequest(method, "org",
|
||||
"client");
|
||||
assertRequestLineEquals(httpRequest,
|
||||
"HEAD https://api.opscode.com/organizations/org/clients/client HTTP/1.1");
|
||||
assertHeadersEqual(httpRequest, "Accept: application/json\n");
|
||||
assertPayloadEquals(httpRequest, null);
|
||||
|
||||
assertResponseParserClassEquals(method, httpRequest, ReturnTrueIf2xx.class);
|
||||
assertSaxResponseParserClassEquals(method, null);
|
||||
assertExceptionParserClassEquals(method, ReturnFalseOnNotFoundOr404.class);
|
||||
|
||||
checkFilters(httpRequest);
|
||||
|
||||
}
|
||||
|
||||
public void testDeleteClientInOrg() throws SecurityException, NoSuchMethodException, IOException {
|
||||
Method method = ChefAsyncClient.class.getMethod("deleteClientInOrg", String.class,
|
||||
String.class);
|
||||
GeneratedHttpRequest<ChefAsyncClient> httpRequest = processor.createRequest(method, "org",
|
||||
"client");
|
||||
assertRequestLineEquals(httpRequest,
|
||||
"DELETE https://api.opscode.com/organizations/org/clients/client HTTP/1.1");
|
||||
assertHeadersEqual(httpRequest, "Accept: application/json\n");
|
||||
assertPayloadEquals(httpRequest, null);
|
||||
|
||||
assertResponseParserClassEquals(method, httpRequest, CloseContentAndReturn.class);
|
||||
assertSaxResponseParserClassEquals(method, null);
|
||||
assertExceptionParserClassEquals(method, ReturnVoidOnNotFoundOr404.class);
|
||||
|
||||
checkFilters(httpRequest);
|
||||
|
||||
}
|
||||
|
||||
public void testGenerateKeyForClientInOrg() throws SecurityException, NoSuchMethodException,
|
||||
IOException {
|
||||
Method method = ChefAsyncClient.class.getMethod("generateKeyForClientInOrg", String.class,
|
||||
String.class);
|
||||
GeneratedHttpRequest<ChefAsyncClient> httpRequest = processor.createRequest(method, "org",
|
||||
"client");
|
||||
assertRequestLineEquals(httpRequest,
|
||||
"PUT https://api.opscode.com/organizations/org/clients/client HTTP/1.1");
|
||||
assertHeadersEqual(httpRequest,
|
||||
"Accept: application/json\nContent-Length: 44\nContent-Type: application/json\n");
|
||||
assertPayloadEquals(httpRequest, "{\"clientname\":\"client\", \"private_key\": true}");
|
||||
|
||||
assertResponseParserClassEquals(method, httpRequest, ParseKeyFromJson.class);
|
||||
assertSaxResponseParserClassEquals(method, null);
|
||||
assertExceptionParserClassEquals(method, null);
|
||||
|
||||
checkFilters(httpRequest);
|
||||
|
||||
}
|
||||
|
||||
public void testCreateClientInOrg() throws SecurityException, NoSuchMethodException, IOException {
|
||||
Method method = ChefAsyncClient.class.getMethod("createClientInOrg", String.class,
|
||||
String.class);
|
||||
GeneratedHttpRequest<ChefAsyncClient> httpRequest = processor.createRequest(method, "org",
|
||||
"client");
|
||||
|
||||
assertRequestLineEquals(httpRequest,
|
||||
"POST https://api.opscode.com/organizations/org/clients HTTP/1.1");
|
||||
assertHeadersEqual(httpRequest,
|
||||
"Accept: application/json\nContent-Length: 23\nContent-Type: application/json\n");
|
||||
assertPayloadEquals(httpRequest, "{\"clientname\":\"client\"}");
|
||||
|
||||
assertResponseParserClassEquals(method, httpRequest, ParseKeyFromJson.class);
|
||||
assertSaxResponseParserClassEquals(method, null);
|
||||
assertExceptionParserClassEquals(method, null);
|
||||
|
||||
checkFilters(httpRequest);
|
||||
|
||||
}
|
||||
|
||||
public void testListClientsInOrg() throws SecurityException, NoSuchMethodException, IOException {
|
||||
Method method = ChefAsyncClient.class.getMethod("listClientsInOrg", String.class);
|
||||
GeneratedHttpRequest<ChefAsyncClient> httpRequest = processor.createRequest(method, "org");
|
||||
|
||||
assertRequestLineEquals(httpRequest,
|
||||
"GET https://api.opscode.com/organizations/org/clients HTTP/1.1");
|
||||
assertHeadersEqual(httpRequest, "Accept: application/json\n");
|
||||
assertPayloadEquals(httpRequest, null);
|
||||
|
||||
assertResponseParserClassEquals(method, httpRequest, ParseKeySetFromJson.class);
|
||||
assertSaxResponseParserClassEquals(method, null);
|
||||
assertExceptionParserClassEquals(method, null);
|
||||
|
||||
checkFilters(httpRequest);
|
||||
|
||||
}
|
||||
|
||||
public void testCreateUser() throws SecurityException, NoSuchMethodException, IOException {
|
||||
Method method = ChefAsyncClient.class.getMethod("createUser", User.class);
|
||||
|
@ -163,9 +260,8 @@ public class ChefAsyncClientTest extends RestClientTest<ChefAsyncClient> {
|
|||
|
||||
}
|
||||
|
||||
public void testCreateOrganization() throws SecurityException, NoSuchMethodException,
|
||||
IOException {
|
||||
Method method = ChefAsyncClient.class.getMethod("createOrganization", Organization.class);
|
||||
public void testCreateOrg() throws SecurityException, NoSuchMethodException, IOException {
|
||||
Method method = ChefAsyncClient.class.getMethod("createOrg", Organization.class);
|
||||
GeneratedHttpRequest<ChefAsyncClient> httpRequest = processor.createRequest(method,
|
||||
new Organization("myorganization"));
|
||||
|
||||
|
@ -182,9 +278,8 @@ public class ChefAsyncClientTest extends RestClientTest<ChefAsyncClient> {
|
|||
|
||||
}
|
||||
|
||||
public void testUpdateOrganization() throws SecurityException, NoSuchMethodException,
|
||||
IOException {
|
||||
Method method = ChefAsyncClient.class.getMethod("updateOrganization", Organization.class);
|
||||
public void testUpdateOrg() throws SecurityException, NoSuchMethodException, IOException {
|
||||
Method method = ChefAsyncClient.class.getMethod("updateOrg", Organization.class);
|
||||
GeneratedHttpRequest<ChefAsyncClient> httpRequest = processor.createRequest(method,
|
||||
new Organization("myorganization"));
|
||||
|
||||
|
@ -202,8 +297,8 @@ public class ChefAsyncClientTest extends RestClientTest<ChefAsyncClient> {
|
|||
|
||||
}
|
||||
|
||||
public void testGetOrganization() throws SecurityException, NoSuchMethodException, IOException {
|
||||
Method method = ChefAsyncClient.class.getMethod("getOrganization", String.class);
|
||||
public void testGetOrg() throws SecurityException, NoSuchMethodException, IOException {
|
||||
Method method = ChefAsyncClient.class.getMethod("getOrg", String.class);
|
||||
GeneratedHttpRequest<ChefAsyncClient> httpRequest = processor.createRequest(method,
|
||||
"myorganization");
|
||||
|
||||
|
@ -220,9 +315,8 @@ public class ChefAsyncClientTest extends RestClientTest<ChefAsyncClient> {
|
|||
|
||||
}
|
||||
|
||||
public void testDeleteOrganization() throws SecurityException, NoSuchMethodException,
|
||||
IOException {
|
||||
Method method = ChefAsyncClient.class.getMethod("deleteOrganization", String.class);
|
||||
public void testDeleteOrg() throws SecurityException, NoSuchMethodException, IOException {
|
||||
Method method = ChefAsyncClient.class.getMethod("deleteOrg", String.class);
|
||||
GeneratedHttpRequest<ChefAsyncClient> httpRequest = processor.createRequest(method,
|
||||
"myorganization");
|
||||
|
||||
|
|
|
@ -28,11 +28,14 @@ import static org.testng.Assert.assertNotNull;
|
|||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Set;
|
||||
|
||||
import org.jclouds.chef.domain.Organization;
|
||||
import org.jclouds.chef.domain.User;
|
||||
import org.jclouds.logging.log4j.config.Log4JLoggingModule;
|
||||
import org.testng.annotations.BeforeGroups;
|
||||
import org.jclouds.rest.AuthorizationException;
|
||||
import org.jclouds.rest.RestContext;
|
||||
import org.testng.annotations.AfterClass;
|
||||
import org.testng.annotations.BeforeClass;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.common.base.Charsets;
|
||||
|
@ -46,23 +49,73 @@ import com.google.common.io.Files;
|
|||
@Test(groups = "live", testName = "chef.ChefClientLiveTest")
|
||||
public class ChefClientLiveTest {
|
||||
|
||||
private ChefClient client;
|
||||
private String username;
|
||||
private RestContext<ChefAsyncClient, ChefClient> validatorConnection;
|
||||
private RestContext<ChefAsyncClient, ChefClient> clientConnection;
|
||||
|
||||
@BeforeGroups(groups = { "live" })
|
||||
private String orgname;
|
||||
private String clientKey;
|
||||
|
||||
public static final String PREFIX = System.getProperty("user.name") + "-jcloudstest";
|
||||
|
||||
@BeforeClass(groups = { "live" })
|
||||
public void setupClient() throws IOException {
|
||||
username = checkNotNull(System.getProperty("jclouds.test.user"), "jclouds.test.user");
|
||||
orgname = checkNotNull(System.getProperty("jclouds.test.user"), "jclouds.test.user");
|
||||
String keyfile = System.getProperty("jclouds.test.key");
|
||||
if (keyfile == null || keyfile.equals(""))
|
||||
keyfile = System.getProperty("user.home") + "/chef/client.pem";
|
||||
client = ChefContextFactory.createContext(username,
|
||||
Files.toString(new File(keyfile), Charsets.UTF_8), new Log4JLoggingModule())
|
||||
.getApi();
|
||||
keyfile = System.getProperty("user.home") + "/chef/validation.pem";
|
||||
validatorConnection = createConnection(orgname + "-validator", Files.toString(new File(
|
||||
keyfile), Charsets.UTF_8));
|
||||
}
|
||||
|
||||
private RestContext<ChefAsyncClient, ChefClient> createConnection(String identity, String key)
|
||||
throws IOException {
|
||||
return ChefContextFactory.createContext(identity, key, new Log4JLoggingModule());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testListClientsInOrg() throws Exception {
|
||||
Set<String> clients = validatorConnection.getApi().listClientsInOrg(orgname);
|
||||
assertNotNull(clients);
|
||||
assert clients.contains(orgname + "-validator");
|
||||
}
|
||||
|
||||
@Test(dependsOnMethods = "testListClientsInOrg")
|
||||
public void testCreateClientInOrg() throws Exception {
|
||||
validatorConnection.getApi().deleteClientInOrg(orgname, PREFIX);
|
||||
clientKey = validatorConnection.getApi().createClientInOrg(orgname, PREFIX);
|
||||
assertNotNull(clientKey);
|
||||
System.out.println(clientKey);
|
||||
clientConnection = createConnection(PREFIX, clientKey);
|
||||
clientConnection.getApi().clientExistsInOrg(orgname, PREFIX);
|
||||
}
|
||||
|
||||
@Test(dependsOnMethods = "testCreateClientInOrg")
|
||||
public void testGenerateKeyForClientInOrg() throws Exception {
|
||||
clientKey = validatorConnection.getApi().generateKeyForClientInOrg(orgname, PREFIX);
|
||||
assertNotNull(clientKey);
|
||||
clientConnection.close();
|
||||
clientConnection = createConnection(PREFIX, clientKey);
|
||||
clientConnection.getApi().clientExistsInOrg(orgname, PREFIX);
|
||||
}
|
||||
|
||||
@Test(dependsOnMethods = "testCreateClientInOrg")
|
||||
public void testClientExistsInOrg() throws Exception {
|
||||
assertNotNull(validatorConnection.getApi().clientExistsInOrg(orgname, PREFIX));
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = AuthorizationException.class)
|
||||
public void testGetOrgFailsForValidationKey() throws Exception {
|
||||
validatorConnection.getApi().getOrg(orgname);
|
||||
}
|
||||
|
||||
@Test(dependsOnMethods = "testGenerateKeyForClientInOrg", expectedExceptions = AuthorizationException.class)
|
||||
public void testGetOrgFailsForClient() throws Exception {
|
||||
clientConnection.getApi().getOrg(orgname);
|
||||
}
|
||||
|
||||
@Test(enabled = false)
|
||||
public void testGetUser() throws Exception {
|
||||
User user = client.getUser(username);
|
||||
User user = validatorConnection.getApi().getUser(orgname);
|
||||
assertNotNull(user);
|
||||
}
|
||||
|
||||
|
@ -82,24 +135,26 @@ public class ChefClientLiveTest {
|
|||
}
|
||||
|
||||
@Test(enabled = false)
|
||||
public void testCreateOrganization() throws Exception {
|
||||
// TODO
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetOrganization() throws Exception {
|
||||
Organization organization = client.getOrganization("jclouds");
|
||||
assertNotNull(organization);
|
||||
}
|
||||
|
||||
@Test(enabled = false)
|
||||
public void testUpdateOrganization() throws Exception {
|
||||
public void testCreateOrg() throws Exception {
|
||||
// TODO
|
||||
}
|
||||
|
||||
@Test(enabled = false)
|
||||
public void testDeleteOrganization() throws Exception {
|
||||
public void testUpdateOrg() throws Exception {
|
||||
// TODO
|
||||
}
|
||||
|
||||
@Test(enabled = false)
|
||||
public void testDeleteOrg() throws Exception {
|
||||
// TODO
|
||||
|
||||
}
|
||||
|
||||
@AfterClass(groups = { "live" })
|
||||
public void teardownClient() throws IOException {
|
||||
if (clientConnection != null)
|
||||
clientConnection.close();
|
||||
if (validatorConnection != null)
|
||||
validatorConnection.close();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -111,13 +111,18 @@ public class SignedHeaderAuthTest {
|
|||
public static final Multimap<String, String> EXPECTED_SIGN_RESULT_EMPTY = ImmutableMultimap
|
||||
.<String, String> builder().put("X-Ops-Content-Hash", X_OPS_CONTENT_HASH_EMPTY).put(
|
||||
"X-Ops-Userid", USER_ID).put("X-Ops-Sign", "version=1.0").put(
|
||||
"X-Ops-Authorization-1", "N6U75kopDK64cEFqrB6vw+PnubnXr0w5LQeXnIGNGLRP2LvifwIeisk7QxEx").put(
|
||||
"X-Ops-Authorization-2", "mtpQOWAw8HvnWErjzuk9AvUsqVmWpv14ficvkaD79qsPMvbje+aLcIrCGT1P").put(
|
||||
"X-Ops-Authorization-3", "3d2uvf4w7iqwzrIscPnkxLR6o6pymR90gvJXDPzV7Le0jbfD8kmZ8AAK0sGG").put(
|
||||
"X-Ops-Authorization-4", "09F1ftW80bLatJTA66Cw2wBz261r6x/abZhIKFJFDWLzyQGJ8ZNOkUrDDtgI").put(
|
||||
"X-Ops-Authorization-5", "svLVXpOJKZZfKunsElpWjjsyNt3k8vpI1Y4ANO8Eg2bmeCPeEK+YriGm5fbC").put(
|
||||
"X-Ops-Authorization-6", "DzWNPylHJqMeGKVYwGQKpg62QDfe5yXh3wZLiQcXow==").put("X-Ops-Timestamp",
|
||||
TIMESTAMP_ISO8601).build();
|
||||
"X-Ops-Authorization-1",
|
||||
"N6U75kopDK64cEFqrB6vw+PnubnXr0w5LQeXnIGNGLRP2LvifwIeisk7QxEx").put(
|
||||
"X-Ops-Authorization-2",
|
||||
"mtpQOWAw8HvnWErjzuk9AvUsqVmWpv14ficvkaD79qsPMvbje+aLcIrCGT1P").put(
|
||||
"X-Ops-Authorization-3",
|
||||
"3d2uvf4w7iqwzrIscPnkxLR6o6pymR90gvJXDPzV7Le0jbfD8kmZ8AAK0sGG").put(
|
||||
"X-Ops-Authorization-4",
|
||||
"09F1ftW80bLatJTA66Cw2wBz261r6x/abZhIKFJFDWLzyQGJ8ZNOkUrDDtgI").put(
|
||||
"X-Ops-Authorization-5",
|
||||
"svLVXpOJKZZfKunsElpWjjsyNt3k8vpI1Y4ANO8Eg2bmeCPeEK+YriGm5fbC").put(
|
||||
"X-Ops-Authorization-6", "DzWNPylHJqMeGKVYwGQKpg62QDfe5yXh3wZLiQcXow==").put(
|
||||
"X-Ops-Timestamp", TIMESTAMP_ISO8601).build();
|
||||
|
||||
public static String PUBLIC_KEY;
|
||||
public static String PRIVATE_KEY;
|
||||
|
@ -195,6 +200,12 @@ public class SignedHeaderAuthTest {
|
|||
private SignedHeaderAuth signing_obj;
|
||||
private EncryptionService encryptionService;
|
||||
|
||||
@Test
|
||||
void canParseKeyFromCreateClient() throws IOException {
|
||||
String key = "-----BEGIN RSA PRIVATE KEY-----\nMIIEpAIBAAKCAQEA50Iwgq8OIfm5vY9Gwfb6UBt17D7V4djyFSLJ1AbCU/o8Zlrr\nW73JqaK5dC3IO6Dcu+/qPYGtBUWvhFAXrsFOooz0mTod/LtBN1YVurJ60goJrR6w\nKhUYC9H45OW/qcdIM7kdDwiyMZfbHqW6fo0xPqjvgxtZoI+v7pgThacOG6pw7PO6\nGgnJa3MGK3xEbzlI6+EBJWG3EiwexguwOpTD4a4TDIAqKrlVDPeUpU7rFbsBPRS8\nkypR3lU58+WRz/zi9fiH/Sy2X+S3yZg14HiutJjxc8zJsazF3eDxyLGPQmhv3Mso\nA0wbjGusbe6hPdDkzh/B2KO9u96QCdlGu/rc6QIDAQABAoIBAA/7OgD9+fsNF/Hq\nodgrqja4/xg5a2x1Ip2lTs9RPEKza1Mje1pWrkYD0c8ejtTYFAkE1mozuPJBU5TQ\nOCLChx2iohCovIPHqQUa9Nt3FBfJy8tj8Ian+IZwl0OyQOGJvQqeA00Tq8TTmrfu\negne1gVfhVXJIROAeocBiW/WEJqGti0OE5zQQMld3cJ5viTdEsaWYCu2HaEoblKB\nH6KfRGM2N3L3KjKFGtEg+cX1UdaMlzmp+O5/yvjBykZy6cuUOIsgz2e5nQV4hYEq\ntJ/+6E0QVTXfnVZi4IxKlkVMhyonqOxAOKGG+dWeWh3DqPJFzjmp3kcbRN9E3u+2\nqKU5gpECgYEA+a/i5z2jFCJ8rMpoCPPxm2eiIYZVs3LE33WU5FNNieBRC+KqO06h\nMB3rQ3k8KJDNJYWD5UwIrgjCD5mgkmcSDI6SbOn6PA1Mtw6qZlbeg17V9L9ryXxt\nSfC5AC+qVWd6unrLh0LgkvLS8rgG4GjLZY0HDDMrJWodcc+uWVk3Mo0CgYEA7RsG\nC9gOcHWi6WJ2uEDvLj4IkSkB4IFipEVcKl7VVDSnUgxaBZm3o0DLYDYhIOw7XcQL\n6vpxbRZdlApGyu1ahfMbk3+quFNMQuGxZcv9EhHz7ASnXK6mlrWkJzCGjLz6/MdI\nU0VGbtkBtOY/GaLXdTkQksWowVNoedISfQV9as0CgYEA0Tj1JVecw05yskeZDYd8\nOQCJ9xWd0pSlK6pXbUvweUwiHZd9ldy5bJxle1CnfEZ54KsUbptb2pk0I+ZTitob\nYbJGOEWHjbKHSg1b9A1uvx5EoqWUKG2/FmpEW0eVr6LaUFB9I4aCsCARa5mRCZJG\nfX3DHhHyYZOdwLSKIAyGGDECgYALEwkMQpIiFIyAZBXxcy74tPMHfKfWyZRG4ep1\nHCrQnQj3nxYRTuWx3VPicYTImeAH+CEqX3ouwy2pvXUjA0UIHpu6HutlYpacRRhZ\nDdcLIgWHj4wVmx6yyVcacXzHVAhRCCnLod+xS7d1sI9f7igsFHc+s7a3GOM3VWWB\nq2D5PQKBgQDY9eSb5pc5EYbPy0a/wKFLMNCVLXlDT8jRSC2UnhmcHbhi1IdUbn1j\nR+SuUgrAVNAKzJRY9wmF6Zt0pJ2YLFX7L8HaGyfzkib8kli2sXFonlQ4d0dTdcJo\nVGR1jTxfZQicdPcDPOLPpQz/rP31ZqdHtfaegTOxHebX7W2E5QvPZg==\n-----END RSA PRIVATE KEY-----\n";
|
||||
KeyPair.class.cast(new PEMReader(new StringReader(key)).readObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* before class, as we need to ensure that the filter is threadsafe.
|
||||
*
|
||||
|
|
|
@ -37,4 +37,11 @@ public class ParseKeyFromJsonTest {
|
|||
.toInputStream("{\n\"uri\": \"https://api.opscode.com/users/bobo\", \"private_key\": \"RSA_PRIVATE_KEY\",}"))),
|
||||
"RSA_PRIVATE_KEY");
|
||||
}
|
||||
|
||||
public void test2() {
|
||||
String key = handler.apply(new HttpResponse(ParseKeyFromJsonTest.class
|
||||
.getResourceAsStream("/newclient.txt")));
|
||||
assert key.startsWith("-----BEGIN RSA PRIVATE KEY-----\n");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
package org.jclouds.chef.functions;
|
||||
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.jclouds.http.HttpResponse;
|
||||
import org.jclouds.http.functions.config.ParserModule;
|
||||
import org.jclouds.util.Utils;
|
||||
import org.testng.annotations.BeforeTest;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.inject.Guice;
|
||||
import com.google.inject.Injector;
|
||||
|
||||
/**
|
||||
* Tests behavior of {@code ParseKeySetFromJson}
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Test(groups = "unit", sequential = true, testName = "chef.ParseKeySetFromJsonTest")
|
||||
public class ParseKeySetFromJsonTest {
|
||||
|
||||
private ParseKeySetFromJson handler;
|
||||
|
||||
@BeforeTest
|
||||
protected void setUpInjector() throws IOException {
|
||||
Injector injector = Guice.createInjector(new ParserModule());
|
||||
handler = injector.getInstance(ParseKeySetFromJson.class);
|
||||
}
|
||||
|
||||
public void testRegex() {
|
||||
assertEquals(
|
||||
handler
|
||||
.apply(new HttpResponse(
|
||||
Utils
|
||||
.toInputStream("{\n\"opscode-validator\": \"https://api.opscode.com/...\", \"pimp-validator\": \"https://api.opscode.com/...\"}"))),
|
||||
ImmutableSet.of("opscode-validator","pimp-validator"));
|
||||
}
|
||||
}
|
|
@ -1,32 +1,31 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
<!--
|
||||
|
||||
|
||||
Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
Copyright (C) 2009 Cloud Conscious, LLC.
|
||||
<info@cloudconscious.com>
|
||||
|
||||
====================================================================
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
====================================================================
|
||||
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.
|
||||
====================================================================
|
||||
|
||||
-->
|
||||
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.
|
||||
====================================================================
|
||||
-->
|
||||
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
|
||||
|
||||
<!--
|
||||
For more configuration infromation and examples see the Apache Log4j
|
||||
website: http://logging.apache.org/log4j/
|
||||
-->
|
||||
<!--
|
||||
For more configuration infromation and examples see the Apache
|
||||
Log4j website: http://logging.apache.org/log4j/
|
||||
-->
|
||||
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/"
|
||||
debug="false">
|
||||
debug="false">
|
||||
|
||||
<!-- A time/date based rolling appender -->
|
||||
<appender name="WIREFILE" class="org.apache.log4j.DailyRollingFileAppender">
|
||||
|
@ -39,72 +38,80 @@
|
|||
<param name="Threshold" value="TRACE" />
|
||||
|
||||
<layout class="org.apache.log4j.PatternLayout">
|
||||
<!-- The default pattern: Date Priority [Category] Message${symbol_escape}n -->
|
||||
<!--
|
||||
The default pattern: Date Priority [Category]
|
||||
Message${symbol_escape}n
|
||||
-->
|
||||
<param name="ConversionPattern" value="%d %-5p [%c] (%t) %m%n" />
|
||||
|
||||
<!--
|
||||
The full pattern: Date MS Priority [Category] (Thread:NDC) Message${symbol_escape}n
|
||||
<param name="ConversionPattern" value="%d %-5r %-5p [%c] (%t:%x)
|
||||
%m%n"/>
|
||||
The full pattern: Date MS Priority [Category]
|
||||
(Thread:NDC) Message${symbol_escape}n <param
|
||||
name="ConversionPattern" value="%d %-5r %-5p [%c]
|
||||
(%t:%x) %m%n"/>
|
||||
-->
|
||||
</layout>
|
||||
</appender>
|
||||
|
||||
<!-- A time/date based rolling appender -->
|
||||
<appender name="FILE" class="org.apache.log4j.DailyRollingFileAppender">
|
||||
<param name="File" value="target/test-data/jclouds.log" />
|
||||
<param name="Append" value="true" />
|
||||
|
||||
<!-- Rollover at midnight each day -->
|
||||
<param name="DatePattern" value="'.'yyyy-MM-dd" />
|
||||
|
||||
<param name="Threshold" value="TRACE" />
|
||||
|
||||
<layout class="org.apache.log4j.PatternLayout">
|
||||
<!-- The default pattern: Date Priority [Category] Message${symbol_escape}n -->
|
||||
<param name="ConversionPattern" value="%d %-5p [%c] (%t) %m%n" />
|
||||
|
||||
<!--
|
||||
The full pattern: Date MS Priority [Category] (Thread:NDC) Message${symbol_escape}n
|
||||
<param name="ConversionPattern" value="%d %-5r %-5p [%c] (%t:%x)
|
||||
%m%n"/>
|
||||
-->
|
||||
</layout>
|
||||
</appender>
|
||||
|
||||
<appender name="ASYNC" class="org.apache.log4j.AsyncAppender">
|
||||
<appender-ref ref="FILE" />
|
||||
</appender>
|
||||
<!-- A time/date based rolling appender -->
|
||||
<appender name="FILE" class="org.apache.log4j.DailyRollingFileAppender">
|
||||
<param name="File" value="target/test-data/jclouds.log" />
|
||||
<param name="Append" value="true" />
|
||||
|
||||
<!-- Rollover at midnight each day -->
|
||||
<param name="DatePattern" value="'.'yyyy-MM-dd" />
|
||||
|
||||
<param name="Threshold" value="TRACE" />
|
||||
|
||||
<layout class="org.apache.log4j.PatternLayout">
|
||||
<!--
|
||||
The default pattern: Date Priority [Category]
|
||||
Message${symbol_escape}n
|
||||
-->
|
||||
<param name="ConversionPattern" value="%d %-5p [%c] (%t) %m%n" />
|
||||
|
||||
<!--
|
||||
The full pattern: Date MS Priority [Category]
|
||||
(Thread:NDC) Message${symbol_escape}n <param
|
||||
name="ConversionPattern" value="%d %-5r %-5p [%c]
|
||||
(%t:%x) %m%n"/>
|
||||
-->
|
||||
</layout>
|
||||
</appender>
|
||||
|
||||
<appender name="ASYNC" class="org.apache.log4j.AsyncAppender">
|
||||
<appender-ref ref="FILE" />
|
||||
</appender>
|
||||
|
||||
<appender name="ASYNCWIRE" class="org.apache.log4j.AsyncAppender">
|
||||
<appender-ref ref="WIREFILE" />
|
||||
</appender>
|
||||
|
||||
<!-- ================ -->
|
||||
<!-- Limit categories -->
|
||||
<!-- ================ -->
|
||||
|
||||
<category name="org.jclouds">
|
||||
<priority value="DEBUG" />
|
||||
</appender>
|
||||
|
||||
<!-- ================ -->
|
||||
<!-- Limit categories -->
|
||||
<!-- ================ -->
|
||||
|
||||
<category name="org.jclouds">
|
||||
<priority value="DEBUG" />
|
||||
<appender-ref ref="ASYNC" />
|
||||
</category>
|
||||
|
||||
</category>
|
||||
|
||||
<category name="jclouds.headers">
|
||||
<priority value="DEBUG" />
|
||||
<appender-ref ref="ASYNCWIRE" />
|
||||
</category><!--
|
||||
</category>
|
||||
|
||||
<category name="jclouds.wire">
|
||||
<priority value="DEBUG" />
|
||||
<appender-ref ref="ASYNCWIRE" />
|
||||
</category>
|
||||
|
||||
--><!-- ======================= -->
|
||||
<!-- Setup the Root category -->
|
||||
<!-- ======================= -->
|
||||
|
||||
<root>
|
||||
<priority value="WARN" />
|
||||
</root>
|
||||
<!-- ======================= -->
|
||||
<!-- Setup the Root category -->
|
||||
<!-- ======================= -->
|
||||
|
||||
<root>
|
||||
<priority value="WARN" />
|
||||
</root>
|
||||
|
||||
</log4j:configuration>
|
|
@ -0,0 +1 @@
|
|||
{"clientname":"adriancole-jcloudstest","private_key":"-----BEGIN RSA PRIVATE KEY-----\nMIIEowIBAAKCAQEAuzaE6azgUxwESX1rCGdJ5xpdrc1XC311bOGZBCE8NA+CpFh2\npopCBQwjpOnlgpdd/+C+TESl30ojauvVej9AbgJb30Jl7e7dEX4Brncnj03G+mo+\nG4osf7I2PA/6+9Ol7xamK9GL/cs8nOb17cRTWmhTRW7+3Rrli/s6wzqQXjGjWzgz\nthXv7FOPHA87UjJzrePBFta7+S8BxKCG2QaTxzNGytSAy8KBX8BUrSt5+X22QjEM\nQF3zA4TPtoWp/lcDRzCMdffMYoVPZzKqIeEFSexwvNlJ/qU6hbcyAxab1lYawjKU\nRgvPCflVYTIw6teHNqkyvTPX+lpIAVXigSVQXwIDAQABAoIBAHz81xvTSSjzaYFO\n9Gh13QcnuSdSEi0fo4f/zdLOBY2UVVo3nW9umskX46w0ZAAd4qn0d9gfdMZwjtjR\nfoLRO8i2VnPltnt1n64P/DtoXcb03EVPLQvh4feXGVJcMOpz0TKgYmyax+W3DE6M\ne+Az1JplUELo6crgLCSapA63SK85PEuWAcMUQg9s6MnzB/qXz95yJlzgjVMIJUyb\n9jFdq2s0gefTpK2cKeSYWQAFPd41Ea5v/3j0LN8qs/dImNnzxDXu+hi8+16/4PTK\npl+1bJXwE9YkWPdd39EfjVkk6q/HyFijK3VpHnOy7n3iaJTUKwBJLRsFrQ5Eor3U\nvNKyGXECgYEA3RZdFC6MRBAo76GKd9axbA0G9Bmct9pQT4B+od2AGGOdiYzYRWfF\nlyTgctY9dcfsX5DBQFUHNnYXMHHI0wHQk1m20UpFLa7IV3RWkW5JwYkbQHmeP4pn\np8GtJEXC+4PrT0Pc32acfWozArokUju7nLLazCPCDdfc8t9MPX1W230CgYEA2MbB\ndwdwLZx9zEqZ0MciRxjsOA30b6OYPOqMP1ADVeExPN8fHLCAQjwUExQa86+FMV4H\nOtu+DXlisp+TSTRQzpXMfGppupbK1j5cqz2sU37upKuz/uf0XyeyBLOi0y9/DMl5\njG2StLLIMawRqJRUuq/fyA/6oTzADNwoW6LjCgsCgYBGvCj7lAj8nc77HEwZG2+Y\ninJ3Ftq1V/vp88qQLzYUl4qHv7BSRGlLelj1ZOY1EMnnqYCq/IlaO14f+ceu+x2o\nh0OeooyPmSQwFuC7lvWyHhPCBSdEXRvc6HJk8Iz5u7NFoQjB0SqwVZIMhVGpncLg\n17h5J9emZjIi4p6Z7cgkYQKBgHt+/8in3Cif9qrj9S0TxVtrv2dPy+mt8ZUCqlOH\nad8LI9nh4v+dLfSN9YHI+nHJlL/DKatGdMeIV8obTvVtcHvAq3ZVyVYbggL8FB8a\nS4plzd7SUwDtdDKhkrFLBX/6lw7Z2P0/j0ySbaqetJCtsHeKqpp3P/mLen3ZDsTl\nzyJxAoGBAIxl1SGzu3lO3BQ5+EPaprNw3eN3nzG4WLQvnzZwpeAFS+E5pllMkIfs\nu01Vfv68NC4u6LFgdXSY1vQt6hiA5TNqQk0TyVfFAunbXgTekF6XqDPQUf1nq9aZ\nlMvo4vlaLDKBkhG5HJE/pIa0iB+RMZLS0GhxsIWerEDmYdHKM25o\n-----END RSA PRIVATE KEY-----\n","uri":"https://api.opscode.com/organizations/jclouds/clients/adriancole-jcloudstest","certificate":"-----BEGIN CERTIFICATE-----\nMIIClzCCAgCgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBnjELMAkGA1UEBhMCVVMx\nEzARBgNVBAgMCldhc2hpbmd0b24xEDAOBgNVBAcMB1NlYXR0bGUxFjAUBgNVBAoM\nDU9wc2NvZGUsIEluYy4xHDAaBgNVBAsME0NlcnRpZmljYXRlIFNlcnZpY2UxMjAw\nBgNVBAMMKW9wc2NvZGUuY29tL2VtYWlsQWRkcmVzcz1hdXRoQG9wc2NvZGUuY29t\nMB4XDTEwMDYwNDIzMzM0NloXDTIwMDYwMTIzMzM0NlowADCCASIwDQYJKoZIhvcN\nAQEBBQADggEPADCCAQoCggEBALs2hOms4FMcBEl9awhnSecaXa3NVwt9dWzhmQQh\nPDQPgqRYdqaKQgUMI6Tp5YKXXf/gvkxEpd9KI2rr1Xo/QG4CW99CZe3u3RF+Aa53\nJ49NxvpqPhuKLH+yNjwP+vvTpe8WpivRi/3LPJzm9e3EU1poU0Vu/t0a5Yv7OsM6\nkF4xo1s4M7YV7+xTjxwPO1Iyc63jwRbWu/kvAcSghtkGk8czRsrUgMvCgV/AVK0r\nefl9tkIxDEBd8wOEz7aFqf5XA0cwjHX3zGKFT2cyqiHhBUnscLzZSf6lOoW3MgMW\nm9ZWGsIylEYLzwn5VWEyMOrXhzapMr0z1/paSAFV4oElUF8CAwEAATANBgkqhkiG\n9w0BAQUFAAOBgQCTllbpWNagYjCiaU5UnjIFXn0YyNfZzqCh8SQ0Asj8MtksVbFG\nAErp03+Cb9a7GTdNE7fIyPsLTnGzFhqTwKN+3jIj4wgxhrbYXF73x1+rDRyHjJu7\na7gdTEYZqWiAHdW47vXj69W1dB5e4vNm1F29gOSL/x7BMAyjLFWbdbKw0w==\n-----END CERTIFICATE-----\n","orgname":"jclouds}
|
|
@ -1,8 +1,8 @@
|
|||
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
|
||||
<suite name="jclouds-chef">
|
||||
<test verbose="2" name="org.jclouds.chef.ChefClientLiveTest" annotations="JDK">
|
||||
<test verbose="2" name="org.jclouds.chef.functions.ParseKeyFromJsonTest" annotations="JDK">
|
||||
<classes>
|
||||
<class name="org.jclouds.chef.ChefClientLiveTest"/>
|
||||
<class name="org.jclouds.chef.functions.ParseKeyFromJsonTest"/>
|
||||
</classes>
|
||||
</test>
|
||||
</suite>
|
||||
|
|
Loading…
Reference in New Issue