added id to endpoint and used only endpoint.versionId to enforce endpointVersion

This commit is contained in:
Adrian Cole 2012-10-07 16:18:34 -07:00
parent a02c79c7f4
commit 99d3422b4d
16 changed files with 826 additions and 337 deletions

View File

@ -37,25 +37,33 @@ public interface KeystoneProperties {
* </ul> * </ul>
* *
* @see CredentialTypes * @see CredentialTypes
* @see <a href="http://docs.openstack.org/api/openstack-identity-service/2.0/content/POST_authenticate_v2.0_tokens_Service_API_Api_Operations.html" * @see <a href=
* "http://docs.openstack.org/api/openstack-identity-service/2.0/content/POST_authenticate_v2.0_tokens_Service_API_Api_Operations.html"
* /> * />
*/ */
public static final String CREDENTIAL_TYPE = "jclouds.keystone.credential-type"; public static final String CREDENTIAL_TYPE = "jclouds.keystone.credential-type";
/** /**
* set this property to specify the tenant id of the authenticated user. Cannot be used simultaneously with {@link #TENANT_NAME} * set this property to specify the tenant id of the authenticated user.
* Cannot be used simultaneously with {@link #TENANT_NAME}
*
* @see <a href="http://wiki.openstack.org/CLIAuth">openstack docs</a> * @see <a href="http://wiki.openstack.org/CLIAuth">openstack docs</a>
*/ */
public static final String TENANT_ID = "jclouds.keystone.tenant-id"; public static final String TENANT_ID = "jclouds.keystone.tenant-id";
/** /**
* set this property to specify the tenant name of the authenticated user. Cannot be used simultaneously with {@link #TENANT_ID} * set this property to specify the tenant name of the authenticated user.
* Cannot be used simultaneously with {@link #TENANT_ID}
*
* @see <a href="http://wiki.openstack.org/CLIAuth">openstack docs</a> * @see <a href="http://wiki.openstack.org/CLIAuth">openstack docs</a>
*/ */
public static final String TENANT_NAME = "jclouds.keystone.tenant-name"; public static final String TENANT_NAME = "jclouds.keystone.tenant-name";
/** /**
* set this property to {@code true} to designate that the service requires explicit specification of either {@link #TENANT_NAME} or {@link #TENANT_ID} * set this property to {@code true} to designate that the service requires
* explicit specification of either {@link #TENANT_NAME} or
* {@link #TENANT_ID}
*
* @see <a href="http://wiki.openstack.org/CLIAuth">openstack docs</a> * @see <a href="http://wiki.openstack.org/CLIAuth">openstack docs</a>
*/ */
public static final String REQUIRES_TENANT = "jclouds.keystone.requires-tenant"; public static final String REQUIRES_TENANT = "jclouds.keystone.requires-tenant";

View File

@ -27,16 +27,18 @@ import org.jclouds.javax.annotation.Nullable;
import com.google.common.base.Objects; import com.google.common.base.Objects;
import com.google.common.base.Objects.ToStringHelper; import com.google.common.base.Objects.ToStringHelper;
import com.google.common.collect.ForwardingSet;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
/** /**
* TODO * TODO
* *
* @author Adrian Cole * @author Adrian Cole
* @see <a href="http://docs.openstack.org/api/openstack-identity-service/2.0/content/Service_API_Api_Operations.html" * @see <a href=
/> * "http://docs.openstack.org/api/openstack-identity-service/2.0/content/Identity-Service-Concepts-e1362.html"
* />
*/ */
public class Access implements Comparable<Access> { public class Access extends ForwardingSet<Service> implements Comparable<Access> {
public static Builder<?> builder() { public static Builder<?> builder() {
return new ConcreteBuilder(); return new ConcreteBuilder();
@ -51,7 +53,7 @@ public class Access implements Comparable<Access> {
protected Token token; protected Token token;
protected User user; protected User user;
protected Set<Service> serviceCatalog = ImmutableSet.of(); protected ImmutableSet.Builder<Service> serviceCatalog = ImmutableSet.<Service> builder();
/** /**
* @see Access#getToken() * @see Access#getToken()
@ -70,26 +72,44 @@ public class Access implements Comparable<Access> {
} }
/** /**
* @see Access#getServiceCatalog() * @see Access#delegate()
*/ */
public T serviceCatalog(Set<Service> serviceCatalog) { public T service(Service service) {
this.serviceCatalog = ImmutableSet.copyOf(checkNotNull(serviceCatalog, "serviceCatalog")); this.serviceCatalog.add(service);
return self(); return self();
} }
/**
* @see Access#delegate()
*/
public T services(Iterable<Service> serviceCatalog) {
this.serviceCatalog.addAll(serviceCatalog);
return self();
}
/**
* @see #services(Iterable)
*/
@Deprecated
public T serviceCatalog(Set<Service> serviceCatalog) {
this.serviceCatalog.addAll(serviceCatalog);
return self();
}
/**
* @see #services(Iterable)
*/
@Deprecated
public T serviceCatalog(Service... in) { public T serviceCatalog(Service... in) {
return serviceCatalog(ImmutableSet.copyOf(in)); return serviceCatalog(ImmutableSet.copyOf(in));
} }
public Access build() { public Access build() {
return new Access(token, user, serviceCatalog); return new Access(token, user, serviceCatalog.build());
} }
public T fromAccess(Access in) { public T fromAccess(Access in) {
return this return this.token(in.getToken()).user(in.getUser()).services(in);
.token(in.getToken())
.user(in.getUser())
.serviceCatalog(in.getServiceCatalog());
} }
} }
@ -104,13 +124,11 @@ public class Access implements Comparable<Access> {
private final User user; private final User user;
private final Set<Service> serviceCatalog; private final Set<Service> serviceCatalog;
@ConstructorProperties({ @ConstructorProperties({ "token", "user", "serviceCatalog" })
"token", "user", "serviceCatalog"
})
protected Access(Token token, User user, @Nullable Set<Service> serviceCatalog) { protected Access(Token token, User user, @Nullable Set<Service> serviceCatalog) {
this.token = checkNotNull(token, "token"); this.token = checkNotNull(token, "token");
this.user = checkNotNull(user, "user"); this.user = checkNotNull(user, "user");
this.serviceCatalog = serviceCatalog == null ? ImmutableSet.<Service>of() : ImmutableSet.copyOf(serviceCatalog); this.serviceCatalog = serviceCatalog == null ? ImmutableSet.<Service> of() : ImmutableSet.copyOf(serviceCatalog);
} }
/** /**
@ -128,8 +146,9 @@ public class Access implements Comparable<Access> {
} }
/** /**
* TODO * Please access the service catalog via normal collection mechanisms
*/ */
@Deprecated
public Set<Service> getServiceCatalog() { public Set<Service> getServiceCatalog() {
return this.serviceCatalog; return this.serviceCatalog;
} }
@ -141,17 +160,18 @@ public class Access implements Comparable<Access> {
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object obj) {
if (this == obj) return true; if (this == obj)
if (obj == null || getClass() != obj.getClass()) return false; return true;
if (obj == null || getClass() != obj.getClass())
return false;
Access that = Access.class.cast(obj); Access that = Access.class.cast(obj);
return Objects.equal(this.token, that.token) return Objects.equal(this.token, that.token) && Objects.equal(this.user, that.user)
&& Objects.equal(this.user, that.user)
&& Objects.equal(this.serviceCatalog, that.serviceCatalog); && Objects.equal(this.serviceCatalog, that.serviceCatalog);
} }
protected ToStringHelper string() { protected ToStringHelper string() {
return Objects.toStringHelper(this) return Objects.toStringHelper(this).omitNullValues().add("token", token).add("user", user)
.add("token", token).add("user", user).add("serviceCatalog", serviceCatalog); .add("serviceCatalog", serviceCatalog);
} }
@Override @Override
@ -168,4 +188,9 @@ public class Access implements Comparable<Access> {
return this.token.compareTo(that.token); return this.token.compareTo(that.token);
} }
@Override
protected Set<Service> delegate() {
return serviceCatalog;
}
} }

View File

@ -27,13 +27,15 @@ import com.google.common.base.Objects;
import com.google.common.base.Objects.ToStringHelper; import com.google.common.base.Objects.ToStringHelper;
/** /**
* An network-accessible address, usually described by URL, where a service may be accessed. If * An network-accessible address, usually described by URL, where a service may
* using an extension for templates, you can create an endpoint template, which represents the * be accessed. If using an extension for templates, you can create an endpoint
* templates of all the consumable services that are available across the regions. * template, which represents the templates of all the consumable services that
* are available across the regions.
* *
* @author AdrianCole * @author AdrianCole
* @see <a href="http://docs.openstack.org/api/openstack-identity-service/2.0/content/Identity-Endpoint-Concepts-e1362.html" * @see <a href=
/> * "http://docs.openstack.org/api/openstack-identity-service/2.0/content/Identity-Endpoint-Concepts-e1362.html"
* />
*/ */
public class Endpoint { public class Endpoint {
@ -48,6 +50,7 @@ public class Endpoint {
public static abstract class Builder<T extends Builder<T>> { public static abstract class Builder<T extends Builder<T>> {
protected abstract T self(); protected abstract T self();
protected String id;
protected String versionId; protected String versionId;
protected String region; protected String region;
protected URI publicURL; protected URI publicURL;
@ -57,6 +60,15 @@ public class Endpoint {
protected URI versionInfo; protected URI versionInfo;
protected URI versionList; protected URI versionList;
/**
* @see Endpoint#getId()
*/
public T id(String id) {
this.id = id;
return self();
}
/** /**
* @see Endpoint#getVersionId() * @see Endpoint#getVersionId()
*/ */
@ -113,6 +125,41 @@ public class Endpoint {
return self(); return self();
} }
/**
* @see Endpoint#getPublicURL()
*/
public T publicURL(String publicURL) {
return publicURL(URI.create(publicURL));
}
/**
* @see Endpoint#getInternalURL()
*/
public T internalURL(String internalURL) {
return internalURL(URI.create(internalURL));
}
/**
* @see Endpoint#getAdminURL()
*/
public T adminURL(String adminURL) {
return adminURL(URI.create(adminURL));
}
/**
* @see Endpoint#getVersionInfo()
*/
public T versionInfo(String versionInfo) {
return versionInfo(URI.create(versionInfo));
}
/**
* @see Endpoint#getVersionList()
*/
public T versionList(String versionList) {
return versionList(URI.create(versionList));
}
/** /**
* @see Endpoint#getTenantId() * @see Endpoint#getTenantId()
*/ */
@ -122,19 +169,14 @@ public class Endpoint {
} }
public Endpoint build() { public Endpoint build() {
return new Endpoint(null, versionId, region, publicURL, internalURL, adminURL, versionInfo, versionList, null, tenantId); return new Endpoint(id, versionId, region, publicURL, internalURL, adminURL, versionInfo, versionList, null,
tenantId);
} }
public T fromEndpoint(Endpoint in) { public T fromEndpoint(Endpoint in) {
return this return this.versionId(in.getVersionId()).region(in.getRegion()).publicURL(in.getPublicURL())
.versionId(in.getVersionId()) .internalURL(in.getInternalURL()).adminURL(in.getAdminURL()).versionInfo(in.getVersionInfo())
.region(in.getRegion()) .versionList(in.getVersionList()).tenantId(in.getTenantId());
.publicURL(in.getPublicURL())
.internalURL(in.getInternalURL())
.adminURL(in.getAdminURL())
.versionInfo(in.getVersionInfo())
.versionList(in.getVersionList())
.tenantId(in.getTenantId());
} }
} }
@ -145,22 +187,26 @@ public class Endpoint {
} }
} }
private final String versionId; private final String id;
private final String tenantId;
private final String region; private final String region;
private final URI publicURL; private final URI publicURL;
private final URI internalURL; private final URI internalURL;
private final URI adminURL; private final URI adminURL;
// fields not defined in
// https://github.com/openstack/keystone/blob/master/keystone/service.py
private final String versionId;
private final URI versionInfo; private final URI versionInfo;
private final URI versionList; private final URI versionList;
private final String tenantId;
@ConstructorProperties({ @ConstructorProperties({ "id", "versionId", "region", "publicURL", "internalURL", "adminURL", "versionInfo",
"id", "versionId", "region", "publicURL", "internalURL", "adminURL", "versionInfo", "versionList", "tenantName", "tenantId" "versionList", "tenantName", "tenantId" })
}) protected Endpoint(@Nullable String id, @Nullable String versionId, @Nullable String region,
protected Endpoint(@Nullable String id, @Nullable String versionId, @Nullable String region, @Nullable URI publicURL, @Nullable URI publicURL, @Nullable URI internalURL, @Nullable URI adminURL, @Nullable URI versionInfo,
@Nullable URI internalURL, @Nullable URI adminURL, @Nullable URI versionInfo, @Nullable URI versionList, @Nullable URI versionList, @Nullable String tenantName, @Nullable String tenantId) {
@Nullable String tenantName, @Nullable String tenantId) { this.id = id;
this.versionId = versionId != null ? versionId : id; this.versionId = versionId;
this.tenantId = tenantId != null ? tenantId : tenantName; this.tenantId = tenantId != null ? tenantId : tenantName;
this.region = region; this.region = region;
this.publicURL = publicURL; this.publicURL = publicURL;
@ -171,10 +217,26 @@ public class Endpoint {
} }
/** /**
* When providing an ID, it is assumed that the endpoint exists in the current OpenStack * When providing an ID, it is assumed that the endpoint exists in the
* deployment * current OpenStack deployment
* *
* @return the versionId of the endpoint in the current OpenStack deployment, or null if not specified * @return the id of the endpoint in the current OpenStack deployment, or
* null if not specified
*/
@Nullable
public String getId() {
return this.id;
}
/**
*
* <h4>Note</h4>
*
* This is not defined in <a href=
* "https://github.com/openstack/keystone/blob/master/keystone/service.py"
* >KeyStone</a>, rather only in <a href=
* "http://docs.rackspace.com/auth/api/v2.0/auth-client-devguide/content/Release_Notes-d1e140.html"
* >Rackspace</a>
*/ */
@Nullable @Nullable
public String getVersionId() { public String getVersionId() {
@ -213,11 +275,31 @@ public class Endpoint {
return this.adminURL; return this.adminURL;
} }
/**
*
* <h4>Note</h4>
*
* This is not defined in <a href=
* "https://github.com/openstack/keystone/blob/master/keystone/service.py"
* >KeyStone</a>, rather only in <a href=
* "http://docs.rackspace.com/auth/api/v2.0/auth-client-devguide/content/Release_Notes-d1e140.html"
* >Rackspace</a>
*/
@Nullable @Nullable
public URI getVersionInfo() { public URI getVersionInfo() {
return this.versionInfo; return this.versionInfo;
} }
/**
*
* <h4>Note</h4>
*
* This is not defined in <a href=
* "https://github.com/openstack/keystone/blob/master/keystone/service.py"
* >KeyStone</a>, rather only in <a href=
* "http://docs.rackspace.com/auth/api/v2.0/auth-client-devguide/content/Release_Notes-d1e140.html"
* >Rackspace</a>
*/
@Nullable @Nullable
public URI getVersionList() { public URI getVersionList() {
return this.versionList; return this.versionList;
@ -233,28 +315,29 @@ public class Endpoint {
@Override @Override
public int hashCode() { public int hashCode() {
return Objects.hashCode(versionId, region, publicURL, internalURL, adminURL, versionInfo, versionList, tenantId); return Objects.hashCode(id, versionId, region, publicURL, internalURL, adminURL, versionInfo, versionList,
tenantId);
} }
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object obj) {
if (this == obj) return true; if (this == obj)
if (obj == null || getClass() != obj.getClass()) return false; return true;
if (obj == null || getClass() != obj.getClass())
return false;
Endpoint that = Endpoint.class.cast(obj); Endpoint that = Endpoint.class.cast(obj);
return Objects.equal(this.versionId, that.versionId) return Objects.equal(this.id, that.id) && Objects.equal(this.versionId, that.versionId)
&& Objects.equal(this.region, that.region) && Objects.equal(this.region, that.region) && Objects.equal(this.publicURL, that.publicURL)
&& Objects.equal(this.publicURL, that.publicURL) && Objects.equal(this.internalURL, that.internalURL) && Objects.equal(this.adminURL, that.adminURL)
&& Objects.equal(this.internalURL, that.internalURL) && Objects.equal(this.versionInfo, that.versionInfo) && Objects.equal(this.versionList, that.versionList)
&& Objects.equal(this.adminURL, that.adminURL)
&& Objects.equal(this.versionInfo, that.versionInfo)
&& Objects.equal(this.versionList, that.versionList)
&& Objects.equal(this.tenantId, that.tenantId); && Objects.equal(this.tenantId, that.tenantId);
} }
protected ToStringHelper string() { protected ToStringHelper string() {
return Objects.toStringHelper(this).omitNullValues() return Objects.toStringHelper(this).omitNullValues().add("id", id).add("versionId", versionId)
.add("versionId", versionId).add("region", region).add("publicURL", publicURL).add("internalURL", internalURL) .add("region", region).add("publicURL", publicURL).add("internalURL", internalURL)
.add("adminURL", adminURL).add("versionInfo", versionInfo).add("versionList", versionList).add("tenantId", tenantId); .add("adminURL", adminURL).add("versionInfo", versionInfo).add("versionList", versionList)
.add("tenantId", tenantId);
} }
@Override @Override

View File

@ -195,7 +195,7 @@ public class Role {
} }
protected ToStringHelper string() { protected ToStringHelper string() {
return Objects.toStringHelper(this) return Objects.toStringHelper(this).omitNullValues()
.add("id", id).add("name", name).add("description", description).add("serviceId", serviceId).add("tenantId", tenantId); .add("id", id).add("name", name).add("description", description).add("serviceId", serviceId).add("tenantId", tenantId);
} }

View File

@ -25,7 +25,6 @@ import java.util.Set;
import com.google.common.base.Objects; import com.google.common.base.Objects;
import com.google.common.base.Objects.ToStringHelper; import com.google.common.base.Objects.ToStringHelper;
import com.google.common.collect.ComparisonChain;
import com.google.common.collect.ForwardingSet; import com.google.common.collect.ForwardingSet;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
@ -38,7 +37,7 @@ import com.google.common.collect.ImmutableSet;
* @see <a href="http://docs.openstack.org/api/openstack-typeentity-service/2.0/content/Identity-Service-Concepts-e1362.html" * @see <a href="http://docs.openstack.org/api/openstack-typeentity-service/2.0/content/Identity-Service-Concepts-e1362.html"
/> />
*/ */
public class Service extends ForwardingSet<Endpoint> implements Comparable<Service> { public class Service extends ForwardingSet<Endpoint> {
public static Builder<?> builder() { public static Builder<?> builder() {
return new ConcreteBuilder(); return new ConcreteBuilder();
@ -53,7 +52,7 @@ public class Service extends ForwardingSet<Endpoint> implements Comparable<Servi
protected String type; protected String type;
protected String name; protected String name;
protected Set<Endpoint> endpoints = ImmutableSet.of(); protected ImmutableSet.Builder<Endpoint> endpoints = ImmutableSet.<Endpoint>builder();
/** /**
* @see Service#getType() * @see Service#getType()
@ -72,26 +71,38 @@ public class Service extends ForwardingSet<Endpoint> implements Comparable<Servi
} }
/** /**
* @see Service#getEndpoints() * @see Service#delegate()
*/ */
public T endpoints(Set<Endpoint> endpoints) { public T endpoint(Endpoint endpoint) {
this.endpoints = ImmutableSet.copyOf(checkNotNull(endpoints, "endpoints")); this.endpoints.add(endpoint);
return self(); return self();
} }
/**
* @see Service#delegate()
*/
public T endpoints(Iterable<Endpoint> endpoints) {
this.endpoints.addAll(endpoints);
return self();
}
/**
* @see #endpoints(Iterable)
*/
@Deprecated
public T endpoints(Endpoint... in) { public T endpoints(Endpoint... in) {
return endpoints(ImmutableSet.copyOf(in)); return endpoints(ImmutableSet.copyOf(in));
} }
public Service build() { public Service build() {
return new Service(type, name, endpoints); return new Service(type, name, endpoints.build());
} }
public T fromService(Service in) { public T fromService(Service in) {
return this return this
.type(in.getType()) .type(in.getType())
.name(in.getName()) .name(in.getName())
.endpoints(in.getEndpoints()); .endpoints(in);
} }
} }
private static class ConcreteBuilder extends Builder<ConcreteBuilder> { private static class ConcreteBuilder extends Builder<ConcreteBuilder> {
@ -131,8 +142,9 @@ public class Service extends ForwardingSet<Endpoint> implements Comparable<Servi
} }
/** /**
* @return the endpoints assigned to the service * Please use this as a Set
*/ */
@Deprecated
public Set<Endpoint> getEndpoints() { public Set<Endpoint> getEndpoints() {
return this.endpoints; return this.endpoints;
} }
@ -153,7 +165,7 @@ public class Service extends ForwardingSet<Endpoint> implements Comparable<Servi
} }
protected ToStringHelper string() { protected ToStringHelper string() {
return Objects.toStringHelper(this) return Objects.toStringHelper(this).omitNullValues()
.add("type", type).add("name", name).add("endpoints", endpoints); .add("type", type).add("name", name).add("endpoints", endpoints);
} }
@ -162,14 +174,6 @@ public class Service extends ForwardingSet<Endpoint> implements Comparable<Servi
return string().toString(); return string().toString();
} }
@Override
public int compareTo(Service that) {
return ComparisonChain.start()
.compare(this.type, that.type)
.compare(this.name, that.name)
.result();
}
@Override @Override
protected Set<Endpoint> delegate() { protected Set<Endpoint> delegate() {
return endpoints; return endpoints;

View File

@ -148,7 +148,7 @@ public class Tenant {
} }
protected ToStringHelper string() { protected ToStringHelper string() {
return Objects.toStringHelper(this) return Objects.toStringHelper(this).omitNullValues()
.add("id", id).add("name", name).add("description", description); .add("id", id).add("name", name).add("description", description);
} }

View File

@ -27,6 +27,7 @@ import org.jclouds.javax.annotation.Nullable;
import com.google.common.base.Objects; import com.google.common.base.Objects;
import com.google.common.base.Objects.ToStringHelper; import com.google.common.base.Objects.ToStringHelper;
import com.google.common.collect.ForwardingSet;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
/** /**
@ -37,10 +38,10 @@ import com.google.common.collect.ImmutableSet;
* tenant. * tenant.
* *
* @author Adrian Cole * @author Adrian Cole
* @see <a href="http://docs.openstack.org/api/openstack-identity-service/2.0/content/Identity-Service-Concepts-e1362.html" * @see <a href="http://docs.openstack.org/api/openstack-identity-service/2.0/content/Identity-User-Concepts-e1362.html"
* /> * />
*/ */
public class User { public class User extends ForwardingSet<Role> {
public static Builder<?> builder() { public static Builder<?> builder() {
return new ConcreteBuilder(); return new ConcreteBuilder();
@ -55,7 +56,7 @@ public class User {
protected String id; protected String id;
protected String name; protected String name;
protected Set<Role> roles = ImmutableSet.of(); protected ImmutableSet.Builder<Role> roles = ImmutableSet.<Role> builder();
/** /**
* @see User#getId() * @see User#getId()
@ -74,26 +75,38 @@ public class User {
} }
/** /**
* @see User#getRoles() * @see User#delegate()
*/ */
public T roles(Set<Role> roles) { public T role(Role role) {
this.roles = ImmutableSet.copyOf(checkNotNull(roles, "roles")); this.roles.add(role);
return self(); return self();
} }
/**
* @see User#delegate()
*/
public T roles(Iterable<Role> roles) {
this.roles.addAll(roles);
return self();
}
/**
* @see #roles(Iterable)
*/
@Deprecated
public T roles(Role... in) { public T roles(Role... in) {
return roles(ImmutableSet.copyOf(in)); return roles(ImmutableSet.copyOf(in));
} }
public User build() { public User build() {
return new User(id, name, roles); return new User(id, name, roles.build());
} }
public T fromUser(User in) { public T fromUser(User in) {
return this return this
.id(in.getId()) .id(in.getId())
.name(in.getName()) .name(in.getName())
.roles(in.getRoles()); .roles(in);
} }
} }
@ -114,7 +127,7 @@ public class User {
protected User(String id, String name, @Nullable Set<Role> roles) { protected User(String id, String name, @Nullable Set<Role> roles) {
this.id = checkNotNull(id, "id"); this.id = checkNotNull(id, "id");
this.name = checkNotNull(name, "name"); this.name = checkNotNull(name, "name");
this.roles = roles == null ? ImmutableSet.<Role>of() : ImmutableSet.copyOf(checkNotNull(roles, "roles")); this.roles = roles == null ? ImmutableSet.<Role>of() : ImmutableSet.copyOf(roles);
} }
/** /**
@ -134,8 +147,10 @@ public class User {
} }
/** /**
* Please use User as a Set
* @return the roles assigned to the user * @return the roles assigned to the user
*/ */
@Deprecated
public Set<Role> getRoles() { public Set<Role> getRoles() {
return this.roles; return this.roles;
} }
@ -156,7 +171,7 @@ public class User {
} }
protected ToStringHelper string() { protected ToStringHelper string() {
return Objects.toStringHelper(this) return Objects.toStringHelper(this).omitNullValues()
.add("id", id).add("name", name).add("roles", roles); .add("id", id).add("name", name).add("roles", roles);
} }
@ -165,4 +180,9 @@ public class User {
return string().toString(); return string().toString();
} }
@Override
protected Set<Role> delegate() {
return roles;
}
} }

View File

@ -18,29 +18,63 @@
*/ */
package org.jclouds.openstack.keystone.v2_0.suppliers; package org.jclouds.openstack.keystone.v2_0.suppliers;
import static com.google.common.collect.Iterables.any;
import static com.google.common.collect.Iterables.concat;
import static com.google.common.collect.Iterables.size;
import static com.google.common.collect.Iterables.tryFind;
import static com.google.common.collect.Multimaps.index;
import java.net.URI; import java.net.URI;
import java.util.Collection;
import java.util.Map; import java.util.Map;
import java.util.NoSuchElementException; import java.util.NoSuchElementException;
import java.util.Set;
import javax.inject.Inject; import javax.annotation.Resource;
import javax.inject.Singleton; import javax.inject.Singleton;
import org.jclouds.javax.annotation.Nullable;
import org.jclouds.logging.Logger;
import org.jclouds.openstack.keystone.v2_0.domain.Access; import org.jclouds.openstack.keystone.v2_0.domain.Access;
import org.jclouds.openstack.keystone.v2_0.domain.Endpoint; import org.jclouds.openstack.keystone.v2_0.domain.Endpoint;
import org.jclouds.openstack.keystone.v2_0.domain.Service; import org.jclouds.openstack.keystone.v2_0.domain.Service;
import org.jclouds.openstack.keystone.v2_0.functions.EndpointToSupplierURI; import org.jclouds.openstack.keystone.v2_0.functions.EndpointToSupplierURI;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function; import com.google.common.base.Function;
import com.google.common.base.Optional;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
import com.google.common.base.Supplier; import com.google.common.base.Supplier;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMap.Builder;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import com.google.common.collect.Sets; import com.google.common.collect.Multimap;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted; import com.google.inject.assistedinject.Assisted;
@Singleton @Singleton
public class LocationIdToURIFromAccessForTypeAndVersion implements Supplier<Map<String, Supplier<URI>>> { public class LocationIdToURIFromAccessForTypeAndVersion implements Supplier<Map<String, Supplier<URI>>> {
public 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, or null if not available
* @return locations mapped to default uri
* @throws NoSuchElementException
* if the {@code apiType} is not present in the catalog
*/
LocationIdToURIFromAccessForTypeAndVersion createForApiTypeAndVersion(@Assisted("apiType") String apiType,
@Nullable @Assisted("apiVersion") String apiVersion) throws NoSuchElementException;
}
@Resource
protected Logger logger = Logger.NULL;
protected final Supplier<Access> access; protected final Supplier<Access> access;
protected final EndpointToSupplierURI endpointToSupplierURI; protected final EndpointToSupplierURI endpointToSupplierURI;
protected final Function<Endpoint, String> endpointToLocationId; protected final Function<Endpoint, String> endpointToLocationId;
@ -50,7 +84,7 @@ public class LocationIdToURIFromAccessForTypeAndVersion implements Supplier<Map<
@Inject @Inject
public LocationIdToURIFromAccessForTypeAndVersion(Supplier<Access> access, public LocationIdToURIFromAccessForTypeAndVersion(Supplier<Access> access,
EndpointToSupplierURI endpointToSupplierURI, Function<Endpoint, String> endpointToLocationId, EndpointToSupplierURI endpointToSupplierURI, Function<Endpoint, String> endpointToLocationId,
@Assisted("apiType") String apiType, @Assisted("apiVersion") String apiVersion) { @Assisted("apiType") String apiType, @Nullable @Assisted("apiVersion") String apiVersion) {
this.access = access; this.access = access;
this.endpointToSupplierURI = endpointToSupplierURI; this.endpointToSupplierURI = endpointToSupplierURI;
this.endpointToLocationId = endpointToLocationId; this.endpointToLocationId = endpointToLocationId;
@ -60,38 +94,112 @@ public class LocationIdToURIFromAccessForTypeAndVersion implements Supplier<Map<
@Override @Override
public Map<String, Supplier<URI>> get() { public Map<String, Supplier<URI>> get() {
Access accessResponse = access.get(); FluentIterable<Service> services = FluentIterable.from(access.get()).filter(apiTypeEquals);
Set<Service> services = Sets.filter(accessResponse.getServiceCatalog(), new Predicate<Service>() { if (services.toImmutableSet().size() == 0)
throw new NoSuchElementException(String.format("apiType %s not found in catalog %s", apiType, services));
Iterable<Endpoint> endpoints = concat(services);
if (size(endpoints) == 0)
throw new NoSuchElementException(
String.format("no endpoints for apiType %s in services %s", apiType, services));
boolean checkVersionId = any(endpoints, versionAware);
Multimap<String, Endpoint> locationToEndpoints = index(endpoints, endpointToLocationId);
Map<String, Endpoint> locationToEndpoint;
if (checkVersionId && apiVersion != null) {
locationToEndpoint = refineToVersionSpecificEndpoint(locationToEndpoints);
if (locationToEndpoint.size() == 0)
throw new NoSuchElementException(String.format(
"no endpoints for apiType %s are of version %s, or version agnostic: %s", apiType, apiVersion,
locationToEndpoints));
} else {
locationToEndpoint = firstEndpointInLocation(locationToEndpoints);
}
logger.debug("endpoints for apiType %s and version %s: %s", apiType, apiVersion, locationToEndpoints);
return Maps.transformValues(locationToEndpoint, endpointToSupplierURI);
}
@VisibleForTesting
Map<String, Endpoint> firstEndpointInLocation(Multimap<String, Endpoint> locationToEndpoints) {
Builder<String, Endpoint> locationToEndpointBuilder = ImmutableMap.<String, Endpoint> builder();
for (String locationId : locationToEndpoints.keySet()) {
Collection<Endpoint> endpoints = locationToEndpoints.get(locationId);
switch (endpoints.size()) {
case 0:
logNoEndpointsInLocation(locationId);
break;
default:
locationToEndpointBuilder.put(locationId, Iterables.get(endpoints, 0));
}
}
return locationToEndpointBuilder.build();
}
@VisibleForTesting
Map<String, Endpoint> refineToVersionSpecificEndpoint(Multimap<String, Endpoint> locationToEndpoints) {
Builder<String, Endpoint> locationToEndpointBuilder = ImmutableMap.<String, Endpoint> builder();
for (String locationId : locationToEndpoints.keySet()) {
Collection<Endpoint> endpoints = locationToEndpoints.get(locationId);
switch (endpoints.size()) {
case 0:
logNoEndpointsInLocation(locationId);
break;
default:
putIfPresent(locationId, strictMatchEndpointVersion(endpoints, locationId), locationToEndpointBuilder);
}
}
return locationToEndpointBuilder.build();
}
/**
* Prioritizes endpoint.versionId over endpoint.id when matching
*/
private Optional<Endpoint> strictMatchEndpointVersion(Iterable<Endpoint> endpoints, String locationId) {
Optional<Endpoint> endpointOfVersion = tryFind(endpoints, apiVersionEqualsVersionId);
if (!endpointOfVersion.isPresent())
logger.debug("no endpoints of apiType %s matched expected version %s in location %s: %s", apiType, apiVersion,
locationId, endpoints);
return endpointOfVersion;
}
private void logNoEndpointsInLocation(String locationId) {
logger.debug("no endpoints found for apiType %s in location %s", apiType, locationId);
}
private final Predicate<Endpoint> apiVersionEqualsVersionId = new Predicate<Endpoint>() {
@Override
public boolean apply(Endpoint input) {
return input.getVersionId().equals(apiVersion);
}
};
private final Predicate<Endpoint> versionAware = new Predicate<Endpoint>() {
@Override
public boolean apply(Endpoint input) {
return input.getVersionId() != null;
}
};
private final Predicate<Service> apiTypeEquals = new Predicate<Service>() {
@Override @Override
public boolean apply(Service input) { public boolean apply(Service input) {
return input.getType().equals(apiType); return input.getType().equals(apiType);
} }
}); };
if (services.size() == 0)
throw new NoSuchElementException(String.format("apiType %s not found in catalog %s", apiType,
accessResponse.getServiceCatalog()));
Iterable<Endpoint> endpoints = Iterables.filter(Iterables.concat(services), new Predicate<Endpoint>() { private static <K, V> void putIfPresent(K key, Optional<V> value, Builder<K, V> builder) {
if (value.isPresent())
@Override builder.put(key, value.get());
public boolean apply(Endpoint input) {
if (input.getVersionId() == null) {
return true;
}
return input.getVersionId().equals(apiVersion);
}
});
if (Iterables.size(endpoints) == 0)
throw new NoSuchElementException(String.format(
"no endpoints for apiType %s are of version %s, or version agnostic: %s", apiType, apiVersion,
services));
Map<String, Endpoint> locationIdToEndpoint = Maps.uniqueIndex(endpoints, endpointToLocationId);
return Maps.transformValues(locationIdToEndpoint, endpointToSupplierURI);
} }
@Override @Override

View File

@ -143,7 +143,7 @@ public class TokenApiExpectTest extends BaseKeystoneRestApiExpectTest<KeystoneAp
assertEquals(endpoints, ImmutableSet.of( assertEquals(endpoints, ImmutableSet.of(
Endpoint.builder().publicURL(URI.create("https://csnode.jclouds.org/v2.0/")) Endpoint.builder().publicURL(URI.create("https://csnode.jclouds.org/v2.0/"))
.adminURL(URI.create("https://csnode.jclouds.org:35357/v2.0/")) .adminURL(URI.create("https://csnode.jclouds.org:35357/v2.0/"))
.region("region-a.geo-1").versionId("2.0").build() .region("region-a.geo-1").id("2.0").versionId("2.0").build()
)); ));
} }

View File

@ -18,8 +18,6 @@
*/ */
package org.jclouds.openstack.keystone.v2_0.parse; package org.jclouds.openstack.keystone.v2_0.parse;
import java.net.URI;
import javax.ws.rs.Consumes; import javax.ws.rs.Consumes;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
@ -50,70 +48,67 @@ public class ParseAccessTest extends BaseItemParserTest<Access> {
@SelectJson("access") @SelectJson("access")
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public Access expected() { public Access expected() {
return Access.builder().token( return Access.builder()
Token.builder().expires(new SimpleDateFormatDateService().iso8601DateParse("2012-01-18T21:35:59.050Z")) .token(Token.builder()
.id("Auth_4f173437e4b013bee56d1007").tenant( .expires(new SimpleDateFormatDateService().iso8601DateParse("2012-01-18T21:35:59.050Z"))
Tenant.builder().id("40806637803162").name("user@jclouds.org-default-tenant").build()) .id("Auth_4f173437e4b013bee56d1007")
.build()).user( .tenant(Tenant.builder().id("40806637803162").name("user@jclouds.org-default-tenant").build()).build())
User.builder().id("36980896575174").name("user@jclouds.org").roles( .user(User.builder()
Role.builder().id("00000000004022").serviceId("110").name("Admin").tenantId("40806637803162") .id("36980896575174").name("user@jclouds.org")
.build(), .role(Role.builder().id("00000000004022").serviceId("110").name("Admin").tenantId("40806637803162").build())
Role.builder().id("00000000004024").serviceId("140").name("user").tenantId("40806637803162") .role(Role.builder().id("00000000004024").serviceId("140").name("user").tenantId("40806637803162").build())
.build(), .role(Role.builder().id("00000000004004").serviceId("100").name("domainuser").build())
Role.builder().id("00000000004004").serviceId("100").name("domainuser").build(), .role(Role.builder().id("00000000004016").serviceId("120").name("netadmin").tenantId("40806637803162").build()).build())
Role.builder().id("00000000004016").serviceId("120").name("netadmin") .service(Service.builder().name("Object Storage").type("object-store")
.tenantId("40806637803162").build()).build()).serviceCatalog( .endpoint(Endpoint.builder()
.tenantId("40806637803162")
Service.builder().name("Object Storage").type("object-store").endpoints( .publicURL("https://objects.jclouds.org/v1.0/40806637803162")
Endpoint.builder().tenantId("40806637803162").publicURL( .adminURL("https://objects.jclouds.org/v1.0/")
URI.create("https://objects.jclouds.org/v1.0/40806637803162")) .id("1.0")
.adminURL(URI.create("https://objects.jclouds.org/v1.0/")) .region("region-a.geo-1").build()).build())
.region("region-a.geo-1").versionId("1.0").build()).build(), .service(Service.builder().name("Identity").type("identity")
.endpoint(Endpoint.builder()
Service.builder().name("Identity").type("identity").endpoints( .publicURL("https://csnode.jclouds.org/v2.0/")
Endpoint.builder().publicURL(URI.create("https://csnode.jclouds.org/v2.0/")) .adminURL("https://csnode.jclouds.org:35357/v2.0/")
.adminURL(URI.create("https://csnode.jclouds.org:35357/v2.0/")) .region("region-a.geo-1")
.region("region-a.geo-1").versionId("2.0").build()).build(), .id("2.0")
.versionId("2.0").build()).build())
Service.builder().name("Image Management").type("image").endpoints( .service(Service.builder().name("Image Management").type("image")
Endpoint.builder().tenantId("40806637803162").publicURL( .endpoint(Endpoint.builder()
URI.create("https://glance.jclouds.org:9292/v1.0")).region("az-1.region-a.geo-1") .tenantId("40806637803162")
.versionId("1.0").build()).build(), .publicURL("https://glance.jclouds.org:9292/v1.0")
.region("az-1.region-a.geo-1")
Service.builder().name("Compute").type("compute").endpoints( .id("1.0").build()).build())
Endpoint.builder() .service(Service.builder().name("Compute").type("compute")
.endpoint(Endpoint.builder()
.tenantId("3456") .tenantId("3456")
.publicURL(URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456")) .publicURL("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456")
.region("az-1.region-a.geo-1") .region("az-1.region-a.geo-1")
.versionId("1.1") .versionId("1.1")
.versionInfo(URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/")) .versionInfo("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/")
.versionList(URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com")).build(), .versionList("https://az-1.region-a.geo-1.compute.hpcloudsvc.com").build())
Endpoint.builder() .endpoint(Endpoint.builder()
.tenantId("3456") .tenantId("3456")
.publicURL(URI.create("https://az-2.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456")) .publicURL("https://az-2.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456")
.region("az-2.region-a.geo-1") .region("az-2.region-a.geo-1")
.versionId("1.1") .versionId("1.1")
.versionInfo(URI.create("https://az-2.region-a.geo-1.compute.hpcloudsvc.com/v1.1/")) .versionInfo("https://az-2.region-a.geo-1.compute.hpcloudsvc.com/v1.1/")
.versionList(URI.create("https://az-2.region-a.geo-1.compute.hpcloudsvc.com")).build(), .versionList("https://az-2.region-a.geo-1.compute.hpcloudsvc.com").build())
Endpoint.builder() .endpoint(Endpoint.builder()
.tenantId("3456") .tenantId("3456")
.publicURL(URI.create("https://az-3.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456")) .publicURL("https://az-3.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456")
.region("az-3.region-a.geo-1") .region("az-3.region-a.geo-1")
.versionId("1.1") .versionId("1.1")
.versionInfo(URI.create("https://az-3.region-a.geo-1.compute.hpcloudsvc.com/v1.1/")) .versionInfo("https://az-3.region-a.geo-1.compute.hpcloudsvc.com/v1.1/")
.versionList(URI.create("https://az-3.region-a.geo-1.compute.hpcloudsvc.com")).build()).build(), .versionList("https://az-3.region-a.geo-1.compute.hpcloudsvc.com").build()).build())
.service(Service.builder().name("Quantum Service").type("network")
Service.builder().name("Quantum Service").type("network").endpoints( .endpoint(Endpoint.builder()
Endpoint.builder()
.tenantId("3456") .tenantId("3456")
.publicURL(URI.create("https://csnode.jclouds.org:9696/v1.0/tenants/3456")) .publicURL("https://csnode.jclouds.org:9696/v1.0/tenants/3456")
.internalURL(URI.create("https://csnode.jclouds.org:9696/v1.0/tenants/3456")) .internalURL("https://csnode.jclouds.org:9696/v1.0/tenants/3456")
.adminURL(URI.create("https://csnode.jclouds.org:9696/v1.0")) .adminURL("https://csnode.jclouds.org:9696/v1.0")
.region("region-a.geo-1") .region("region-a.geo-1")
.versionId("1.0").build() .versionId("1.0").build()).build()).build();
).build())
.build();
} }
} }

View File

@ -18,8 +18,6 @@
*/ */
package org.jclouds.openstack.keystone.v2_0.parse; package org.jclouds.openstack.keystone.v2_0.parse;
import java.net.URI;
import javax.ws.rs.Consumes; import javax.ws.rs.Consumes;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
@ -36,7 +34,7 @@ import org.jclouds.rest.annotations.SelectJson;
import org.testng.annotations.Test; import org.testng.annotations.Test;
/** /**
* @author Adam Lowe * @author Adam Lowe, Adrian Cole
*/ */
@Test(groups = "unit", testName = "ParseAdminAccessTest") @Test(groups = "unit", testName = "ParseAdminAccessTest")
public class ParseAdminAccessTest extends BaseItemParserTest<Access> { public class ParseAdminAccessTest extends BaseItemParserTest<Access> {
@ -50,52 +48,52 @@ public class ParseAdminAccessTest extends BaseItemParserTest<Access> {
@SelectJson("access") @SelectJson("access")
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public Access expected() { public Access expected() {
return Access.builder().token( return Access.builder()
Token.builder().expires(new SimpleDateFormatDateService().iso8601SecondsDateParse("2012-08-01T13:08:52Z")) .token(Token.builder()
.id("946b8ad1ede4422f87ab21dcba27896d").tenant( .expires(new SimpleDateFormatDateService().iso8601SecondsDateParse("2012-08-01T13:08:52Z"))
Tenant.builder().id("2fdc88ae152948c690b97ba307acae9b").name("admin").build()) .id("946b8ad1ede4422f87ab21dcba27896d")
.build()).user( .tenant(Tenant.builder().id("2fdc88ae152948c690b97ba307acae9b").name("admin").build()).build())
User.builder().id("b4d134cfe3cf43ad8ba0c2fc5b5d8f91").name("admin").roles( .user(User.builder()
Role.builder().name("admin").build(), .id("b4d134cfe3cf43ad8ba0c2fc5b5d8f91")
Role.builder().name("KeystoneServiceAdmin").build(), .name("admin")
Role.builder().name("KeystoneAdmin").build()).build()) .role(Role.builder().name("admin").build())
.serviceCatalog( .role(Role.builder().name("KeystoneServiceAdmin").build())
Service.builder().name("Compute Service").type("compute").endpoints( .role(Role.builder().name("KeystoneAdmin").build()).build())
Endpoint.builder() .service(Service.builder().name("Compute Service").type("compute")
.adminURL(URI.create("http://10.0.1.13:8774/v2/2fdc88ae152948c690b97ba307acae9b")) .endpoint(Endpoint.builder()
.internalURL(URI.create("http://10.0.1.13:8774/v2/2fdc88ae152948c690b97ba307acae9b")) .adminURL("http://10.0.1.13:8774/v2/2fdc88ae152948c690b97ba307acae9b")
.publicURL(URI.create("http://10.0.1.13:8774/v2/2fdc88ae152948c690b97ba307acae9b")) .internalURL("http://10.0.1.13:8774/v2/2fdc88ae152948c690b97ba307acae9b")
.region("RegionOne").build()).build(), .publicURL("http://10.0.1.13:8774/v2/2fdc88ae152948c690b97ba307acae9b")
Service.builder().name("S3 Service").type("s3").endpoints( .region("RegionOne").build()).build())
Endpoint.builder() .service(Service.builder().name("S3 Service").type("s3")
.adminURL(URI.create("http://10.0.1.13:3333")) .endpoint(Endpoint.builder()
.internalURL(URI.create("http://10.0.1.13:3333")) .adminURL("http://10.0.1.13:3333")
.publicURL(URI.create("http://10.0.1.13:3333")) .internalURL("http://10.0.1.13:3333")
.region("RegionOne").build()).build(), .publicURL("http://10.0.1.13:3333")
Service.builder().name("Image Service").type("image").endpoints( .region("RegionOne").build()).build())
Endpoint.builder() .service(Service.builder().name("Image Service").type("image")
.adminURL(URI.create("http://10.0.1.13:9292")) .endpoint(Endpoint.builder()
.internalURL(URI.create("http://10.0.1.13:9292")) .adminURL("http://10.0.1.13:9292")
.publicURL(URI.create("http://10.0.1.13:9292")) .internalURL("http://10.0.1.13:9292")
.region("RegionOne").build()).build(), .publicURL("http://10.0.1.13:9292")
Service.builder().name("Volume Service").type("volume").endpoints( .region("RegionOne").build()).build())
Endpoint.builder() .service(Service.builder().name("Volume Service").type("volume")
.adminURL(URI.create("http://10.0.1.13:8776/v1/2fdc88ae152948c690b97ba307acae9b")) .endpoint(Endpoint.builder()
.internalURL(URI.create("http://10.0.1.13:8776/v1/2fdc88ae152948c690b97ba307acae9b")) .adminURL("http://10.0.1.13:8776/v1/2fdc88ae152948c690b97ba307acae9b")
.publicURL(URI.create("http://10.0.1.13:8776/v1/2fdc88ae152948c690b97ba307acae9b")) .internalURL("http://10.0.1.13:8776/v1/2fdc88ae152948c690b97ba307acae9b")
.region("RegionOne").build()).build(), .publicURL("http://10.0.1.13:8776/v1/2fdc88ae152948c690b97ba307acae9b")
Service.builder().name("EC2 Service").type("ec2").endpoints( .region("RegionOne").build()).build())
Endpoint.builder() .service(Service.builder().name("EC2 Service").type("ec2")
.adminURL(URI.create("http://10.0.1.13:8773/services/Admin")) .endpoint(Endpoint.builder()
.internalURL(URI.create("http://10.0.1.13:8773/services/Cloud")) .adminURL("http://10.0.1.13:8773/services/Admin")
.publicURL(URI.create("http://10.0.1.13:8773/services/Cloud")) .internalURL("http://10.0.1.13:8773/services/Cloud")
.region("RegionOne").build()).build(), .publicURL("http://10.0.1.13:8773/services/Cloud")
Service.builder().name("Identity Service").type("identity").endpoints( .region("RegionOne").build()).build())
Endpoint.builder() .service(Service.builder().name("Identity Service").type("identity")
.adminURL(URI.create("http://10.0.1.13:35357/v2.0")) .endpoint(Endpoint.builder()
.internalURL(URI.create("http://10.0.1.13:5000/v2.0")) .adminURL("http://10.0.1.13:35357/v2.0")
.publicURL(URI.create("http://10.0.1.13:5000/v2.0")) .internalURL("http://10.0.1.13:5000/v2.0")
.region("RegionOne").build()).build() .publicURL("http://10.0.1.13:5000/v2.0")
).build(); .region("RegionOne").build()).build()).build();
} }
} }

View File

@ -18,8 +18,6 @@
*/ */
package org.jclouds.openstack.keystone.v2_0.parse; package org.jclouds.openstack.keystone.v2_0.parse;
import java.net.URI;
import javax.ws.rs.Consumes; import javax.ws.rs.Consumes;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
@ -38,7 +36,7 @@ import org.testng.annotations.Test;
/** /**
* @author Adrian Cole * @author Adrian Cole
*/ */
@Test(groups = "unit", testName = "ParseAccessTest") @Test(groups = "unit", testName = "ParseRackspaceAccessTest")
public class ParseRackspaceAccessTest extends BaseItemParserTest<Access> { public class ParseRackspaceAccessTest extends BaseItemParserTest<Access> {
@Override @Override
@ -50,64 +48,69 @@ public class ParseRackspaceAccessTest extends BaseItemParserTest<Access> {
@SelectJson("access") @SelectJson("access")
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public Access expected() { public Access expected() {
return Access.builder().token( return Access.builder()
Token.builder().expires(new SimpleDateFormatDateService().iso8601DateParse("2012-06-06T20:56:47.000-05:00")) .token(Token.builder()
.id("Auth_4f173437e4b013bee56d1007").tenant( .expires(new SimpleDateFormatDateService().iso8601DateParse("2012-06-06T20:56:47.000-05:00"))
Tenant.builder().id("40806637803162").name("40806637803162").build()) .id("Auth_4f173437e4b013bee56d1007")
.build()).user( .tenant(Tenant.builder().id("40806637803162").name("40806637803162").build()).build())
User.builder().id("54321").name("joe").roles( .user(User.builder()
Role.builder().id("3").name("identity:user-admin").description("User Admin Role.") .id("54321")
.build()).build()).serviceCatalog( .name("joe")
.role(Role.builder()
Service.builder().name("cloudDatabases").type("rax:database").endpoints( .id("3")
Endpoint.builder().tenantId("40806637803162").publicURL( .name("identity:user-admin")
URI.create("https://dfw.databases.api.rackspacecloud.com/v1.0/40806637803162")) .description("User Admin Role.").build()).build())
.region("DFW").build(), .service(Service.builder().name("cloudDatabases").type("rax:database")
Endpoint.builder().tenantId("40806637803162").publicURL( .endpoint(Endpoint.builder()
URI.create("https://ord.databases.api.rackspacecloud.com/v1.0/40806637803162")) .tenantId("40806637803162")
.region("ORD").build()).build(), .publicURL("https://dfw.databases.api.rackspacecloud.com/v1.0/40806637803162")
.region("DFW").build())
Service.builder().name("cloudServers").type("compute").endpoints( .endpoint(Endpoint.builder()
Endpoint.builder().tenantId("40806637803162").publicURL( .tenantId("40806637803162")
URI.create("https://servers.api.rackspacecloud.com/v1.0/40806637803162")) .publicURL("https://ord.databases.api.rackspacecloud.com/v1.0/40806637803162")
.versionId("1.0").versionInfo(URI.create("https://servers.api.rackspacecloud.com/v1.0")) .region("ORD").build()).build())
.versionList(URI.create("https://servers.api.rackspacecloud.com/")).build()).build(), .service(Service.builder().name("cloudServers").type("compute")
.endpoint(Endpoint.builder()
Service.builder().name("cloudFiles").type("object-store").endpoints( .tenantId("40806637803162")
Endpoint.builder().tenantId("MossoCloudFS_dc1f419c-5059-4c87-a389-3f2e33a77b22").publicURL( .publicURL("https://servers.api.rackspacecloud.com/v1.0/40806637803162")
URI.create("https://storage101.dfw1.clouddrive.com/v1/MossoCloudFS_dc1f419c-5059-4c87-a389-3f2e33a77b22")) .versionId("1.0")
.internalURL( .versionInfo("https://servers.api.rackspacecloud.com/v1.0")
URI.create("https://snet-storage101.dfw1.clouddrive.com/v1/MossoCloudFS_dc1f419c-5059-4c87-a389-3f2e33a77b22")) .versionList("https://servers.api.rackspacecloud.com/").build()).build())
.region("DFW").build()).build(), .service(Service.builder().name("cloudFiles").type("object-store")
.endpoint(Endpoint.builder()
Service.builder().name("cloudServersOpenStack").type("compute").endpoints( .tenantId("MossoCloudFS_dc1f419c-5059-4c87-a389-3f2e33a77b22")
Endpoint.builder().tenantId("40806637803162").publicURL( .publicURL("https://storage101.dfw1.clouddrive.com/v1/MossoCloudFS_dc1f419c-5059-4c87-a389-3f2e33a77b22")
URI.create("https://dfw.servers.api.rackspacecloud.com/v2/40806637803162")) .internalURL("https://snet-storage101.dfw1.clouddrive.com/v1/MossoCloudFS_dc1f419c-5059-4c87-a389-3f2e33a77b22")
.versionInfo(URI.create("https://dfw.servers.api.rackspacecloud.com/v2")) .region("DFW").build()).build())
.versionList(URI.create("https://dfw.servers.api.rackspacecloud.com/")) .service(Service.builder().name("cloudServersOpenStack").type("compute")
.endpoint(Endpoint.builder()
.tenantId("40806637803162")
.publicURL("https://dfw.servers.api.rackspacecloud.com/v2/40806637803162")
.versionInfo("https://dfw.servers.api.rackspacecloud.com/v2")
.versionList("https://dfw.servers.api.rackspacecloud.com/")
.versionId("2") .versionId("2")
.region("DFW").build()).build(), .region("DFW").build()).build())
.service(Service.builder().name("cloudLoadBalancers").type("rax:load-balancer")
Service.builder().name("cloudLoadBalancers").type("rax:load-balancer").endpoints( .endpoint(Endpoint.builder()
Endpoint.builder().tenantId("40806637803162").publicURL( .tenantId("40806637803162")
URI.create("https://ord.loadbalancers.api.rackspacecloud.com/v1.0/40806637803162")) .publicURL("https://ord.loadbalancers.api.rackspacecloud.com/v1.0/40806637803162")
.region("ORD").build(), .region("ORD").build())
Endpoint.builder().tenantId("40806637803162").publicURL( .endpoint(Endpoint.builder()
URI.create("https://dfw.loadbalancers.api.rackspacecloud.com/v1.0/40806637803162")) .tenantId("40806637803162")
.region("DFW").build()).build(), .publicURL("https://dfw.loadbalancers.api.rackspacecloud.com/v1.0/40806637803162")
.region("DFW").build()).build())
Service.builder().name("cloudMonitoring").type("rax:monitor").endpoints( .service(Service.builder().name("cloudMonitoring").type("rax:monitor")
Endpoint.builder().tenantId("40806637803162").publicURL( .endpoint(Endpoint.builder()
URI.create("https://monitoring.api.rackspacecloud.com/v1.0/40806637803162")).build()).build(), .tenantId("40806637803162")
.publicURL("https://monitoring.api.rackspacecloud.com/v1.0/40806637803162").build()).build())
Service.builder().name("cloudDNS").type("dnsextension:dns").endpoints( .service(Service.builder().name("cloudDNS").type("dnsextension:dns")
Endpoint.builder().tenantId("40806637803162").publicURL( .endpoint(Endpoint.builder()
URI.create("https://dns.api.rackspacecloud.com/v1.0/40806637803162")).build()).build(), .tenantId("40806637803162")
.publicURL("https://dns.api.rackspacecloud.com/v1.0/40806637803162").build()).build())
Service.builder().name("cloudFilesCDN").type("rax:object-cdn").endpoints( .service(Service.builder().name("cloudFilesCDN").type("rax:object-cdn")
Endpoint.builder().tenantId("MossoCloudFS_dc1f419c-5059-4c87-a389-3f2e33a77b22").publicURL( .endpoint(Endpoint.builder()
URI.create("https://cdn1.clouddrive.com/v1/MossoCloudFS_dc1f419c-5059-4c87-a389-3f2e33a77b22")) .tenantId("MossoCloudFS_dc1f419c-5059-4c87-a389-3f2e33a77b22")
.region("DFW").build()).build() .publicURL("https://cdn1.clouddrive.com/v1/MossoCloudFS_dc1f419c-5059-4c87-a389-3f2e33a77b22")
).build(); .region("DFW").build()).build()).build();
} }
} }

View File

@ -0,0 +1,112 @@
/**
* 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 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.keystone.v2_0.domain.Access;
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;
/**
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "ParseRandomEndpointVersionAccessTest")
public class ParseRandomEndpointVersionAccessTest extends BaseItemParserTest<Access> {
@Override
public String resource() {
return "/access_version_uids.json";
}
@Override
@SelectJson("access")
@Consumes(MediaType.APPLICATION_JSON)
public Access expected() {
return Access.builder()
.token(Token.builder()
.expires(new SimpleDateFormatDateService().iso8601SecondsDateParse("2012-09-29T19:53:45Z"))
.id("b267e2e240624b108b1ed5bba6e5882e")
.tenant(Tenant.builder()
// "enabled": true,
.id("82d8d2f865484776a1daf1e2245d3317")
.name("demo").build()).build())
.service(Service.builder().type("compute").name("nova")
.endpoint(Endpoint.builder()
.adminURL("http://10.10.10.10:8774/v2/82d8d2f865484776a1daf1e2245d3317")
.region("RegionOne")
.internalURL("http://10.10.10.10:8774/v2/82d8d2f865484776a1daf1e2245d3317")
.id("bb3ce9ccdc5045909882688b90cc3ff0")
.publicURL("http://10.10.10.10:8774/v2/82d8d2f865484776a1daf1e2245d3317").build()).build())
.service(Service.builder().type("s3").name("s3")
.endpoint(Endpoint.builder()
.adminURL("http://10.10.10.10:3333")
.region("RegionOne")
.internalURL("http://10.10.10.10:3333")
.id("9646263f31ea4f499732c5e1370ecf5e")
.publicURL("http://10.10.10.10:3333").build()).build())
.service(Service.builder().type("image").name("glance")
.endpoint(Endpoint.builder()
.adminURL("http://10.10.10.10:9292")
.region("RegionOne")
.internalURL("http://10.10.10.10:9292")
.id("aa5d0b2574824ba097dc07faacf3be65")
.publicURL("http://10.10.10.10:9292").build()).build())
.service(Service.builder().type("volume").name("cinder")
.endpoint(Endpoint.builder()
.adminURL("http://10.10.10.10:8776/v1/82d8d2f865484776a1daf1e2245d3317")
.region("RegionOne")
.internalURL("http://10.10.10.10:8776/v1/82d8d2f865484776a1daf1e2245d3317")
.id("7679065b1405447eb5f1a38a6b99ccc0")
.publicURL("http://10.10.10.10:8776/v1/82d8d2f865484776a1daf1e2245d3317").build()).build())
.service(Service.builder().type("ec2").name("ec2")
.endpoint(Endpoint.builder()
.adminURL("http://10.10.10.10:8773/services/Admin")
.region("RegionOne")
.internalURL("http://10.10.10.10:8773/services/Cloud")
.id("22b007f023fb4c42be094916eb2bf18b")
.publicURL("http://10.10.10.10:8773/services/Cloud").build()).build())
.service(Service.builder().type("identity").name("keystone")
.endpoint(Endpoint.builder()
.adminURL("http://10.10.10.10:35357/v2.0")
.region("RegionOne")
.internalURL("http://10.10.10.10:5000/v2.0")
.id("57ee5fb4f9a840f3b965909681d0fc53")
.publicURL("http://10.10.10.10:5000/v2.0").build()).build())
.user(User.builder()
.id("ca248caf55844c14a4876c22112bbbb9")
.name("demo")
// .username("demo")
.role(Role.builder().name("Member").build()).build()).build();
// "metadata": {
// "is_admin": 0,
// "roles": ["1f697d8e3ace4f5a80f7701e554ee5d9"]
// }
}
}

View File

@ -0,0 +1,131 @@
/**
* 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 java.util.NoSuchElementException;
import javax.inject.Singleton;
import org.jclouds.location.Provider;
import org.jclouds.openstack.keystone.v2_0.domain.Access;
import org.jclouds.openstack.keystone.v2_0.domain.Endpoint;
import org.jclouds.openstack.keystone.v2_0.functions.EndpointToRegion;
import org.jclouds.openstack.keystone.v2_0.parse.ParseAccessTest;
import org.jclouds.openstack.keystone.v2_0.parse.ParseRackspaceAccessTest;
import org.testng.annotations.Test;
import com.google.common.base.Function;
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.TypeLiteral;
import com.google.inject.assistedinject.FactoryModuleBuilder;
/**
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "LocationIdToURIFromAccessForTypeAndVersionTest")
public class LocationIdToURIFromAccessForTypeAndVersionTest {
private final LocationIdToURIFromAccessForTypeAndVersion.Factory factory = Guice.createInjector(new AbstractModule() {
@Override
protected void configure() {
bindConstant().annotatedWith(Provider.class).to("openstack-keystone");
bind(new TypeLiteral<Supplier<URI>>(){
}).annotatedWith(Provider.class).toInstance(Suppliers.ofInstance(URI.create("https://identity")));
bind(new TypeLiteral<Function<Endpoint, String>>(){}).to(EndpointToRegion.class);
install(new FactoryModuleBuilder().implement(LocationIdToURIFromAccessForTypeAndVersion.class,
LocationIdToURIFromAccessForTypeAndVersion.class).build(
LocationIdToURIFromAccessForTypeAndVersion.Factory.class));
}
@Provides
@Singleton
public Supplier<Access> provide() {
return Suppliers.ofInstance(new ParseAccessTest().expected());
}
}).getInstance(LocationIdToURIFromAccessForTypeAndVersion.Factory.class);
public void testRegionUnmatchesOkWhenNoVersionIdSet() {
assertEquals(Maps.transformValues(factory.createForApiTypeAndVersion("compute", "1.1").get(), Suppliers
.<URI> supplierFunction()), ImmutableMap.of("az-1.region-a.geo-1", URI
.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456"), "az-2.region-a.geo-1", URI
.create("https://az-2.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456"), "az-3.region-a.geo-1", URI
.create("https://az-3.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456")));
}
public void testRegionMatches() {
assertEquals(Maps.transformValues(factory.createForApiTypeAndVersion("compute", "1.1").get(), Suppliers
.<URI> supplierFunction()), ImmutableMap.of("az-1.region-a.geo-1", URI
.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456"), "az-2.region-a.geo-1", URI
.create("https://az-2.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456"), "az-3.region-a.geo-1", URI
.create("https://az-3.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456")));
}
private final LocationIdToURIFromAccessForTypeAndVersion.Factory raxFactory = Guice.createInjector(new AbstractModule() {
@Override
protected void configure() {
bindConstant().annotatedWith(Provider.class).to("rackspace");
bind(new TypeLiteral<Supplier<URI>>() {
}).annotatedWith(Provider.class).toInstance(Suppliers.ofInstance(URI.create("https://identity")));
bind(new TypeLiteral<Function<Endpoint, String>>(){}).to(EndpointToRegion.class);
install(new FactoryModuleBuilder().implement(LocationIdToURIFromAccessForTypeAndVersion.class,
LocationIdToURIFromAccessForTypeAndVersion.class).build(
LocationIdToURIFromAccessForTypeAndVersion.Factory.class));
}
@Provides
@Singleton
public Supplier<Access> provide() {
return Suppliers.ofInstance(new ParseRackspaceAccessTest().expected());
}
}).getInstance(LocationIdToURIFromAccessForTypeAndVersion.Factory.class);
@Test(expectedExceptions = NoSuchElementException.class)
public void testWhenNotInList() {
assertEquals(Maps.transformValues(raxFactory.createForApiTypeAndVersion("goo", "1.0").get(), Suppliers
.<URI> supplierFunction()), ImmutableMap.of("rackspace", URI
.create("https://servers.api.rackspacecloud.com/v1.0/40806637803162")));
}
public void testProviderWhenNoRegions() {
Map<String, URI> withNoRegions = Maps.transformValues(raxFactory.createForApiTypeAndVersion("compute", "1.0")
.get(), Suppliers.<URI> supplierFunction());
assertEquals(withNoRegions, ImmutableMap.of("rackspace", URI
.create("https://servers.api.rackspacecloud.com/v1.0/40806637803162")));
}
public void testOkWithNoVersions() {
assertEquals(Maps.transformValues(raxFactory.createForApiTypeAndVersion("rax:database", null).get(), Suppliers
.<URI> supplierFunction()), ImmutableMap.of("DFW", URI
.create("https://dfw.databases.api.rackspacecloud.com/v1.0/40806637803162"), "ORD", URI
.create("https://ord.databases.api.rackspacecloud.com/v1.0/40806637803162")));
}
}

View File

@ -18,11 +18,11 @@
*/ */
package org.jclouds.openstack.nova.v2_0; package org.jclouds.openstack.nova.v2_0;
import static org.jclouds.Constants.PROPERTY_ENDPOINT;
import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertEquals;
import java.util.Properties; import java.util.Properties;
import org.jclouds.Constants;
import org.jclouds.http.HttpRequest; import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse; import org.jclouds.http.HttpResponse;
import org.jclouds.openstack.nova.v2_0.internal.BaseNovaApiExpectTest; import org.jclouds.openstack.nova.v2_0.internal.BaseNovaApiExpectTest;
@ -31,13 +31,14 @@ import org.testng.annotations.Test;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
/** /**
* Tests to ensure that we can pick the only endpoint of a service
* *
* @author Adrian Cole * @author Adrian Cole
*/ */
@Test(groups = "unit", testName = "OverrideApiVersionExpectTest") @Test(groups = "unit", testName = "EndpointIdIsRandomExpectTest")
public class OverrideApiVersionExpectTest extends BaseNovaApiExpectTest { public class EndpointIdIsRandomExpectTest extends BaseNovaApiExpectTest {
public OverrideApiVersionExpectTest() { public EndpointIdIsRandomExpectTest() {
this.identity = "demo:demo"; this.identity = "demo:demo";
this.credential = "password"; this.credential = "password";
} }
@ -45,20 +46,21 @@ public class OverrideApiVersionExpectTest extends BaseNovaApiExpectTest {
@Override @Override
protected Properties setupProperties() { protected Properties setupProperties() {
Properties overrides = super.setupProperties(); Properties overrides = super.setupProperties();
overrides.setProperty(Constants.PROPERTY_ENDPOINT, "http://10.10.10.10:5000/v2.0/"); overrides.setProperty(PROPERTY_ENDPOINT, "http://10.10.10.10:5000/v2.0/");
overrides.setProperty(provider + ".api-version", "bb3ce9ccdc5045909882688b90cc3ff0");
return overrides; return overrides;
} }
public void testVersionMatchOnConfiguredZonesWhenResponseIs2xx() { public void testVersionMatchOnConfiguredZonesWhenResponseIs2xx() {
HttpRequest authenticate = HttpRequest.builder().method("POST") HttpRequest authenticate = HttpRequest
.builder()
.method("POST")
.endpoint("http://10.10.10.10:5000/v2.0/tokens") .endpoint("http://10.10.10.10:5000/v2.0/tokens")
.addHeader("Accept", "application/json") .addHeader("Accept", "application/json")
.payload(payloadFromStringWithContentType( .payload(
"{\"auth\":{\"passwordCredentials\":{\"username\":\"demo\",\"password\":\"password\"},\"tenantName\":\"demo\"}}" payloadFromStringWithContentType(
, "application/json")).build(); "{\"auth\":{\"passwordCredentials\":{\"username\":\"demo\",\"password\":\"password\"},\"tenantName\":\"demo\"}}",
"application/json")).build();
HttpResponse authenticationResponse = HttpResponse.builder().statusCode(200) HttpResponse authenticationResponse = HttpResponse.builder().statusCode(200)
.payload(payloadFromResourceWithContentType("/access_version_uids.json", "application/json")).build(); .payload(payloadFromResourceWithContentType("/access_version_uids.json", "application/json")).build();