Merge pull request #590 from aplowe/openstack-nova

Adding openstack-keystone to labs
This commit is contained in:
Adrian Cole 2012-04-30 07:58:29 -07:00
commit 8a01ec72e2
56 changed files with 2689 additions and 48 deletions

View File

@ -35,17 +35,17 @@ import com.google.common.util.concurrent.ListenableFuture;
* Provides asynchronous access to Service via their REST API.
* <p/>
*
* @see ServiceClient
* @see AuthenticationClient
* @see <a href=
* "http://docs.openstack.org/api/openstack-identity-service/2.0/content/Service_API_Client_Operations.html"
* />
* @author Adrian Cole
*/
@Path("/v1.1")
public interface ServiceAsyncClient {
public interface AuthenticationAsyncClient {
/**
* @see ServiceClient#authenticate
* @see AuthenticationClient#authenticate
*/
@POST
@SelectJson("auth")

View File

@ -27,13 +27,13 @@ import org.jclouds.openstack.keystone.v1_1.domain.Auth;
* Provides synchronous access to the KeyStone Service API.
* <p/>
*
* @see ServiceAsyncClient
* @see AuthenticationAsyncClient
* @see <a href="http://docs.openstack.org/api/openstack-identity-service/2.0/content/Service_API_Client_Operations.html"
* />
* @author Adrian Cole
*/
@Timeout(duration = 30, timeUnit = TimeUnit.SECONDS)
public interface ServiceClient {
public interface AuthenticationClient {
/**
* Authenticate to generate a token.

View File

@ -35,8 +35,8 @@ import org.jclouds.http.annotation.ClientError;
import org.jclouds.location.Provider;
import org.jclouds.location.suppliers.RegionIdToURISupplier;
import org.jclouds.openstack.Authentication;
import org.jclouds.openstack.keystone.v1_1.ServiceAsyncClient;
import org.jclouds.openstack.keystone.v1_1.ServiceClient;
import org.jclouds.openstack.keystone.v1_1.AuthenticationAsyncClient;
import org.jclouds.openstack.keystone.v1_1.AuthenticationClient;
import org.jclouds.openstack.keystone.v1_1.domain.Auth;
import org.jclouds.openstack.keystone.v1_1.handlers.RetryOnRenew;
import org.jclouds.openstack.keystone.v1_1.suppliers.RegionIdToURIFromAuthForServiceSupplier;
@ -63,7 +63,7 @@ public class AuthenticationServiceModule extends AbstractModule {
}).to(GetAuth.class);
// ServiceClient is used directly for filters and retry handlers, so let's bind it
// explicitly
bindClientAndAsyncClient(binder(), ServiceClient.class, ServiceAsyncClient.class);
bindClientAndAsyncClient(binder(), AuthenticationClient.class, AuthenticationAsyncClient.class);
install(new FactoryModuleBuilder().implement(RegionIdToURISupplier.class,
RegionIdToURIFromAuthForServiceSupplier.class).build(RegionIdToURISupplier.Factory.class));
bind(HttpRetryHandler.class).annotatedWith(ClientError.class).to(RetryOnRenew.class);
@ -88,7 +88,7 @@ public class AuthenticationServiceModule extends AbstractModule {
public static class GetAuth extends RetryOnTimeOutExceptionFunction<Credentials, Auth> {
@Inject
public GetAuth(final ServiceClient client) {
public GetAuth(final AuthenticationClient client) {
super(new Function<Credentials, Auth>() {
@Override

View File

@ -37,16 +37,16 @@ import com.google.common.util.concurrent.ListenableFuture;
* Provides asynchronous access to Service via their REST API.
* <p/>
*
* @see ServiceClient
* @see AuthenticationClient
* @see <a href="http://docs.openstack.org/api/openstack-identity-service/2.0/content/Service_API_Client_Operations.html"
* />
* @author Adrian Cole
*/
@Path("/v2.0")
public interface ServiceAsyncClient {
public interface AuthenticationAsyncClient {
/**
* @see ServiceClient#authenticateTenantWithCredentials(String,PasswordCredentials)
* @see AuthenticationClient#authenticateTenantWithCredentials(String,PasswordCredentials)
*/
@POST
@SelectJson("access")
@ -57,7 +57,7 @@ public interface ServiceAsyncClient {
PasswordCredentials passwordCredentials);
/**
* @see ServiceClient#authenticateTenantWithCredentials(String,ApiAccessKeyCredentials)
* @see AuthenticationClient#authenticateTenantWithCredentials(String,ApiAccessKeyCredentials)
*/
@POST
@SelectJson("access")

View File

@ -29,13 +29,13 @@ import org.jclouds.openstack.keystone.v2_0.domain.PasswordCredentials;
* Provides synchronous access to the KeyStone Service API.
* <p/>
*
* @see ServiceAsyncClient
* @see AuthenticationAsyncClient
* @see <a href="http://docs.openstack.org/api/openstack-identity-service/2.0/content/Service_API_Client_Operations.html"
* />
* @author Adrian Cole
*/
@Timeout(duration = 30, timeUnit = TimeUnit.SECONDS)
public interface ServiceClient {
public interface AuthenticationClient {
/**
* Authenticate to generate a token.

View File

@ -40,12 +40,14 @@ import org.jclouds.location.suppliers.ZoneIdsSupplier;
import org.jclouds.location.suppliers.derived.RegionIdsFromRegionIdToURIKeySet;
import org.jclouds.location.suppliers.derived.ZoneIdsFromZoneIdToURIKeySet;
import org.jclouds.openstack.Authentication;
import org.jclouds.openstack.keystone.v2_0.ServiceAsyncClient;
import org.jclouds.openstack.keystone.v2_0.ServiceClient;
import org.jclouds.openstack.keystone.v2_0.AuthenticationAsyncClient;
import org.jclouds.openstack.keystone.v2_0.AuthenticationClient;
import org.jclouds.openstack.keystone.v2_0.domain.Access;
import org.jclouds.openstack.keystone.v2_0.functions.AuthenticateApiAccessKeyCredentials;
import org.jclouds.openstack.keystone.v2_0.functions.AuthenticatePasswordCredentials;
import org.jclouds.openstack.keystone.v2_0.handlers.RetryOnRenew;
import org.jclouds.openstack.keystone.v2_0.suppliers.RegionIdToAdminURIFromAccessForTypeAndVersionSupplier;
import org.jclouds.openstack.keystone.v2_0.suppliers.RegionIdToAdminURISupplier;
import org.jclouds.openstack.keystone.v2_0.suppliers.RegionIdToURIFromAccessForTypeAndVersionSupplier;
import org.jclouds.openstack.keystone.v2_0.suppliers.ZoneIdToURIFromAccessForTypeAndVersionSupplier;
import org.jclouds.rest.annotations.ApiVersion;
@ -85,6 +87,8 @@ public class KeystoneAuthenticationModule extends AbstractModule {
protected void configure() {
install(new FactoryModuleBuilder().implement(RegionIdToURISupplier.class,
RegionIdToURIFromAccessForTypeAndVersionSupplier.class).build(RegionIdToURISupplier.Factory.class));
install(new FactoryModuleBuilder().implement(RegionIdToAdminURISupplier.class,
RegionIdToAdminURIFromAccessForTypeAndVersionSupplier.class).build(RegionIdToAdminURISupplier.Factory.class));
// dynamically build the region list as opposed to from properties
bind(RegionIdsSupplier.class).to(RegionIdsFromRegionIdToURIKeySet.class);
}
@ -98,6 +102,16 @@ public class KeystoneAuthenticationModule extends AbstractModule {
RegionIdToURISupplier.Factory factory) {
return factory.createForApiTypeAndVersion(serviceType, apiVersion);
}
// supply the region to id to AdminURL map from keystone, based on the servicetype and api version in
// config
@Provides
@Singleton
protected RegionIdToAdminURISupplier provideRegionIdToAdminURISupplierForApiVersion(
@Named(KeystoneProperties.SERVICE_TYPE) String serviceType, @ApiVersion String apiVersion,
RegionIdToAdminURISupplier.Factory factory) {
return factory.createForApiTypeAndVersion(serviceType, apiVersion);
}
}
@ -132,7 +146,7 @@ public class KeystoneAuthenticationModule extends AbstractModule {
bind(CredentialType.class).toProvider(CredentialTypeFromPropertyOrDefault.class);
// ServiceClient is used directly for filters and retry handlers, so let's bind it
// explicitly
bindClientAndAsyncClient(binder(), ServiceClient.class, ServiceAsyncClient.class);
bindClientAndAsyncClient(binder(), AuthenticationClient.class, AuthenticationAsyncClient.class);
install(locationModule);
}

View File

@ -0,0 +1,170 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.openstack.keystone.v2_0.domain;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Collections;
import java.util.Date;
import java.util.Set;
import org.jclouds.javax.annotation.Nullable;
import org.jclouds.openstack.domain.Link;
import org.jclouds.openstack.domain.Resource;
import com.google.common.base.Objects;
import com.google.common.base.Objects.ToStringHelper;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
import com.google.gson.annotations.SerializedName;
/**
* Class ApiMetadata
*/
public class ApiMetadata extends Resource {
public static Builder builder() {
return new Builder();
}
public Builder toBuilder() {
return new Builder().fromApiMetadata(this);
}
public static class Builder extends Resource.Builder {
private String status;
private Date updated;
private Set<MediaType> mediaTypes = Sets.newLinkedHashSet();
public Builder status(String status) {
this.status = status;
return this;
}
public Builder updated(Date updated) {
this.updated = updated;
return this;
}
public Builder mediaTypes(Set<MediaType> mediaTypes) {
this.mediaTypes = mediaTypes;
return this;
}
public ApiMetadata build() {
return new ApiMetadata(id, name, links, updated, status, mediaTypes);
}
public Builder fromApiMetadata(ApiMetadata in) {
return fromResource(in)
.status(in.getStatus())
.updated(in.getUpdated())
.mediaTypes(in.getMediaTypes());
}
/**
* {@inheritDoc}
*/
@Override
public Builder id(String id) {
return Builder.class.cast(super.id(id));
}
/**
* {@inheritDoc}
*/
@Override
public Builder name(String name) {
return Builder.class.cast(super.name(name));
}
/**
* {@inheritDoc}
*/
@Override
public Builder links(Set<Link> links) {
return Builder.class.cast(super.links(links));
}
/**
* {@inheritDoc}
*/
@Override
public Builder fromResource(Resource in) {
return Builder.class.cast(super.fromResource(in));
}
}
private final String status;
private final Date updated;
@SerializedName("media-types")
private final Set<MediaType> mediaTypes;
protected ApiMetadata(String id, String name, Set<Link> links, Date updated, String status, Set<MediaType> mediaTypes) {
super(id, name, links);
this.status = status;
this.updated = updated;
this.mediaTypes = ImmutableSet.copyOf(checkNotNull(mediaTypes, "mediaTypes"));
}
/**
*/
@Nullable
public String getStatus() {
return this.status;
}
/**
*/
@Nullable
public Date getUpdated() {
return this.updated;
}
/**
*/
@Nullable
public Set<MediaType> getMediaTypes() {
return Collections.unmodifiableSet(this.mediaTypes);
}
@Override
public int hashCode() {
return Objects.hashCode(status, updated, mediaTypes);
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
ApiMetadata that = ApiMetadata.class.cast(obj);
return Objects.equal(this.status, that.status)
&& Objects.equal(this.updated, that.updated)
&& Objects.equal(this.mediaTypes, that.mediaTypes)
;
}
protected ToStringHelper string() {
return super.string()
.add("status", status)
.add("updated", updated)
.add("mediaTypes", mediaTypes);
}
}

View File

@ -55,6 +55,7 @@ public class Endpoint implements Comparable<Endpoint> {
protected String region;
protected URI publicURL;
protected URI internalURL;
protected URI adminURL;
protected String tenantId;
/**
@ -89,6 +90,14 @@ public class Endpoint implements Comparable<Endpoint> {
return this;
}
/**
* @see Endpoint#getInternalURL()
*/
public Builder adminURL(URI adminURL) {
this.adminURL = checkNotNull(adminURL, "adminURL");
return this;
}
/**
* @see Endpoint#getTenantId()
*/
@ -98,7 +107,7 @@ public class Endpoint implements Comparable<Endpoint> {
}
public Endpoint build() {
return new Endpoint(versionId, region, publicURL, internalURL, tenantId);
return new Endpoint(versionId, region, publicURL, internalURL, adminURL, tenantId);
}
public Builder fromEndpoint(Endpoint from) {
@ -113,17 +122,20 @@ public class Endpoint implements Comparable<Endpoint> {
protected final String region;
protected final URI publicURL;
protected final URI internalURL;
protected final URI adminURL;
// renamed half-way through
@Deprecated
protected String tenantName;
protected final String tenantId;
protected Endpoint(String versionId, String region, @Nullable URI publicURL, @Nullable URI internalURL,
@Nullable String tenantId) {
@Nullable URI adminURL, @Nullable String tenantId) {
this.versionId = checkNotNull(versionId, "versionId");
this.region = checkNotNull(region, "region");
this.publicURL = publicURL;
this.internalURL = internalURL;
this.adminURL = adminURL;
this.tenantId = tenantId;
}
@ -160,6 +172,14 @@ public class Endpoint implements Comparable<Endpoint> {
return internalURL;
}
/**
* @return the admin url of the endpoint
*/
@Nullable
public URI getAdminURL() {
return adminURL;
}
/**
* @return the tenant versionId of the endpoint or null
*/
@ -176,7 +196,7 @@ public class Endpoint implements Comparable<Endpoint> {
if (object instanceof Endpoint) {
final Endpoint other = Endpoint.class.cast(object);
return equal(getVersionId(), other.getVersionId()) && equal(region, other.region) && equal(publicURL, other.publicURL)
&& equal(internalURL, other.internalURL) && equal(getTenantId(), other.getTenantId());
&& equal(internalURL, other.internalURL) && equal(adminURL, other.adminURL) && equal(getTenantId(), other.getTenantId());
} else {
return false;
}
@ -184,13 +204,13 @@ public class Endpoint implements Comparable<Endpoint> {
@Override
public int hashCode() {
return Objects.hashCode(getVersionId(), region, publicURL, internalURL, getTenantId());
return Objects.hashCode(getVersionId(), region, publicURL, internalURL, adminURL, getTenantId());
}
@Override
public String toString() {
return toStringHelper("").add("versionId", getVersionId()).add("region", region).add("publicURL", publicURL).add("internalURL",
internalURL).add("tenantId", getTenantId()).toString();
internalURL).add("adminURL", adminURL).add("tenantId", getTenantId()).toString();
}
@Override

View File

@ -0,0 +1,111 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.openstack.keystone.v2_0.domain;
import org.jclouds.javax.annotation.Nullable;
import com.google.common.base.Objects;
import com.google.common.base.Objects.ToStringHelper;
/**
* Class MediaType
*/
public class MediaType {
public static Builder builder() {
return new Builder();
}
public Builder toBuilder() {
return builder().fromMediaType(this);
}
public static class Builder {
private String base;
private String type;
public Builder base(String base) {
this.base = base;
return this;
}
public Builder type(String type) {
this.type = type;
return this;
}
public MediaType build() {
return new MediaType(this);
}
public Builder fromMediaType(MediaType in) {
return this.base(in.getBase()).type(in.getType());
}
}
private final String base;
private final String type;
protected MediaType(Builder builder) {
this.base = builder.base;
this.type = builder.type;
}
/**
*/
@Nullable
public String getBase() {
return this.base;
}
/**
*/
@Nullable
public String getType() {
return this.type;
}
@Override
public int hashCode() {
return Objects.hashCode(base, type);
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
MediaType that = MediaType.class.cast(obj);
return Objects.equal(this.base, that.base)
&& Objects.equal(this.type, that.type)
;
}
protected ToStringHelper string() {
return Objects.toStringHelper("")
.add("base", base)
.add("type", type);
}
@Override
public String toString() {
return string().toString();
}
}

View File

@ -52,7 +52,7 @@ public class Service implements Comparable<Service> {
protected Set<Endpoint> endpoints = ImmutableSet.of();
/**
* @see Service#getId()
* @see Service#getType()
*/
public Builder type(String type) {
this.type = checkNotNull(type, "type");

View File

@ -23,12 +23,16 @@ import static com.google.common.base.Objects.equal;
import static com.google.common.base.Objects.toStringHelper;
import static com.google.common.base.Preconditions.checkNotNull;
import javax.ws.rs.DefaultValue;
import org.jclouds.javax.annotation.Nullable;
import com.google.common.base.Objects;
/**
* A container used to group or isolate resources and/or identity objects. Depending on the service
* operator, a tenant may map to a customer, account, organization, or project.
*
*
* @author Adrian Cole
* @see <a href="http://docs.openstack.org/api/openstack-identity-service/2.0/content/Identity-Service-Concepts-e1362.html"
* />
@ -46,6 +50,7 @@ public class Tenant implements Comparable<Tenant> {
public static class Builder {
protected String id;
protected String name;
protected String description;
/**
* @see Tenant#getId()
@ -63,8 +68,16 @@ public class Tenant implements Comparable<Tenant> {
return this;
}
/**
* @see Tenant#getDescription()
*/
public Builder description(String description) {
this.description = description;
return this;
}
public Tenant build() {
return new Tenant(id, name);
return new Tenant(id, name, description);
}
public Builder fromTenant(Tenant from) {
@ -74,15 +87,17 @@ public class Tenant implements Comparable<Tenant> {
protected final String id;
protected final String name;
protected final String description;
public Tenant(String id, String name) {
protected Tenant(String id, String name, String description) {
this.id = checkNotNull(id, "id");
this.name = checkNotNull(name, "name");
this.description = description;
}
/**
* When providing an ID, it is assumed that the tenant exists in the current OpenStack deployment
*
*
* @return the id of the tenant in the current OpenStack deployment
*/
public String getId() {
@ -96,6 +111,14 @@ public class Tenant implements Comparable<Tenant> {
return name;
}
/**
* @return the description of the tenant
*/
@Nullable
public String getDescription() {
return description;
}
@Override
public boolean equals(Object object) {
if (this == object) {
@ -103,7 +126,8 @@ public class Tenant implements Comparable<Tenant> {
}
if (object instanceof Tenant) {
final Tenant other = Tenant.class.cast(object);
return equal(id, other.id) && equal(name, other.name);
return equal(id, other.id) && equal(name, other.name)
&& equal(description, other.description);
} else {
return false;
}
@ -111,12 +135,12 @@ public class Tenant implements Comparable<Tenant> {
@Override
public int hashCode() {
return Objects.hashCode(id, name);
return Objects.hashCode(id, name, description);
}
@Override
public String toString() {
return toStringHelper("").add("id", id).add("name", name).toString();
return toStringHelper("").add("id", id).add("name", name).add("description", description).toString();
}
@Override

View File

@ -98,11 +98,17 @@ public class User implements Comparable<User> {
protected final String name;
protected final Set<Role> roles;
public User(String id, String name, Set<Role> roles) {
protected User(String id, String name, Set<Role> roles) {
this.id = checkNotNull(id, "id");
this.name = checkNotNull(name, "name");
this.roles = ImmutableSet.copyOf(checkNotNull(roles, "roles"));
}
protected User() {
id = null;
name = null;
roles = ImmutableSet.of();
}
/**
* When providing an ID, it is assumed that the user exists in the current OpenStack deployment

View File

@ -0,0 +1,43 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.openstack.keystone.v2_0.functions;
import java.net.URI;
import javax.inject.Singleton;
import org.jclouds.openstack.keystone.v2_0.domain.Endpoint;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
/**
* @author Adam Lowe
*/
@Singleton
public class AdminURL implements EndpointToSupplierAdminURI {
@Override
public Supplier<URI> apply(Endpoint input) {
return Suppliers.ofInstance(input.getAdminURL());
}
public String toString() {
return "supplyAdminURL()";
}
}

View File

@ -22,7 +22,7 @@ import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.domain.Credentials;
import org.jclouds.openstack.keystone.v2_0.ServiceClient;
import org.jclouds.openstack.keystone.v2_0.AuthenticationClient;
import org.jclouds.openstack.keystone.v2_0.domain.Access;
import org.jclouds.openstack.keystone.v2_0.domain.ApiAccessKeyCredentials;
import org.jclouds.rest.AuthorizationException;
@ -31,10 +31,10 @@ import com.google.common.base.Function;
@Singleton
public class AuthenticateApiAccessKeyCredentials implements Function<Credentials, Access> {
private final ServiceClient client;
private final AuthenticationClient client;
@Inject
public AuthenticateApiAccessKeyCredentials(ServiceClient client) {
public AuthenticateApiAccessKeyCredentials(AuthenticationClient client) {
this.client = client;
}

View File

@ -20,7 +20,7 @@ package org.jclouds.openstack.keystone.v2_0.functions;
import javax.inject.Inject;
import org.jclouds.domain.Credentials;
import org.jclouds.openstack.keystone.v2_0.ServiceClient;
import org.jclouds.openstack.keystone.v2_0.AuthenticationClient;
import org.jclouds.openstack.keystone.v2_0.domain.Access;
import org.jclouds.openstack.keystone.v2_0.domain.PasswordCredentials;
import org.jclouds.rest.AuthorizationException;
@ -28,10 +28,10 @@ import org.jclouds.rest.AuthorizationException;
import com.google.common.base.Function;
public class AuthenticatePasswordCredentials implements Function<Credentials, Access> {
private final ServiceClient client;
private final AuthenticationClient client;
@Inject
public AuthenticatePasswordCredentials(ServiceClient client) {
public AuthenticatePasswordCredentials(AuthenticationClient client) {
this.client = client;
}

View File

@ -0,0 +1,28 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.openstack.keystone.v2_0.functions;
import com.google.inject.ImplementedBy;
/**
* @author Adam Lowe
*/
@ImplementedBy(AdminURL.class)
public interface EndpointToSupplierAdminURI extends EndpointToSupplierURI {
}

View File

@ -0,0 +1,16 @@
package org.jclouds.openstack.keystone.v2_0.functions;
import javax.inject.Inject;
import org.jclouds.location.functions.RegionToEndpoint;
import org.jclouds.openstack.keystone.v2_0.suppliers.RegionIdToAdminURISupplier;
/**
* @author Adam Lowe
*/
public class RegionToAdminEndpointURI extends RegionToEndpoint {
@Inject
public RegionToAdminEndpointURI(RegionIdToAdminURISupplier regionToEndpointSupplier) {
super(regionToEndpointSupplier);
}
}

View File

@ -0,0 +1,45 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.openstack.keystone.v2_0.suppliers;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.openstack.keystone.v2_0.domain.Access;
import org.jclouds.openstack.keystone.v2_0.functions.EndpointToRegion;
import org.jclouds.openstack.keystone.v2_0.functions.EndpointToSupplierAdminURI;
import com.google.common.base.Supplier;
import com.google.inject.assistedinject.Assisted;
@Singleton
public class RegionIdToAdminURIFromAccessForTypeAndVersionSupplier extends
LocationIdToURIFromAccessForTypeAndVersionSupplier implements RegionIdToAdminURISupplier {
@Inject
public RegionIdToAdminURIFromAccessForTypeAndVersionSupplier(Supplier<Access> access,
EndpointToSupplierAdminURI endpointToSupplierURI, EndpointToRegion endpointToRegion,
@Assisted("apiType") String apiType, @Assisted("apiVersion") String apiVersion) {
super(access, endpointToSupplierURI, endpointToRegion, apiType, apiVersion);
}
@Override
public String toString() {
return "regionIdToAdminURIFromAccessForTypeAndVersion(" + apiType + ", " + apiVersion + ")";
}
}

View File

@ -0,0 +1,28 @@
package org.jclouds.openstack.keystone.v2_0.suppliers;
import java.net.URI;
import java.util.Map;
import com.google.common.base.Supplier;
import com.google.inject.ImplementedBy;
import com.google.inject.assistedinject.Assisted;
/**
* @author Adam Lowe
*/
@ImplementedBy(RegionIdToAdminURIFromAccessForTypeAndVersionSupplier.class)
public interface RegionIdToAdminURISupplier extends Supplier<Map<String, Supplier<URI>>> {
static interface Factory {
/**
*
* @param apiType
* type of the api, according to the provider. ex. {@code compute} {@code
* object-store}
* @param apiVersion
* version of the api
* @return regions mapped to default uri
*/
RegionIdToAdminURISupplier createForApiTypeAndVersion(@Assisted("apiType") String apiType,
@Assisted("apiVersion") String apiVersion);
}
}

View File

@ -41,4 +41,8 @@ public interface ServiceType {
* Image Service (Glance)
*/
public static final String IMAGE = "image";
/**
* Identity Service (Keystone)
*/
public static final String IDENTITY = "identity";
}

View File

@ -0,0 +1,50 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.openstack.keystone.v2_0.functions;
import static org.testng.Assert.assertEquals;
import java.net.URI;
import org.jclouds.openstack.keystone.v2_0.domain.Endpoint;
import org.testng.annotations.Test;
/**
* @author Adam Lowe
*/
@Test(groups = "unit", testName = "AdminURLTest")
public class AdminURLTest {
private final AdminURL fn = new AdminURL();
public void testAdminURL() {
assertEquals(fn.apply(
Endpoint.builder().region("LON").versionId("1.0").adminURL(
URI.create("https://cdn3.clouddrive.com/v1/MossoCloudFS_83a9d536-2e25-4166-bd3b-a503a934f953"))
.build()).get(), URI
.create("https://cdn3.clouddrive.com/v1/MossoCloudFS_83a9d536-2e25-4166-bd3b-a503a934f953"));
}
public void testPublicURLNullReturnsInternalURL() {
assertEquals(fn
.apply(
Endpoint.builder().region("lon").versionId("1.0")
.internalURL(URI.create("https://192.168.1.1")).build()).get(), null);
}
}

View File

@ -67,11 +67,13 @@ public class ParseAccessTest extends BaseItemParserTest<Access> {
Service.builder().name("Object Storage").type("object-store").endpoints(
Endpoint.builder().tenantId("40806637803162").publicURL(
URI.create("https://objects.jclouds.org/v1.0/40806637803162"))
.adminURL(URI.create("https://objects.jclouds.org/v1.0/"))
.region("region-a.geo-1").versionId("1.0").build()).build(),
Service.builder().name("Identity").type("identity").endpoints(
Endpoint.builder().publicURL(URI.create("https://csnode.jclouds.org/v2.0/")).region(
"region-a.geo-1").versionId("2.0").build()).build(),
Endpoint.builder().publicURL(URI.create("https://csnode.jclouds.org/v2.0/"))
.adminURL(URI.create("https://csnode.jclouds.org:35357/v2.0/"))
.region("region-a.geo-1").versionId("2.0").build()).build(),
Service.builder().name("Image Management").type("image").endpoints(
Endpoint.builder().tenantId("40806637803162").publicURL(

View File

@ -0,0 +1,70 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.openstack.keystone.v2_0.parse;
import java.net.URI;
import javax.ws.rs.Consumes;
import javax.ws.rs.core.MediaType;
import org.jclouds.date.internal.SimpleDateFormatDateService;
import org.jclouds.json.BaseItemParserTest;
import org.jclouds.openstack.domain.Link;
import org.jclouds.openstack.keystone.v2_0.domain.Access;
import org.jclouds.openstack.keystone.v2_0.domain.ApiMetadata;
import org.jclouds.openstack.keystone.v2_0.domain.Endpoint;
import org.jclouds.openstack.keystone.v2_0.domain.Role;
import org.jclouds.openstack.keystone.v2_0.domain.Service;
import org.jclouds.openstack.keystone.v2_0.domain.Tenant;
import org.jclouds.openstack.keystone.v2_0.domain.Token;
import org.jclouds.openstack.keystone.v2_0.domain.User;
import org.jclouds.rest.annotations.SelectJson;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableSet;
/**
* @author Adam Lowe
*/
@Test(groups = "unit", testName = "ParseApiMetadataTest")
public class ParseApiMetadataTest extends BaseItemParserTest<ApiMetadata> {
@Override
public String resource() {
return "/apiMetadataResponse.json";
}
@Override
@SelectJson("version")
@Consumes(MediaType.APPLICATION_JSON)
public ApiMetadata expected() {
return ApiMetadata.builder().id("v2.0")
.links(ImmutableSet.of(Link.builder().relation(Link.Relation.SELF).href(URI.create("http://172.16.89.140:5000/v2.0/")).build(),
Link.builder().relation(Link.Relation.DESCRIBEDBY).type("text/html").href(URI.create("http://docs.openstack.org/api/openstack-identity-service/2.0/content/")).build(),
Link.builder().relation(Link.Relation.DESCRIBEDBY).type("application/pdf").href(URI.create("http://docs.openstack.org/api/openstack-identity-service/2.0/identity-dev-guide-2.0.pdf")).build()
))
.status("beta")
.updated(new SimpleDateFormatDateService().iso8601SecondsDateParse("2011-11-19T00:00:00Z"))
.mediaTypes(ImmutableSet.of(
org.jclouds.openstack.keystone.v2_0.domain.MediaType.builder().base("application/json").type("application/vnd.openstack.identity-v2.0+json").build(),
org.jclouds.openstack.keystone.v2_0.domain.MediaType.builder().base("application/xml").type("application/vnd.openstack.identity-v2.0+xml").build()
))
.build();
}
}

View File

@ -0,0 +1,71 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.openstack.keystone.v2_0.suppliers;
import static org.testng.Assert.assertEquals;
import java.net.URI;
import java.util.Map;
import javax.inject.Singleton;
import org.jclouds.openstack.keystone.v2_0.domain.Access;
import org.jclouds.openstack.keystone.v2_0.parse.ParseAccessTest;
import org.testng.annotations.Test;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Provides;
import com.google.inject.assistedinject.FactoryModuleBuilder;
/**
* @author Adam Lowe
*/
@Test(groups = "unit", testName = "RegionIdToAdminURIFromAccessForTypeAndVersionSupplierTest")
public class RegionIdToAdminURIFromAccessForTypeAndVersionSupplierTest {
private final RegionIdToAdminURISupplier.Factory factory = Guice.createInjector(new AbstractModule() {
@Override
protected void configure() {
install(new FactoryModuleBuilder().implement(RegionIdToAdminURISupplier.class,
RegionIdToAdminURIFromAccessForTypeAndVersionSupplier.class).build(RegionIdToAdminURISupplier.Factory.class));
}
@SuppressWarnings("unused")
@Provides
@Singleton
public Supplier<Access> provide() {
return Suppliers.ofInstance(new ParseAccessTest().expected());
}
}).getInstance(RegionIdToAdminURISupplier.Factory.class);
public void testRegionMatches() {
assertEquals(Maps.transformValues(factory.createForApiTypeAndVersion("identity", "2.0").get(), Suppliers
.<URI> supplierFunction()), ImmutableMap.of("region-a.geo-1", URI.create("https://csnode.jclouds.org:35357/v2.0/")));
Map<String, URI> map = Maps.newLinkedHashMap();
map.put("region-a.geo-1", null);
assertEquals(Maps.transformValues(factory.createForApiTypeAndVersion("compute", "1.1").get(), Suppliers
.<URI> supplierFunction()), map);
}
}

View File

@ -0,0 +1 @@
{"version": {"status": "beta", "updated": "2011-11-19T00:00:00Z", "media-types": [{"base": "application/json", "type": "application/vnd.openstack.identity-v2.0+json"}, {"base": "application/xml", "type": "application/vnd.openstack.identity-v2.0+xml"}], "id": "v2.0", "links": [{"href": "http://172.16.89.140:5000/v2.0/", "rel": "self"}, {"href": "http://docs.openstack.org/api/openstack-identity-service/2.0/content/", "type": "text/html", "rel": "describedby"}, {"href": "http://docs.openstack.org/api/openstack-identity-service/2.0/identity-dev-guide-2.0.pdf", "type": "application/pdf", "rel": "describedby"}]}}

View File

@ -56,9 +56,11 @@
"type": "identity",
"endpoints": [
{
"adminURL": "https://csnode.jclouds.org:35357/v2.0/",
"publicURL": "https://csnode.jclouds.org/v2.0/",
"region": "region-a.geo-1",
"id": "2.0",
"versionId":"2.0",
"list": "https://csnode.jclouds.org/extension"
}
]

View File

@ -367,12 +367,15 @@ public abstract class BaseRestClientExpectTest<S> {
*/
public boolean httpRequestsAreEqual(HttpRequest a, HttpRequest b) {
try {
if (a == null || b == null) {
return false;
}
if (a.getPayload() == null || b.getPayload() == null) {
return Objects.equal(a, b);
}
switch (compareHttpRequestAsType(a)) {
case XML: {
if (a == null || b == null || a.getPayload() == null || b.getPayload() == null) {
return false;
}
Diff diff = XMLUnit.compareXML(Strings2.toStringAndClose(a.getPayload().getInput()), Strings2
.toStringAndClose(b.getPayload().getInput()));
@ -404,10 +407,7 @@ public abstract class BaseRestClientExpectTest<S> {
return diff.identical() && Objects.equal(a.getHeaders(), b.getHeaders());
}
case JSON: {
if (a == null || b == null || a.getPayload() == null || b.getPayload() == null) {
return false;
}
case JSON: {
JsonParser parser = new JsonParser();
JsonElement payloadA = parser.parse(Strings2.toStringAndClose(a.getPayload().getInput()));
JsonElement payloadB = parser.parse(Strings2.toStringAndClose(b.getPayload().getInput()));

View File

@ -0,0 +1,134 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to jclouds, Inc. (jclouds) under one or more
contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. jclouds 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.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.jclouds</groupId>
<artifactId>jclouds-project</artifactId>
<version>1.5.0-SNAPSHOT</version>
<relativePath>../../project/pom.xml</relativePath>
</parent>
<groupId>org.jclouds.labs</groupId>
<artifactId>openstack-keystone</artifactId>
<name>jcloud openstack-keystone api</name>
<description>jclouds components to access an implementation of OpenStack Keystone</description>
<packaging>bundle</packaging>
<properties>
<!-- keystone endpoint -->
<test.openstack-keystone.endpoint>http://localhost:5000</test.openstack-keystone.endpoint>
<!-- keystone version -->
<test.openstack-keystone.api-version>2.0</test.openstack-keystone.api-version>
<test.openstack-keystone.build-version></test.openstack-keystone.build-version>
<test.openstack-keystone.identity>FIXME_IDENTITY</test.openstack-keystone.identity>
<test.openstack-keystone.credential>FIXME_CREDENTIALS</test.openstack-keystone.credential>
<test.jclouds.keystone.credential-type>passwordCredentials</test.jclouds.keystone.credential-type>
</properties>
<dependencies>
<dependency>
<groupId>org.jclouds.common</groupId>
<artifactId>openstack-common</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.jclouds</groupId>
<artifactId>jclouds-core</artifactId>
<version>${project.version}</version>
<type>test-jar</type>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jclouds.common</groupId>
<artifactId>openstack-common</artifactId>
<version>${project.version}</version>
<type>test-jar</type>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jclouds.driver</groupId>
<artifactId>jclouds-slf4j</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.0.0</version>
<scope>test</scope>
</dependency>
</dependencies>
<profiles>
<profile>
<id>live</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<executions>
<execution>
<id>integration</id>
<phase>integration-test</phase>
<goals>
<goal>test</goal>
</goals>
<configuration>
<systemPropertyVariables>
<test.openstack-keystone.endpoint>${test.openstack-keystone.endpoint}</test.openstack-keystone.endpoint>
<test.openstack-keystone.api-version>${test.openstack-keystone.api-version}</test.openstack-keystone.api-version>
<test.openstack-keystone.build-version>${test.openstack-keystone.build-version}</test.openstack-keystone.build-version>
<test.openstack-keystone.identity>${test.openstack-keystone.identity}</test.openstack-keystone.identity>
<test.openstack-keystone.credential>${test.openstack-keystone.credential}</test.openstack-keystone.credential>
<test.jclouds.keystone.credential-type>${test.jclouds.keystone.credential-type}</test.jclouds.keystone.credential-type>
</systemPropertyVariables>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
<build>
<plugins>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<configuration>
<instructions>
<Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
<Export-Package>org.jclouds.openstack.keystone.v2_0*;version="${project.version}"</Export-Package>
<Import-Package>
org.jclouds.rest.internal;version="${project.version}",
org.jclouds*;version="${project.version}",
*
</Import-Package>
</instructions>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,177 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.openstack.keystone.v2_0;
import java.util.Set;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.HEAD;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import org.jclouds.openstack.filters.AuthenticateRequest;
import org.jclouds.openstack.keystone.v2_0.domain.ApiMetadata;
import org.jclouds.openstack.keystone.v2_0.domain.Endpoint;
import org.jclouds.openstack.keystone.v2_0.domain.Role;
import org.jclouds.openstack.keystone.v2_0.domain.Tenant;
import org.jclouds.openstack.keystone.v2_0.domain.Token;
import org.jclouds.openstack.keystone.v2_0.domain.User;
import org.jclouds.rest.annotations.ExceptionParser;
import org.jclouds.rest.annotations.RequestFilters;
import org.jclouds.rest.annotations.SelectJson;
import org.jclouds.rest.annotations.SkipEncoding;
import org.jclouds.rest.functions.ReturnEmptySetOnNotFoundOr404;
import org.jclouds.rest.functions.ReturnFalseOnNotFoundOr404;
import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
import com.google.common.util.concurrent.ListenableFuture;
/**
* Provides asynchronous access to Admin via their REST API.
* <p/>
*
* @see AdminClient
* @see <a href=
* "http://docs.openstack.org/api/openstack-identity-service/2.0/content/Admin_API_Service_Developer_Operations-d1e1356.html"
* />
* @author Adam Lowe
*/
@SkipEncoding({ '/', '=' })
public interface AdminAsyncClient {
/**
* @see AdminClient#getApiMetadata()
*/
@GET
@SelectJson("version")
@Consumes(MediaType.APPLICATION_JSON)
@Path("/")
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
ListenableFuture<ApiMetadata> getApiMetadata();
/**
* @see AdminClient#listTenants()
*/
@GET
@SelectJson("tenants")
@Consumes(MediaType.APPLICATION_JSON)
@Path("/tenants")
@RequestFilters(AuthenticateRequest.class)
@ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
ListenableFuture<Set<Tenant>> listTenants();
/** @see AdminClient#getToken(String) */
@GET
@SelectJson("token")
@Consumes(MediaType.APPLICATION_JSON)
@Path("/tokens/{token}")
@RequestFilters(AuthenticateRequest.class)
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
ListenableFuture<Token> getToken(@PathParam("token") String token);
/** @see AdminClient#getUserOfToken(String) */
@GET
@SelectJson("user")
@Consumes(MediaType.APPLICATION_JSON)
@Path("/tokens/{token}")
@RequestFilters(AuthenticateRequest.class)
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
ListenableFuture<User> getUserOfToken(@PathParam("token") String token);
/** @see AdminClient#checkTokenIsValid(String) */
@HEAD
@Path("/tokens/{token}")
@RequestFilters(AuthenticateRequest.class)
@ExceptionParser(ReturnFalseOnNotFoundOr404.class)
ListenableFuture<Boolean> checkTokenIsValid(@PathParam("token") String token);
/** @see AdminClient#getEndpointsForToken(String) */
@GET
@SelectJson("endpoints")
@Consumes(MediaType.APPLICATION_JSON)
@Path("/tokens/{token}/endpoints")
@RequestFilters(AuthenticateRequest.class)
@ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
ListenableFuture<Set<Endpoint>> getEndpointsForToken(@PathParam("token") String token);
/** @see AdminClient#getTenant(String) */
@GET
@SelectJson("tenant")
@Consumes(MediaType.APPLICATION_JSON)
@Path("/tenants/{tenantId}")
@RequestFilters(AuthenticateRequest.class)
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
ListenableFuture<Tenant> getTenant(@PathParam("tenantId") String tenantId);
/** @see AdminClient#getTenantByName(String) */
@GET
@SelectJson("tenant")
@Consumes(MediaType.APPLICATION_JSON)
@Path("/tenants")
@RequestFilters(AuthenticateRequest.class)
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
ListenableFuture<Tenant> getTenantByName(@QueryParam("name") String tenantName);
/** @see AdminClient#listUsers() */
@GET
@SelectJson("users")
@Consumes(MediaType.APPLICATION_JSON)
@Path("/users")
@RequestFilters(AuthenticateRequest.class)
@ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
ListenableFuture<Set<User>> listUsers();
/** @see AdminClient#getUser(String) */
@GET
@SelectJson("user")
@Consumes(MediaType.APPLICATION_JSON)
@Path("/users/{userId}")
@RequestFilters(AuthenticateRequest.class)
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
ListenableFuture<User> getUser(@PathParam("userId") String userId);
/** @see AdminClient#getUserByName(String) */
@GET
@SelectJson("user")
@Consumes(MediaType.APPLICATION_JSON)
@Path("/users")
@RequestFilters(AuthenticateRequest.class)
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
ListenableFuture<User> getUserByName(@QueryParam("name") String userName);
/** @see AdminClient#listRolesOfUser(String) */
@GET
@SelectJson("roles")
@Consumes(MediaType.APPLICATION_JSON)
@Path("/users/{userId}/roles")
@RequestFilters(AuthenticateRequest.class)
@ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
ListenableFuture<Set<Role>> listRolesOfUser(@PathParam("userId") String userId);
/** @see AdminClient#listRolesOfUserOnTenant(String, String) */
@GET
@SelectJson("roles")
@Consumes(MediaType.APPLICATION_JSON)
@Path("/tenants/{tenantId}/users/{userId}/roles")
@RequestFilters(AuthenticateRequest.class)
@ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
ListenableFuture<Set<Role>> listRolesOfUserOnTenant(@PathParam("userId") String userId, @PathParam("tenantId") String tenantId);
}

View File

@ -0,0 +1,145 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.openstack.keystone.v2_0;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import org.jclouds.concurrent.Timeout;
import org.jclouds.openstack.keystone.v2_0.domain.ApiMetadata;
import org.jclouds.openstack.keystone.v2_0.domain.Endpoint;
import org.jclouds.openstack.keystone.v2_0.domain.Role;
import org.jclouds.openstack.keystone.v2_0.domain.Tenant;
import org.jclouds.openstack.keystone.v2_0.domain.Token;
import org.jclouds.openstack.keystone.v2_0.domain.User;
/**
* Provides synchronous access to the KeyStone Admin API.
* <p/>
*
* @author Adam Lowe
* @see AdminAsyncClient
* @see <a href=
* "http://docs.openstack.org/api/openstack-identity-service/2.0/content/Admin_API_Service_Developer_Operations-d1e1356.html"
* />
*/
@Timeout(duration = 30, timeUnit = TimeUnit.SECONDS)
public interface AdminClient {
/**
* Discover API version information, links to documentation (PDF, HTML, WADL), and supported media types
*
* @return the requested information
*/
ApiMetadata getApiMetadata();
/**
* The operation returns a list of tenants which the current token provides access to.
*/
Set<Tenant> listTenants();
/**
* Retrieve information about a tenant, by tenant ID
*
* @return the information about the tenant
*/
Tenant getTenant(String tenantId);
/**
* Retrieve information about a tenant, by tenant name
* <p/>
* NOTE: currently not working in openstack ( https://bugs.launchpad.net/keystone/+bug/956687 )
*
* @return the information about the tenant
*/
Tenant getTenantByName(String tenantName);
/**
* Validate a token and, if it is valid, return access information regarding the tenant (though not the service catalog)/
*
* @return the requested information
*/
Token getToken(String token);
/**
* Validate a token and, if it is valid, return access information regarding the tenant (though not the service catalog)/
*
* @return the requested information
*/
User getUserOfToken(String token);
/**
* Validate a token. This is a high-performance variant of the #getToken() call that does not return any further
* information.
*
* @return true if the token is valid
*/
Boolean checkTokenIsValid(String token);
/**
* List all endpoints for a token
* <p/>
* NOTE: currently not working in openstack ( https://bugs.launchpad.net/keystone/+bug/988672 )
*
* @return the set of endpoints
*/
Set<Endpoint> getEndpointsForToken(String token);
/**
* Retrieve the list of users
* <p/>
* NOTE: this method is not in API documentation for keystone, but does work
*
* @return the list of users
*/
Set<User> listUsers();
/**
* Retrieve information about a user, by user ID
*
* @return the information about the user
*/
User getUser(String userId);
/**
* Retrieve information about a user, by user name
* <p/>
* NOTE: currently not working in openstack ( https://bugs.launchpad.net/keystone/+bug/956687 )
*
* @return the information about the user
*/
User getUserByName(String userName);
/**
* Retrieves the list of global roles associated with a specific user (excludes tenant roles).
* <p/>
* NOTE: Broken in openstack ( https://bugs.launchpad.net/keystone/+bug/933565 )
*
* @return the set of Roles granted to the user
*/
Set<Role> listRolesOfUser(String userId);
/**
* List the roles a user has been granted on a specific tenant
*
* @return the set of roles
*/
Set<Role> listRolesOfUserOnTenant(String userId, String tenantId);
}

View File

@ -0,0 +1,102 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.openstack.keystone.v2_0;
import static org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties.SERVICE_TYPE;
import java.net.URI;
import java.util.Properties;
import org.jclouds.apis.ApiMetadata;
import org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties;
import org.jclouds.openstack.keystone.v2_0.config.KeystoneRestClientModule;
import org.jclouds.openstack.services.ServiceType;
import org.jclouds.rest.RestContext;
import org.jclouds.rest.internal.BaseRestApiMetadata;
import com.google.common.collect.ImmutableSet;
import com.google.common.reflect.TypeToken;
import com.google.inject.Module;
/**
* Implementation of {@link org.jclouds.apis.ApiMetadata} for Keystone 2.0 API
*
* @author Adrian Cole
*/
public class KeystoneApiMetadata extends BaseRestApiMetadata {
/** The serialVersionUID */
private static final long serialVersionUID = 6725672099385580694L;
public static final TypeToken<RestContext<KeystoneClient, KeystoneAsyncClient>> CONTEXT_TOKEN = new TypeToken<RestContext<KeystoneClient, KeystoneAsyncClient>>() {
};
@Override
public Builder toBuilder() {
return new Builder().fromApiMetadata(this);
}
public KeystoneApiMetadata() {
this(new Builder());
}
protected KeystoneApiMetadata(Builder builder) {
super(builder);
}
public static Properties defaultProperties() {
Properties properties = BaseRestApiMetadata.defaultProperties();
// auth fail can happen while cloud-init applies keypair updates
properties.setProperty("jclouds.ssh.max-retries", "7");
properties.setProperty("jclouds.ssh.retry-auth", "true");
// TODO: this doesn't actually do anything yet.
properties.setProperty(KeystoneProperties.VERSION, "2.0");
properties.put(SERVICE_TYPE, ServiceType.IDENTITY);
return properties;
}
public static class Builder extends BaseRestApiMetadata.Builder {
protected Builder() {
super(KeystoneClient.class, KeystoneAsyncClient.class);
id("openstack-keystone")
.name("OpenStack Keystone Essex+ API")
.identityName("tenantId:user")
.credentialName("password")
.documentation(URI.create("http://api.openstack.org/"))
.version("2.0")
.defaultEndpoint("http://localhost:5000")
.defaultProperties(KeystoneApiMetadata.defaultProperties())
.defaultModules(ImmutableSet.<Class<? extends Module>>of(KeystoneRestClientModule.class));
}
@Override
public KeystoneApiMetadata build() {
return new KeystoneApiMetadata(this);
}
@Override
public Builder fromApiMetadata(ApiMetadata in) {
super.fromApiMetadata(in);
return this;
}
}
}

View File

@ -0,0 +1,59 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.openstack.keystone.v2_0;
import java.util.Set;
import javax.ws.rs.Path;
import org.jclouds.Constants;
import org.jclouds.javax.annotation.Nullable;
import org.jclouds.location.Region;
import org.jclouds.location.functions.RegionToEndpoint;
import org.jclouds.openstack.keystone.v2_0.functions.RegionToAdminEndpointURI;
import org.jclouds.rest.annotations.Delegate;
import org.jclouds.rest.annotations.EndpointParam;
import com.google.inject.Provides;
/**
* Provides access to Openstack keystone resources via their REST API.
* <p/>
*
* @author Adam Lowe
* @see <a href="http://keystone.openstack.org/" />
* @see KeystoneClient
*/
@Path("/v{" + Constants.PROPERTY_API_VERSION + "}")
public interface KeystoneAsyncClient {
/**
* @return the Region codes configured
*/
@Provides
@Region
Set<String> getConfiguredRegions();
/** Provides asynchronous access to Identity user-accessible features */
@Delegate
ServiceAsyncClient getServiceClientForRegion(@EndpointParam(parser = RegionToEndpoint.class) @Nullable String region);
/** Provides asynchronous access to the KeyStone Admin API */
@Delegate
AdminAsyncClient getAdminClientForRegion(@EndpointParam(parser = RegionToAdminEndpointURI.class) @Nullable String region);
}

View File

@ -0,0 +1,58 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.openstack.keystone.v2_0;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import org.jclouds.concurrent.Timeout;
import org.jclouds.javax.annotation.Nullable;
import org.jclouds.location.Region;
import org.jclouds.location.functions.RegionToEndpoint;
import org.jclouds.openstack.keystone.v2_0.functions.RegionToAdminEndpointURI;
import org.jclouds.rest.annotations.Delegate;
import org.jclouds.rest.annotations.EndpointParam;
import com.google.inject.Provides;
/**
* Provides access to Openstack keystone resources via their REST API.
* <p/>
*
* @author Adam Lowe
* @see <a href="http://keystone.openstack.org/" />
*/
@Timeout(duration = 10, timeUnit = TimeUnit.SECONDS)
public interface KeystoneClient {
/**
* @return the Region codes configured
*/
@Provides
@Region
Set<String> getConfiguredRegions();
/** Provides synchronous access to Identity user-accessible features */
@Delegate
ServiceClient getServiceClientForRegion(@EndpointParam(parser = RegionToEndpoint.class) @Nullable String region);
/** Provides synchronous access to the KeyStone Admin API */
@Delegate
AdminClient getAdminClientForRegion(@EndpointParam(parser = RegionToAdminEndpointURI.class) @Nullable String region);
}

View File

@ -0,0 +1,71 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.openstack.keystone.v2_0;
import java.util.Set;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.core.MediaType;
import org.jclouds.openstack.filters.AuthenticateRequest;
import org.jclouds.openstack.keystone.v2_0.domain.ApiMetadata;
import org.jclouds.openstack.keystone.v2_0.domain.Tenant;
import org.jclouds.rest.annotations.ExceptionParser;
import org.jclouds.rest.annotations.RequestFilters;
import org.jclouds.rest.annotations.SelectJson;
import org.jclouds.rest.annotations.SkipEncoding;
import org.jclouds.rest.functions.ReturnEmptySetOnNotFoundOr404;
import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
import com.google.common.util.concurrent.ListenableFuture;
/**
* Provides asynchronous access to Service via their REST API.
* <p/>
*
* @see ServiceClient
* @see <a href="http://docs.openstack.org/api/openstack-identity-service/2.0/content/Service_API_Client_Operations.html"
* />
* @author Adam Lowe
*/
@SkipEncoding({ '/', '=' })
public interface ServiceAsyncClient {
/**
* @see ServiceClient#getApiMetadata()
*/
@GET
@SelectJson("version")
@Consumes(MediaType.APPLICATION_JSON)
@Path("/")
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
ListenableFuture<ApiMetadata> getApiMetadata();
/**
* @see ServiceClient#listTenants()
*/
@GET
@SelectJson("tenants")
@Consumes(MediaType.APPLICATION_JSON)
@Path("/tenants")
@RequestFilters(AuthenticateRequest.class)
@ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
ListenableFuture<Set<Tenant>> listTenants();
}

View File

@ -0,0 +1,51 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.openstack.keystone.v2_0;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import org.jclouds.concurrent.Timeout;
import org.jclouds.openstack.keystone.v2_0.domain.ApiMetadata;
import org.jclouds.openstack.keystone.v2_0.domain.Tenant;
/**
* Provides synchronous access to the KeyStone Service API.
* <p/>
*
* @author Adam Lowe
* @see ServiceAsyncClient
* @see <a href="http://docs.openstack.org/api/openstack-identity-service/2.0/content/Service_API_Client_Operations.html"
* />
*/
@Timeout(duration = 30, timeUnit = TimeUnit.SECONDS)
public interface ServiceClient {
/**
* Discover API version information, links to documentation (PDF, HTML, WADL), and supported media types
*
* @return the requested information
*/
ApiMetadata getApiMetadata();
/**
* The operation returns a list of tenants which the current token provides access to.
*/
Set<Tenant> listTenants();
}

View File

@ -0,0 +1,36 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.openstack.keystone.v2_0.config;
import org.jclouds.json.config.GsonModule;
import org.jclouds.json.config.GsonModule.DateAdapter;
import com.google.inject.AbstractModule;
/**
* @author Adam Lowe
*/
public class KeystoneParserModule extends AbstractModule {
@Override
protected void configure() {
bind(DateAdapter.class).to(GsonModule.Iso8601DateAdapter.class);
}
}

View File

@ -0,0 +1,76 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.openstack.keystone.v2_0.config;
import java.util.Map;
import org.jclouds.http.HttpErrorHandler;
import org.jclouds.http.annotation.ClientError;
import org.jclouds.http.annotation.Redirection;
import org.jclouds.http.annotation.ServerError;
import org.jclouds.openstack.keystone.v2_0.AdminAsyncClient;
import org.jclouds.openstack.keystone.v2_0.AdminClient;
import org.jclouds.openstack.keystone.v2_0.KeystoneAsyncClient;
import org.jclouds.openstack.keystone.v2_0.KeystoneClient;
import org.jclouds.openstack.keystone.v2_0.ServiceAsyncClient;
import org.jclouds.openstack.keystone.v2_0.ServiceClient;
import org.jclouds.openstack.keystone.v2_0.handlers.KeystoneErrorHandler;
import org.jclouds.rest.ConfiguresRestClient;
import org.jclouds.rest.config.RestClientModule;
import com.google.common.collect.ImmutableMap;
/**
* Configures the Keystone connection.
*
* @author Adam Lowe
*/
@ConfiguresRestClient
public class KeystoneRestClientModule extends RestClientModule<KeystoneClient, KeystoneAsyncClient> {
public static final Map<Class<?>, Class<?>> DELEGATE_MAP = ImmutableMap.<Class<?>, Class<?>> builder()
.put(ServiceClient.class, ServiceAsyncClient.class).put(AdminClient.class, AdminAsyncClient.class)
.build();
public KeystoneRestClientModule() {
super(DELEGATE_MAP);
}
@Override
protected void configure() {
install(new KeystoneParserModule());
super.configure();
}
@Override
protected void installLocations() {
// TODO: select this from KeystoneProperties.VERSION; note you select from
// a guice provided property, so it will have to come from somewhere else, maybe we move
// this to the the ContextBuilder
install(KeystoneAuthenticationModule.forRegions());
super.installLocations();
}
@Override
protected void bindErrorHandlers() {
bind(HttpErrorHandler.class).annotatedWith(Redirection.class).to(KeystoneErrorHandler.class);
bind(HttpErrorHandler.class).annotatedWith(ClientError.class).to(KeystoneErrorHandler.class);
bind(HttpErrorHandler.class).annotatedWith(ServerError.class).to(KeystoneErrorHandler.class);
}
}

View File

@ -0,0 +1,65 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.openstack.keystone.v2_0.handlers;
import static org.jclouds.http.HttpUtils.closeClientButKeepContentStream;
import javax.inject.Singleton;
import org.jclouds.http.HttpCommand;
import org.jclouds.http.HttpErrorHandler;
import org.jclouds.http.HttpResponse;
import org.jclouds.http.HttpResponseException;
import org.jclouds.rest.AuthorizationException;
import org.jclouds.rest.ResourceNotFoundException;
/**
* This will parse and set an appropriate exception on the command object.
*
* @author Adam Lowe
*
*/
// TODO: is there error spec someplace? let's type errors, etc.
@Singleton
public class KeystoneErrorHandler implements HttpErrorHandler {
public void handleError(HttpCommand command, HttpResponse response) {
// it is important to always read fully and close streams
byte[] data = closeClientButKeepContentStream(response);
String message = data != null ? new String(data) : null;
Exception exception = message != null ? new HttpResponseException(command, response, message)
: new HttpResponseException(command, response);
message = message != null ? message : String.format("%s -> %s", command.getCurrentRequest().getRequestLine(),
response.getStatusLine());
switch (response.getStatusCode()) {
case 400:
break;
case 401:
case 403:
exception = new AuthorizationException(message, exception);
break;
case 404:
if (!command.getCurrentRequest().getMethod().equals("DELETE")) {
exception = new ResourceNotFoundException(message, exception);
}
break;
}
command.setException(exception);
}
}

View File

@ -0,0 +1 @@
org.jclouds.openstack.keystone.v2_0.KeystoneApiMetadata

View File

@ -0,0 +1,379 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 1.1 (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-1.1
*
* 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.openstack.keystone.v2_0;
import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertNull;
import static org.testng.Assert.assertTrue;
import java.net.URI;
import java.util.Set;
import org.jclouds.date.DateService;
import org.jclouds.date.internal.SimpleDateFormatDateService;
import org.jclouds.http.HttpResponseException;
import org.jclouds.openstack.domain.Link;
import org.jclouds.openstack.keystone.v2_0.domain.ApiMetadata;
import org.jclouds.openstack.keystone.v2_0.domain.Endpoint;
import org.jclouds.openstack.keystone.v2_0.domain.MediaType;
import org.jclouds.openstack.keystone.v2_0.domain.Role;
import org.jclouds.openstack.keystone.v2_0.domain.Tenant;
import org.jclouds.openstack.keystone.v2_0.domain.Token;
import org.jclouds.openstack.keystone.v2_0.domain.User;
import org.jclouds.openstack.keystone.v2_0.internal.BaseKeystoneRestClientExpectTest;
import org.jclouds.rest.AuthorizationException;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.ImmutableSet;
/**
* Tests parsing and Guice wiring of UserClient
*
* @author Adam Lowe
*/
public class AdminClientExpectTest extends BaseKeystoneRestClientExpectTest<KeystoneClient> {
private DateService dateService = new SimpleDateFormatDateService();
public AdminClientExpectTest() {
endpoint = "https://csnode.jclouds.org:35357";
}
public void testGetApiMetaData() {
AdminClient client = requestsSendResponses(
keystoneAuthWithUsernameAndPassword, responseWithKeystoneAccess,
standardRequestBuilder(endpoint + "/v2.0/").
headers(ImmutableMultimap.of("Accept", APPLICATION_JSON)).build(),
standardResponseBuilder(200).payload(payloadFromResourceWithContentType("/api_metadata.json", APPLICATION_JSON)).build())
.getAdminClientForRegion("region-a.geo-1");
ApiMetadata metadata = client.getApiMetadata();
assertNotNull(metadata);
assertEquals(metadata.getId(), "v2.0");
ApiMetadata expected = ApiMetadata.builder().id("v2.0")
.links(ImmutableSet.of(Link.builder().relation(Link.Relation.SELF).href(URI.create("http://172.16.89.140:5000/v2.0/")).build(),
Link.builder().relation(Link.Relation.DESCRIBEDBY).type("text/html").href(URI.create("http://docs.openstack.org/api/openstack-identity-service/2.0/content/")).build(),
Link.builder().relation(Link.Relation.DESCRIBEDBY).type("application/pdf").href(URI.create("http://docs.openstack.org/api/openstack-identity-service/2.0/identity-dev-guide-2.0.pdf")).build()
))
.status("beta")
.updated(new SimpleDateFormatDateService().iso8601SecondsDateParse("2011-11-19T00:00:00Z"))
.mediaTypes(ImmutableSet.of(
MediaType.builder().base("application/json").type("application/vnd.openstack.identity-v2.0+json").build(),
MediaType.builder().base("application/xml").type("application/vnd.openstack.identity-v2.0+xml").build()
))
.build();
assertEquals(metadata, expected);
}
public void testGetApiMetaDataFailNotFound() {
AdminClient client = requestsSendResponses(
keystoneAuthWithUsernameAndPassword, responseWithKeystoneAccess,
standardRequestBuilder(endpoint + "/v2.0/").headers(ImmutableMultimap.of("Accept", APPLICATION_JSON)).build(),
standardResponseBuilder(404).build()).getAdminClientForRegion("region-a.geo-1");
assertNull(client.getApiMetadata());
}
public void testListTenants() {
AdminClient client = requestsSendResponses(
keystoneAuthWithUsernameAndPassword, responseWithKeystoneAccess,
standardRequestBuilder(endpoint + "/v2.0/tenants").build(),
standardResponseBuilder(200).payload(payloadFromResourceWithContentType("/tenant_list.json", APPLICATION_JSON)).build())
.getAdminClientForRegion("region-a.geo-1");
Set<Tenant> tenants = client.listTenants();
assertNotNull(tenants);
assertFalse(tenants.isEmpty());
Set<Tenant> expected = ImmutableSet.of(
Tenant.builder().name("demo").id("05d1dc7af71646deba64cfc17b81bec0").build(),
Tenant.builder().name("admin").id("7aa2e17ec29f44d193c48feaba0852cc").build()
);
assertEquals(tenants, expected);
}
public void testListTenantsFailNotFound() {
AdminClient client = requestsSendResponses(
keystoneAuthWithUsernameAndPassword, responseWithKeystoneAccess,
standardRequestBuilder(endpoint + "/v2.0/tenants").build(),
standardResponseBuilder(404).build()).getAdminClientForRegion("region-a.geo-1");
assertTrue(client.listTenants().isEmpty());
}
public void testGetTenant() {
AdminClient client = requestsSendResponses(
keystoneAuthWithUsernameAndPassword, responseWithKeystoneAccess,
standardRequestBuilder(endpoint + "/v2.0/tenants/013ba41150a14830bec85ffe93353bcc").build(),
standardResponseBuilder(200).payload(payloadFromResourceWithContentType("/tenant_details.json", APPLICATION_JSON)).build())
.getAdminClientForRegion("region-a.geo-1");
Tenant tenant = client.getTenant("013ba41150a14830bec85ffe93353bcc");
assertNotNull(tenant);
assertEquals(tenant, Tenant.builder().id("013ba41150a14830bec85ffe93353bcc").name("admin").build());
}
@Test(expectedExceptions = AuthorizationException.class)
public void testListTenantsFailNotAuthorized() {
AdminClient client = requestsSendResponses(
keystoneAuthWithUsernameAndPassword, responseWithKeystoneAccess,
standardRequestBuilder(endpoint + "/v2.0/tenants/013ba41150a14830bec85ffe93353bcc").build(),
standardResponseBuilder(401).build()).getAdminClientForRegion("region-a.geo-1");
client.getTenant("013ba41150a14830bec85ffe93353bcc");
}
public void testGetTenantByName() {
AdminClient client = requestsSendResponses(
keystoneAuthWithUsernameAndPassword, responseWithKeystoneAccess,
standardRequestBuilder(endpoint + "/v2.0/tenants?name=admin").build(),
standardResponseBuilder(200).payload(payloadFromResourceWithContentType("/tenant_details.json", APPLICATION_JSON)).build())
.getAdminClientForRegion("region-a.geo-1");
Tenant tenant = client.getTenantByName("admin");
assertNotNull(tenant);
assertEquals(tenant, Tenant.builder().id("013ba41150a14830bec85ffe93353bcc").name("admin").build());
}
public void testGetTenantByNameFailNotFound() {
AdminClient client = requestsSendResponses(
keystoneAuthWithUsernameAndPassword, responseWithKeystoneAccess,
standardRequestBuilder(endpoint + "/v2.0/tenants?name=admin").build(),
standardResponseBuilder(404).build()).getAdminClientForRegion("region-a.geo-1");
assertNull(client.getTenantByName("admin"));
}
public void testGetToken() {
AdminClient client = requestsSendResponses(
keystoneAuthWithUsernameAndPassword, responseWithKeystoneAccess,
standardRequestBuilder(endpoint + "/v2.0/tokens/sometokenorother").build(),
standardResponseBuilder(200).payload(payloadFromResourceWithContentType("/token_details.json", APPLICATION_JSON)).build())
.getAdminClientForRegion("region-a.geo-1");
Token token = client.getToken("sometokenorother");
assertNotNull(token);
assertEquals(token,
Token.builder().id("167eccdc790946969ced473732e8109b").expires(dateService.iso8601SecondsDateParse("2012-04-28T12:42:50Z"))
.tenant(Tenant.builder().id("4cea93f5464b4f1c921fb3e0461d72b5").name("demo").build()).build());
}
public void testGetTokenFailNotFound() {
AdminClient client = requestsSendResponses(
keystoneAuthWithUsernameAndPassword, responseWithKeystoneAccess,
standardRequestBuilder(endpoint + "/v2.0/tokens/sometokenorother").build(),
standardResponseBuilder(404).build())
.getAdminClientForRegion("region-a.geo-1");
assertNull(client.getToken("sometokenorother"));
}
@Test(expectedExceptions = HttpResponseException.class)
public void testGetTokenFail500() {
AdminClient client = requestsSendResponses(
keystoneAuthWithUsernameAndPassword, responseWithKeystoneAccess,
standardRequestBuilder(endpoint + "/v2.0/tokens/sometokenorother").build(),
standardResponseBuilder(500).build()).getAdminClientForRegion("region-a.geo-1");
client.getToken("sometokenorother");
}
public void testGetUserOfToken() {
AdminClient client = requestsSendResponses(
keystoneAuthWithUsernameAndPassword, responseWithKeystoneAccess,
standardRequestBuilder(endpoint + "/v2.0/tokens/sometokenorother").build(),
standardResponseBuilder(200).payload(payloadFromResourceWithContentType("/token_details.json", APPLICATION_JSON)).build())
.getAdminClientForRegion("region-a.geo-1");
User user = client.getUserOfToken("sometokenorother");
assertNotNull(user);
assertEquals(user, User.builder().id("2b9b606181634ae9ac86fd95a8bc2cde").name("admin")
.roles(ImmutableSet.of(Role.builder().id("79cada5c02814b57a52e0eed4dd388cb").name("admin").build()))
.build());
}
public void testGetUserOfTokenFailNotFound() {
AdminClient client = requestsSendResponses(
keystoneAuthWithUsernameAndPassword, responseWithKeystoneAccess,
standardRequestBuilder(endpoint + "/v2.0/tokens/sometokenorother").build(),
standardResponseBuilder(404).build()).getAdminClientForRegion("region-a.geo-1");
assertNull(client.getUserOfToken("sometokenorother"));
}
public void testCheckTokenIsValid() {
AdminClient client = requestsSendResponses(
keystoneAuthWithUsernameAndPassword, responseWithKeystoneAccess,
standardRequestBuilder(endpoint + "/v2.0/tokens/sometokenorother").method("HEAD")
.headers(ImmutableMultimap.of("X-Auth-Token", authToken)).build(),
standardResponseBuilder(200).payload(payloadFromResourceWithContentType("/token_details.json", APPLICATION_JSON)).build())
.getAdminClientForRegion("region-a.geo-1");
assertTrue(client.checkTokenIsValid("sometokenorother"));
}
public void testCheckTokenIsValidFailNotValid() {
AdminClient client = requestsSendResponses(
keystoneAuthWithUsernameAndPassword, responseWithKeystoneAccess,
standardRequestBuilder(endpoint + "/v2.0/tokens/sometokenorother").method("HEAD")
.headers(ImmutableMultimap.of("X-Auth-Token", authToken)).build(),
standardResponseBuilder(404).build()).getAdminClientForRegion("region-a.geo-1");
assertFalse(client.checkTokenIsValid("sometokenorother"));
}
@Test
public void testGetEndpointsForToken() {
AdminClient client = requestsSendResponses(
keystoneAuthWithUsernameAndPassword, responseWithKeystoneAccess,
standardRequestBuilder(endpoint + "/v2.0/tokens/XXXXXX/endpoints").build(),
standardResponseBuilder(200).payload(payloadFromResourceWithContentType("/user_endpoints.json", APPLICATION_JSON)).build())
.getAdminClientForRegion("region-a.geo-1");
Set<Endpoint> endpoints = client.getEndpointsForToken("XXXXXX");
assertEquals(endpoints, ImmutableSet.of(
Endpoint.builder().publicURL(URI.create("https://csnode.jclouds.org/v2.0/"))
.adminURL(URI.create("https://csnode.jclouds.org:35357/v2.0/"))
.region("region-a.geo-1").versionId("2.0").build()
));
}
@Test
public void testGetEndpointsForTokenFailNotFound() {
AdminClient client = requestsSendResponses(
keystoneAuthWithUsernameAndPassword, responseWithKeystoneAccess,
standardRequestBuilder(endpoint + "/v2.0/tokens/XXXXXX/endpoints").build(),
standardResponseBuilder(404).build())
.getAdminClientForRegion("region-a.geo-1");
assertTrue(client.getEndpointsForToken("XXXXXX").isEmpty());
}
public void testListUsers() {
AdminClient client = requestsSendResponses(
keystoneAuthWithUsernameAndPassword, responseWithKeystoneAccess,
standardRequestBuilder(endpoint + "/v2.0/users").build(),
standardResponseBuilder(200).payload(payloadFromResourceWithContentType("/user_list.json", APPLICATION_JSON)).build())
.getAdminClientForRegion("region-a.geo-1");
Set<User> users = client.listUsers();
assertNotNull(users);
assertFalse(users.isEmpty());
Set<User> expected = ImmutableSet.of(
User.builder().name("nova").id("e021dfd758eb44a89f1c57c8ef3be8e2").build(),
User.builder().name("glance").id("3f6c1c9ba993495ead7d2eb2192e284f").build(),
User.builder().name("demo").id("667b2e1420604df8b67cd8ea57d4ee64").build(),
User.builder().name("admin").id("2b9b606181634ae9ac86fd95a8bc2cde").build()
);
assertEquals(users, expected);
}
@Test(expectedExceptions = AuthorizationException.class)
public void testListUsersFailNotAuth() {
AdminClient client = requestsSendResponses(
keystoneAuthWithUsernameAndPassword, responseWithKeystoneAccess,
standardRequestBuilder(endpoint + "/v2.0/users").build(),
standardResponseBuilder(401).build()).getAdminClientForRegion("region-a.geo-1");
client.listUsers();
}
public void testGetUser() {
AdminClient client = requestsSendResponses(
keystoneAuthWithUsernameAndPassword, responseWithKeystoneAccess,
standardRequestBuilder(endpoint + "/v2.0/users/e021dfd758eb44a89f1c57c8ef3be8e2").build(),
standardResponseBuilder(200).payload(payloadFromResourceWithContentType("/user_details.json", APPLICATION_JSON)).build())
.getAdminClientForRegion("region-a.geo-1");
User user = client.getUser("e021dfd758eb44a89f1c57c8ef3be8e2");
assertNotNull(user);
assertEquals(user, User.builder().name("nova").id("e021dfd758eb44a89f1c57c8ef3be8e2").build());
}
public void testGetUserFailNotFound() {
AdminClient client = requestsSendResponses(
keystoneAuthWithUsernameAndPassword, responseWithKeystoneAccess,
standardRequestBuilder(endpoint + "/v2.0/users/f021dfd758eb44a89f1c57c8ef3be8e2").build(),
standardResponseBuilder(404).build()).getAdminClientForRegion("region-a.geo-1");
assertNull(client.getUser("f021dfd758eb44a89f1c57c8ef3be8e2"));
}
public void testGetUserByName() {
AdminClient client = requestsSendResponses(
keystoneAuthWithUsernameAndPassword, responseWithKeystoneAccess,
standardRequestBuilder(endpoint + "/v2.0/users?name=nova").build(),
standardResponseBuilder(200).payload(payloadFromResourceWithContentType("/user_details.json", APPLICATION_JSON)).build())
.getAdminClientForRegion("region-a.geo-1");
User user = client.getUserByName("nova");
assertNotNull(user);
assertEquals(user, User.builder().name("nova").id("e021dfd758eb44a89f1c57c8ef3be8e2").build());
}
public void testGetUserByNameFailNotFound() {
AdminClient client = requestsSendResponses(
keystoneAuthWithUsernameAndPassword, responseWithKeystoneAccess,
standardRequestBuilder(endpoint + "/v2.0/users?name=fred").build(),
standardResponseBuilder(404).build()).getAdminClientForRegion("region-a.geo-1");
assertNull(client.getUserByName("fred"));
}
public void testListRolesOfUser() {
AdminClient client = requestsSendResponses(
keystoneAuthWithUsernameAndPassword, responseWithKeystoneAccess,
standardRequestBuilder(endpoint + "/v2.0/users/3f6c1c9ba993495ead7d2eb2192e284f/roles").build(),
standardResponseBuilder(200).payload(payloadFromResourceWithContentType("/user_role_list.json", APPLICATION_JSON)).build())
.getAdminClientForRegion("region-a.geo-1");
Set<Role> roles = client.listRolesOfUser("3f6c1c9ba993495ead7d2eb2192e284f");
assertNotNull(roles);
assertFalse(roles.isEmpty());
assertEquals(roles, ImmutableSet.of(
Role.builder().id("79cada5c02814b57a52e0eed4dd388cb").name("admin").build()
));
}
public void testListRolesOfUserFailNotFound() {
AdminClient client = requestsSendResponses(
keystoneAuthWithUsernameAndPassword, responseWithKeystoneAccess,
standardRequestBuilder(endpoint + "/v2.0/users/4f6c1c9ba993495ead7d2eb2192e284f/roles").build(),
standardResponseBuilder(404).build()).getAdminClientForRegion("region-a.geo-1");
assertTrue(client.listRolesOfUser("4f6c1c9ba993495ead7d2eb2192e284f").isEmpty());
}
@Test(expectedExceptions = HttpResponseException.class)
public void testListRolesOfUserFailNotImplemented() {
AdminClient client = requestsSendResponses(
keystoneAuthWithUsernameAndPassword, responseWithKeystoneAccess,
standardRequestBuilder(endpoint + "/v2.0/users/5f6c1c9ba993495ead7d2eb2192e284f/roles").build(),
standardResponseBuilder(501).build()).getAdminClientForRegion("region-a.geo-1");
assertTrue(client.listRolesOfUser("5f6c1c9ba993495ead7d2eb2192e284f").isEmpty());
}
public void testListRolesOfUserInTenant() {
AdminClient client = requestsSendResponses(
keystoneAuthWithUsernameAndPassword, responseWithKeystoneAccess,
standardRequestBuilder(endpoint + "/v2.0/users/3f6c1c9ba993495ead7d2eb2192e284f/roles").build(),
standardResponseBuilder(200).payload(payloadFromResourceWithContentType("/user_tenant_role_list.json", APPLICATION_JSON)).build())
.getAdminClientForRegion("region-a.geo-1");
Set<Role> roles = client.listRolesOfUser("3f6c1c9ba993495ead7d2eb2192e284f");
assertNotNull(roles);
assertFalse(roles.isEmpty());
assertEquals(roles, ImmutableSet.of(
Role.builder().id("31c451195aac49b386039341e2c92a16").name("KeystoneServiceAdmin").build(),
Role.builder().id("79cada5c02814b57a52e0eed4dd388cb").name("admin").build(),
Role.builder().id("6ea17ddd37a6447794cb0e164d4db894").name("KeystoneAdmin").build()));
}
public void testListRolesOfUserInTenantFailNotFound() {
AdminClient client = requestsSendResponses(
keystoneAuthWithUsernameAndPassword, responseWithKeystoneAccess,
standardRequestBuilder(endpoint + "/v2.0/users/3f6c1c9ba993495ead7d2eb2192e284f/roles").build(),
standardResponseBuilder(404).build()).getAdminClientForRegion("region-a.geo-1");
assertTrue(client.listRolesOfUser("3f6c1c9ba993495ead7d2eb2192e284f").isEmpty());
}
}

View File

@ -0,0 +1,193 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 1.1 (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-1.1
*
* 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.openstack.keystone.v2_0;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertNull;
import static org.testng.AssertJUnit.assertTrue;
import java.net.URI;
import java.util.Set;
import org.jclouds.http.HttpRequest;
import org.jclouds.openstack.filters.AuthenticateRequest;
import org.jclouds.openstack.keystone.v2_0.domain.ApiMetadata;
import org.jclouds.openstack.keystone.v2_0.domain.Endpoint;
import org.jclouds.openstack.keystone.v2_0.domain.Role;
import org.jclouds.openstack.keystone.v2_0.domain.Tenant;
import org.jclouds.openstack.keystone.v2_0.domain.Token;
import org.jclouds.openstack.keystone.v2_0.domain.User;
import org.jclouds.openstack.keystone.v2_0.internal.BaseKeystoneClientLiveTest;
import org.jclouds.openstack.reference.AuthHeaders;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import com.google.common.collect.Iterables;
/**
* Tests AdminClient
*
* @author Adam Lowe
*/
@Test(groups = "live", testName = "AdminClientLiveTest", singleThreaded = true)
public class AdminClientLiveTest extends BaseKeystoneClientLiveTest {
protected String token;
// Get the token currently in use (there's currently no listTokens())
@BeforeMethod
public void grabToken() {
AuthenticateRequest ar = keystoneContext.getUtils().getInjector().getInstance(AuthenticateRequest.class);
HttpRequest test = ar.filter(HttpRequest.builder().method("GET").endpoint(URI.create(endpoint)).build());
token = Iterables.getOnlyElement(test.getHeaders().get(AuthHeaders.AUTH_TOKEN));
}
public void testGetApiMetaData() {
for (String regionId : keystoneContext.getApi().getConfiguredRegions()) {
ApiMetadata result = keystoneContext.getApi().getAdminClientForRegion(regionId).getApiMetadata();
assertNotNull(result);
assertNotNull(result.getId());
assertNotNull(result.getStatus());
assertNotNull(result.getUpdated());
}
}
public void testTenants() {
for (String regionId : keystoneContext.getApi().getConfiguredRegions()) {
AdminClient client = keystoneContext.getApi().getAdminClientForRegion(regionId);
Set<Tenant> result = client.listTenants();
assertNotNull(result);
assertFalse(result.isEmpty());
for (Tenant tenant : result) {
assertNotNull(tenant.getId());
Tenant aTenant = client.getTenant(tenant.getId());
assertEquals(aTenant, tenant);
}
}
}
public void testToken() {
for (String regionId : keystoneContext.getApi().getConfiguredRegions()) {
AdminClient client = keystoneContext.getApi().getAdminClientForRegion(regionId);
assertTrue(client.checkTokenIsValid(token));
Token result = client.getToken(token);
assertNotNull(result);
assertEquals(result.getId(), token);
assertNotNull(result.getTenant());
User user = client.getUserOfToken(token);
assertNotNull(user);
assertNotNull(user.getId());
assertNotNull(user.getName());
}
}
public void testInvalidToken() {
for (String regionId : keystoneContext.getApi().getConfiguredRegions()) {
AdminClient client = keystoneContext.getApi().getAdminClientForRegion(regionId);
assertFalse(client.checkTokenIsValid("thisisnotarealtoken!"));
assertNull(client.getToken("thisisnotarealtoken!"));
}
}
// TODO this threw 501 not implemented
@Test(enabled = false)
public void testTokenEndpoints() {
for (String regionId : keystoneContext.getApi().getConfiguredRegions()) {
AdminClient client = keystoneContext.getApi().getAdminClientForRegion(regionId);
Set<Endpoint> endpoints = client.getEndpointsForToken(token);
assertNotNull(endpoints);
assertFalse(endpoints.isEmpty());
}
}
// TODO this threw 501 not implemented
@Test(enabled = false)
public void testInvalidTokenEndpoints() {
for (String regionId : keystoneContext.getApi().getConfiguredRegions()) {
AdminClient client = keystoneContext.getApi().getAdminClientForRegion(regionId);
assertTrue(client.getEndpointsForToken("thisisnotarealtoken!").isEmpty());
}
}
public void testUsers() {
for (String regionId : keystoneContext.getApi().getConfiguredRegions()) {
AdminClient client = keystoneContext.getApi().getAdminClientForRegion(regionId);
Set<User> users = client.listUsers();
assertNotNull(users);
assertFalse(users.isEmpty());
for (User user : users) {
User aUser = client.getUser(user.getId());
assertEquals(aUser, user);
}
}
}
@Test(dependsOnMethods = {"testUsers", "testTenants"})
public void testUserRolesOnTenant() {
for (String regionId : keystoneContext.getApi().getConfiguredRegions()) {
AdminClient client = keystoneContext.getApi().getAdminClientForRegion(regionId);
Set<User> users = client.listUsers();
Set<Tenant> tenants = client.listTenants();
for (User user : users) {
for (Tenant tenant : tenants) {
Set<Role> roles = client.listRolesOfUserOnTenant(user.getId(), tenant.getId());
for (Role role : roles) {
assertNotNull(role.getId());
}
}
}
}
}
// TODO this functionality is currently broken in openstack
@Test(enabled = false, dependsOnMethods = "testUsers")
public void testListRolesOfUser() {
for (String regionId : keystoneContext.getApi().getConfiguredRegions()) {
AdminClient client = keystoneContext.getApi().getAdminClientForRegion(regionId);
for (User user : client.listUsers()) {
Set<Role> roles = client.listRolesOfUser(user.getId());
for (Role role : roles) {
assertNotNull(role.getId());
}
}
}
}
// TODO this functionality is currently broken in openstack (possibly deprecated?)
@Test(enabled=false, dependsOnMethods = {"testUsers", "testTenants"})
public void testUsersAndTenantsByName() {
for (String regionId : keystoneContext.getApi().getConfiguredRegions()) {
AdminClient client = keystoneContext.getApi().getAdminClientForRegion(regionId);
for (User user : client.listUsers()) {
User aUser = client.getUserByName(user.getName());
assertEquals(aUser, user);
}
for (Tenant tenant : client.listTenants()) {
Tenant aTenant = client.getTenantByName(tenant.getName());
assertEquals(aTenant, tenant);
}
}
}
}

View File

@ -0,0 +1,95 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 1.1 (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-1.1
*
* 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.openstack.keystone.v2_0;
import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertNotNull;
import java.net.URI;
import java.util.Set;
import org.jclouds.date.internal.SimpleDateFormatDateService;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse;
import org.jclouds.openstack.domain.Link;
import org.jclouds.openstack.keystone.v2_0.domain.ApiMetadata;
import org.jclouds.openstack.keystone.v2_0.domain.MediaType;
import org.jclouds.openstack.keystone.v2_0.domain.Tenant;
import org.jclouds.openstack.keystone.v2_0.internal.BaseKeystoneRestClientExpectTest;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.ImmutableSet;
/**
* Tests parsing and Guice wiring of UserClient
*
* @author Adam Lowe
*/
public class UserClientExpectTest extends BaseKeystoneRestClientExpectTest<KeystoneClient> {
public void testGetApiMetaData() {
ServiceClient client = requestsSendResponses(
keystoneAuthWithUsernameAndPassword, responseWithKeystoneAccess,
HttpRequest.builder().method("GET").endpoint(URI.create(endpoint + "/v2.0/")).
headers(ImmutableMultimap.of("Accept", APPLICATION_JSON)).build(),
HttpResponse.builder().statusCode(200).
payload(payloadFromResourceWithContentType("/api_metadata.json", APPLICATION_JSON)).build())
.getServiceClientForRegion("region-a.geo-1");
ApiMetadata metadata = client.getApiMetadata();
assertNotNull(metadata);
assertEquals(metadata.getId(), "v2.0");
ApiMetadata expected = ApiMetadata.builder().id("v2.0")
.links(ImmutableSet.of(Link.builder().relation(Link.Relation.SELF).href(URI.create("http://172.16.89.140:5000/v2.0/")).build(),
Link.builder().relation(Link.Relation.DESCRIBEDBY).type("text/html").href(URI.create("http://docs.openstack.org/api/openstack-identity-service/2.0/content/")).build(),
Link.builder().relation(Link.Relation.DESCRIBEDBY).type("application/pdf").href(URI.create("http://docs.openstack.org/api/openstack-identity-service/2.0/identity-dev-guide-2.0.pdf")).build()
))
.status("beta")
.updated(new SimpleDateFormatDateService().iso8601SecondsDateParse("2011-11-19T00:00:00Z"))
.mediaTypes(ImmutableSet.of(
MediaType.builder().base("application/json").type("application/vnd.openstack.identity-v2.0+json").build(),
MediaType.builder().base("application/xml").type("application/vnd.openstack.identity-v2.0+xml").build()
))
.build();
assertEquals(metadata, expected);
}
public void testListTenants() {
ServiceClient client = requestsSendResponses(
keystoneAuthWithUsernameAndPassword, responseWithKeystoneAccess,
HttpRequest.builder().method("GET").endpoint(URI.create(endpoint + "/v2.0/tenants")).
headers(ImmutableMultimap.of("Accept", APPLICATION_JSON, "X-Auth-Token", authToken)).build(),
HttpResponse.builder().statusCode(200).
payload(payloadFromResourceWithContentType("/tenant_list.json", APPLICATION_JSON)).build())
.getServiceClientForRegion("region-a.geo-1");
Set<Tenant> tenants = client.listTenants();
assertNotNull(tenants);
assertFalse(tenants.isEmpty());
Set<Tenant> expected = ImmutableSet.of(
Tenant.builder().name("demo").id("05d1dc7af71646deba64cfc17b81bec0").build(),
Tenant.builder().name("admin").id("7aa2e17ec29f44d193c48feaba0852cc").build()
);
assertEquals(tenants, expected);
}
}

View File

@ -0,0 +1,61 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 1.1 (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-1.1
*
* 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.openstack.keystone.v2_0;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertNotNull;
import java.util.Set;
import org.jclouds.openstack.keystone.v2_0.domain.ApiMetadata;
import org.jclouds.openstack.keystone.v2_0.domain.Tenant;
import org.jclouds.openstack.keystone.v2_0.internal.BaseKeystoneClientLiveTest;
import org.testng.annotations.Test;
/**
* Tests UserClient
*
* @author Adam Lowe
*/
@Test(groups = "live", testName = "UserClientLiveTest")
public class UserClientLiveTest extends BaseKeystoneClientLiveTest {
public void testGetApiMetaData() {
for (String regionId : keystoneContext.getApi().getConfiguredRegions()) {
ApiMetadata result = keystoneContext.getApi().getServiceClientForRegion(regionId).getApiMetadata();
assertNotNull(result);
assertNotNull(result.getId());
assertNotNull(result.getStatus());
assertNotNull(result.getUpdated());
}
}
public void testListTenants() {
for (String regionId : keystoneContext.getApi().getConfiguredRegions()) {
Set<Tenant> result = keystoneContext.getApi().getServiceClientForRegion(regionId).listTenants();
assertNotNull(result);
assertFalse(result.isEmpty());
for (Tenant tenant : result) {
assertNotNull(tenant.getId());
}
}
}
}

View File

@ -0,0 +1,77 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.openstack.keystone.v2_0.internal;
import static org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties.SERVICE_TYPE;
import java.util.Properties;
import org.jclouds.apis.BaseContextLiveTest;
import org.jclouds.openstack.keystone.v2_0.KeystoneApiMetadata;
import org.jclouds.openstack.keystone.v2_0.KeystoneAsyncClient;
import org.jclouds.openstack.keystone.v2_0.KeystoneClient;
import org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties;
import org.jclouds.openstack.services.ServiceType;
import org.jclouds.rest.RestContext;
import org.testng.annotations.AfterGroups;
import org.testng.annotations.BeforeGroups;
import org.testng.annotations.Test;
import com.google.common.reflect.TypeToken;
/**
* Tests behavior of {@code KeystoneClient}
*
* @author Adam Lowe
*/
@Test(groups = "live")
public class BaseKeystoneClientLiveTest extends BaseContextLiveTest<RestContext<KeystoneClient, KeystoneAsyncClient>> {
public BaseKeystoneClientLiveTest() {
provider = "openstack-keystone";
}
protected RestContext<KeystoneClient, KeystoneAsyncClient> keystoneContext;
@BeforeGroups(groups = { "integration", "live" })
@Override
public void setupContext() {
super.setupContext();
keystoneContext = context;
}
@Override
protected Properties setupProperties() {
Properties props = super.setupProperties();
setIfTestSystemPropertyPresent(props, KeystoneProperties.CREDENTIAL_TYPE);
return props;
}
@AfterGroups(groups = "live")
protected void tearDown() {
if (keystoneContext != null)
keystoneContext.close();
}
@Override
protected TypeToken<RestContext<KeystoneClient, KeystoneAsyncClient>> contextType() {
return KeystoneApiMetadata.CONTEXT_TOKEN;
}
}

View File

@ -0,0 +1,86 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 1.1 (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-1.1
*
* 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.openstack.keystone.v2_0.internal;
import static org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties.SERVICE_TYPE;
import java.net.URI;
import java.util.Properties;
import javax.ws.rs.core.MediaType;
import org.jclouds.Constants;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse;
import org.jclouds.openstack.keystone.v1_1.config.AuthenticationServiceModule;
import org.jclouds.openstack.services.ServiceType;
import org.jclouds.rest.internal.BaseRestClientExpectTest;
import com.google.common.base.Objects;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.net.HttpHeaders;
/**
* Base class for writing KeyStone 2.0 Rest Client Expect tests
*
* @author Adam Lowe
*/
public class BaseKeystoneRestClientExpectTest<S> extends BaseRestClientExpectTest<S> {
protected HttpRequest keystoneAuthWithUsernameAndPassword;
protected HttpRequest keystoneAuthWithAccessKeyAndSecretKey;
protected String authToken;
protected HttpResponse responseWithKeystoneAccess;
protected String endpoint = "https://csnode.jclouds.org";
public BaseKeystoneRestClientExpectTest() {
provider = "openstack-keystone";
keystoneAuthWithUsernameAndPassword = KeystoneFixture.INSTANCE.initialAuthWithUsernameAndPassword(identity,
credential);
keystoneAuthWithAccessKeyAndSecretKey = KeystoneFixture.INSTANCE.initialAuthWithAccessKeyAndSecretKey(identity,
credential);
authToken = KeystoneFixture.INSTANCE.getAuthToken();
responseWithKeystoneAccess = KeystoneFixture.INSTANCE.responseWithAccess();
// now, createContext arg will need tenant prefix
identity = KeystoneFixture.INSTANCE.getTenantName() + ":" + identity;
}
protected HttpRequest.Builder standardRequestBuilder(String endpoint) {
return HttpRequest.builder().method("GET")
.headers(ImmutableMultimap.of("Accept", MediaType.APPLICATION_JSON, "X-Auth-Token", authToken))
.endpoint(URI.create(endpoint));
}
protected HttpResponse.Builder standardResponseBuilder(int status) {
return HttpResponse.builder().statusCode(status);
}
@Override
protected Properties setupProperties() {
Properties props = super.setupProperties();
props.put(SERVICE_TYPE, ServiceType.IDENTITY);
return props;
}
@Override
protected HttpRequestComparisonType compareHttpRequestAsType(HttpRequest input) {
return Objects.equal("HEAD", input.getMethod()) ? HttpRequestComparisonType.DEFAULT : HttpRequestComparisonType.JSON;
}
}

View File

@ -0,0 +1 @@
{"version": {"status": "beta", "updated": "2011-11-19T00:00:00Z", "media-types": [{"base": "application/json", "type": "application/vnd.openstack.identity-v2.0+json"}, {"base": "application/xml", "type": "application/vnd.openstack.identity-v2.0+xml"}], "id": "v2.0", "links": [{"href": "http://172.16.89.140:5000/v2.0/", "rel": "self"}, {"href": "http://docs.openstack.org/api/openstack-identity-service/2.0/content/", "type": "text/html", "rel": "describedby"}, {"href": "http://docs.openstack.org/api/openstack-identity-service/2.0/identity-dev-guide-2.0.pdf", "type": "application/pdf", "rel": "describedby"}]}}

View File

@ -0,0 +1,51 @@
<?xml version="1.0"?>
<configuration scan="false">
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
<file>target/test-data/jclouds.log</file>
<encoder>
<Pattern>%d %-5p [%c] [%thread] %m%n</Pattern>
</encoder>
</appender>
<appender name="WIREFILE" class="ch.qos.logback.core.FileAppender">
<file>target/test-data/jclouds-wire.log</file>
<encoder>
<Pattern>%d %-5p [%c] [%thread] %m%n</Pattern>
</encoder>
</appender>
<appender name="BLOBSTOREFILE" class="ch.qos.logback.core.FileAppender">
<file>target/test-data/jclouds-blobstore.log</file>
<encoder>
<Pattern>%d %-5p [%c] [%thread] %m%n</Pattern>
</encoder>
</appender>
<root>
<level value="warn" />
</root>
<logger name="org.jclouds">
<level value="DEBUG" />
<appender-ref ref="FILE" />
</logger>
<logger name="jclouds.wire">
<level value="DEBUG" />
<appender-ref ref="WIREFILE" />
</logger>
<logger name="jclouds.headers">
<level value="DEBUG" />
<appender-ref ref="WIREFILE" />
</logger>
<logger name="jclouds.blobstore">
<level value="DEBUG" />
<appender-ref ref="BLOBSTOREFILE" />
</logger>
</configuration>

View File

@ -0,0 +1 @@
{"tenant": {"enabled": true, "description": null, "name": "admin", "id": "013ba41150a14830bec85ffe93353bcc"}}

View File

@ -0,0 +1 @@
{"tenants_links": [], "tenants": [{"enabled": true, "description": null, "name": "demo", "id": "05d1dc7af71646deba64cfc17b81bec0"}, {"enabled": true, "description": null, "name": "admin", "id": "7aa2e17ec29f44d193c48feaba0852cc"}]}

View File

@ -0,0 +1 @@
{"access": {"token": {"expires": "2012-04-28T12:42:50Z", "id": "167eccdc790946969ced473732e8109b", "tenant": {"id": "4cea93f5464b4f1c921fb3e0461d72b5", "enabled": true, "description": null, "name": "demo"}}, "user": {"username": "admin", "roles_links": [], "id": "2b9b606181634ae9ac86fd95a8bc2cde", "roles": [{"id": "79cada5c02814b57a52e0eed4dd388cb", "name": "admin"}], "name": "admin"}}}

View File

@ -0,0 +1 @@
{"user": {"name": "nova", "enabled": true, "email": "nova@example.com", "id": "e021dfd758eb44a89f1c57c8ef3be8e2", "tenantId": "ab1da202f5774cceb5da2aeff1f0aa87"}}

View File

@ -0,0 +1,10 @@
{"endpoints": [
{
"adminURL": "https://csnode.jclouds.org:35357/v2.0/",
"publicURL": "https://csnode.jclouds.org/v2.0/",
"region": "region-a.geo-1",
"id": "2.0",
"versionId":"2.0",
"list": "https://csnode.jclouds.org/extension"
}
]}

View File

@ -0,0 +1 @@
{"users": [{"name": "admin", "enabled": true, "email": "admin@example.com", "id": "2b9b606181634ae9ac86fd95a8bc2cde", "tenantId": null}, {"name": "demo", "enabled": true, "email": "demo@example.com", "id": "667b2e1420604df8b67cd8ea57d4ee64", "tenantId": null}, {"name": "nova", "enabled": true, "email": "nova@example.com", "id": "e021dfd758eb44a89f1c57c8ef3be8e2", "tenantId": "ab1da202f5774cceb5da2aeff1f0aa87"}, {"name": "glance", "enabled": true, "email": "glance@example.com", "id": "3f6c1c9ba993495ead7d2eb2192e284f", "tenantId": "ab1da202f5774cceb5da2aeff1f0aa87"}]}

View File

@ -0,0 +1 @@
{"roles": [{"id": "79cada5c02814b57a52e0eed4dd388cb", "name": "admin"}]}

View File

@ -0,0 +1 @@
{"roles": [{"id": "31c451195aac49b386039341e2c92a16", "name": "KeystoneServiceAdmin"}, {"id": "79cada5c02814b57a52e0eed4dd388cb", "name": "admin"}, {"id": "6ea17ddd37a6447794cb0e164d4db894", "name": "KeystoneAdmin"}]}

View File

@ -46,5 +46,6 @@
<module>cdmi</module>
<module>openstack-glance</module>
<module>joyent-sdc</module>
<module>openstack-keystone</module>
</modules>
</project>