diff --git a/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/v2_0/config/KeystoneAuthenticationModule.java b/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/v2_0/config/KeystoneAuthenticationModule.java index 2432e346f0..c1e201211f 100644 --- a/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/v2_0/config/KeystoneAuthenticationModule.java +++ b/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/v2_0/config/KeystoneAuthenticationModule.java @@ -20,7 +20,9 @@ package org.jclouds.openstack.keystone.v2_0.config; import static com.google.common.base.Preconditions.checkArgument; import static org.jclouds.rest.config.BinderUtils.bindHttpApi; +import static org.jclouds.util.Suppliers2.getLastValueInMap; +import java.net.URI; import java.util.Map; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; @@ -48,14 +50,17 @@ import org.jclouds.location.suppliers.implicit.FirstZone; import org.jclouds.openstack.keystone.v2_0.AuthenticationApi; import org.jclouds.openstack.keystone.v2_0.AuthenticationAsyncApi; 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.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.LocationIdToURIFromAccessForTypeAndVersion; import org.jclouds.openstack.keystone.v2_0.suppliers.RegionIdToAdminURIFromAccessForTypeAndVersion; import org.jclouds.openstack.keystone.v2_0.suppliers.RegionIdToAdminURISupplier; import org.jclouds.openstack.keystone.v2_0.suppliers.RegionIdToURIFromAccessForTypeAndVersion; import org.jclouds.openstack.keystone.v2_0.suppliers.ZoneIdToURIFromAccessForTypeAndVersion; import org.jclouds.rest.annotations.ApiVersion; +import org.jclouds.rest.config.RestClientModule; import com.google.common.base.Function; import com.google.common.base.Supplier; @@ -75,14 +80,55 @@ import com.google.inject.assistedinject.FactoryModuleBuilder; * @author Adrian Cole */ public class KeystoneAuthenticationModule extends AbstractModule { - + + /** + * For global services who have no regions, such as DNS. To use, do the following + *
    + *
  1. add this module to your {@link org.jclouds.apis.ApiMetadata#getDefaultModules()}
  2. + *
  3. create a service-specific annotation, such as {@code @CloudDNS}, and make sure that has the meta-annotation + * {@link javax.inject.Qualifier}
  4. + *
  5. add the above annotation to any {@link AsyncApi} classes by placing it on the type. ex. + * {@code @Endpoint(CloudDNS.class)}
  6. + *
  7. add the following to your {@link RestClientModule}
  8. + * + *
    +    * bind(new TypeLiteral<Supplier<URI>>() {
    +    * }).annotatedWith(CloudDNS.class).to(new TypeLiteral<Supplier<URI>>() {
    +    * });
    +    * 
    + */ + public static class ProviderModule extends AbstractModule { + @Override + protected void configure() { + install(new FactoryModuleBuilder().build(LocationIdToURIFromAccessForTypeAndVersion.Factory.class)); + } + + @Provides + @Singleton + protected Supplier provideZoneIdToURISupplierForApiVersion( + @Named(KeystoneProperties.SERVICE_TYPE) String serviceType, @ApiVersion String apiVersion, + LocationIdToURIFromAccessForTypeAndVersion.Factory factory) { + return getLastValueInMap(factory.createForApiTypeAndVersion(serviceType, apiVersion)); + } + + @Provides + @Singleton + Function provideProvider(@Provider final String provider) { + return new Function() { + public String apply(Endpoint in) { + return provider; + } + }; + } + } + public static class RegionModule extends AbstractModule { @Override protected void configure() { install(new FactoryModuleBuilder().implement(RegionIdToURISupplier.class, - RegionIdToURIFromAccessForTypeAndVersion.class).build(RegionIdToURISupplier.Factory.class)); + RegionIdToURIFromAccessForTypeAndVersion.class).build(RegionIdToURISupplier.Factory.class)); install(new FactoryModuleBuilder().implement(RegionIdToAdminURISupplier.class, - RegionIdToAdminURIFromAccessForTypeAndVersion.class).build(RegionIdToAdminURISupplier.Factory.class)); + RegionIdToAdminURIFromAccessForTypeAndVersion.class).build(RegionIdToAdminURISupplier.Factory.class)); // dynamically build the region list as opposed to from properties bind(RegionIdsSupplier.class).to(RegionIdsFromRegionIdToURIKeySet.class); bind(ImplicitLocationSupplier.class).to(FirstRegion.class).in(Scopes.SINGLETON); @@ -94,8 +140,8 @@ public class KeystoneAuthenticationModule extends AbstractModule { @Provides @Singleton protected RegionIdToURISupplier provideRegionIdToURISupplierForApiVersion( - @Named(KeystoneProperties.SERVICE_TYPE) String serviceType, @ApiVersion String apiVersion, - RegionIdToURISupplier.Factory factory) { + @Named(KeystoneProperties.SERVICE_TYPE) String serviceType, @ApiVersion String apiVersion, + RegionIdToURISupplier.Factory factory) { return factory.createForApiTypeAndVersion(serviceType, apiVersion); } @@ -105,8 +151,8 @@ public class KeystoneAuthenticationModule extends AbstractModule { @Provides @Singleton protected RegionIdToAdminURISupplier provideRegionIdToAdminURISupplierForApiVersion( - @Named(KeystoneProperties.SERVICE_TYPE) String serviceType, @ApiVersion String apiVersion, - RegionIdToAdminURISupplier.Factory factory) { + @Named(KeystoneProperties.SERVICE_TYPE) String serviceType, @ApiVersion String apiVersion, + RegionIdToAdminURISupplier.Factory factory) { return factory.createForApiTypeAndVersion(serviceType, apiVersion); } @@ -116,7 +162,7 @@ public class KeystoneAuthenticationModule extends AbstractModule { @Override protected void configure() { install(new FactoryModuleBuilder().implement(ZoneIdToURISupplier.class, - ZoneIdToURIFromAccessForTypeAndVersion.class).build(ZoneIdToURISupplier.Factory.class)); + ZoneIdToURIFromAccessForTypeAndVersion.class).build(ZoneIdToURISupplier.Factory.class)); // dynamically build the zone list as opposed to from properties bind(ZoneIdsSupplier.class).to(ZoneIdsFromZoneIdToURIKeySet.class); bind(ImplicitLocationSupplier.class).to(FirstZone.class).in(Scopes.SINGLETON); @@ -128,8 +174,8 @@ public class KeystoneAuthenticationModule extends AbstractModule { @Provides @Singleton protected ZoneIdToURISupplier provideZoneIdToURISupplierForApiVersion( - @Named(KeystoneProperties.SERVICE_TYPE) String serviceType, @ApiVersion String apiVersion, - ZoneIdToURISupplier.Factory factory) { + @Named(KeystoneProperties.SERVICE_TYPE) String serviceType, @ApiVersion String apiVersion, + ZoneIdToURISupplier.Factory factory) { return factory.createForApiTypeAndVersion(serviceType, apiVersion); } @@ -153,7 +199,7 @@ public class KeystoneAuthenticationModule extends AbstractModule { @Singleton @Authentication protected Supplier provideAuthenticationTokenCache(final Supplier supplier) - throws InterruptedException, ExecutionException, TimeoutException { + throws InterruptedException, ExecutionException, TimeoutException { return new Supplier() { public String get() { return supplier.get().getToken().getId(); @@ -173,10 +219,10 @@ public class KeystoneAuthenticationModule extends AbstractModule { @Provides @Singleton protected Function authenticationMethodForCredentialType( - @Named(KeystoneProperties.CREDENTIAL_TYPE) String credentialType, - Map> authenticationMethods) { + @Named(KeystoneProperties.CREDENTIAL_TYPE) String credentialType, + Map> authenticationMethods) { checkArgument(authenticationMethods.containsKey(credentialType), "credential type %s not in supported list: %s", - credentialType, authenticationMethods.keySet()); + credentialType, authenticationMethods.keySet()); return authenticationMethods.get(credentialType); } diff --git a/apis/openstack-keystone/src/main/java/org/jclouds/openstack/v2_0/domain/Limit.java b/apis/openstack-keystone/src/main/java/org/jclouds/openstack/v2_0/domain/Limit.java new file mode 100644 index 0000000000..16d852f4d1 --- /dev/null +++ b/apis/openstack-keystone/src/main/java/org/jclouds/openstack/v2_0/domain/Limit.java @@ -0,0 +1,96 @@ +/** + * 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.v2_0.domain; + +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 java.beans.ConstructorProperties; +import java.util.Date; + +import javax.inject.Named; + +import org.jclouds.javax.annotation.Nullable; + +import com.google.common.base.Objects; +import com.google.common.base.Optional; + +/** + * @author Everett Toews + */ +public final class Limit { + + private final String verb; + private final String unit; + private final int value; + private final Optional remaining; + @Named("next-available") + private final Optional nextAvailable; + + @ConstructorProperties({ "verb", "unit", "value", "remaining", "next-available" }) + private Limit(String verb, String unit, int value, @Nullable Integer remaining, @Nullable Date nextAvailable) { + this.verb = checkNotNull(verb, "verb"); + this.unit = checkNotNull(unit, "unit", unit); + this.value = value; + this.remaining = Optional.fromNullable(remaining); + this.nextAvailable = Optional.fromNullable(nextAvailable); + } + + public String getVerb() { + return verb; + } + + public String getUnit() { + return unit; + } + + public int getValue() { + return value; + } + + public Optional getRemaining() { + return remaining; + } + + public Optional getNextAvailable() { + return nextAvailable; + } + + @Override + public int hashCode() { + return Objects.hashCode(verb, unit); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null || getClass() != obj.getClass()) + return false; + Limit that = Limit.class.cast(obj); + return equal(this.verb, that.verb) && equal(this.unit, that.unit); + } + + @Override + public String toString() { + return toStringHelper(this).omitNullValues().add("verb", verb).add("unit", unit).add("value", value) + .add("remaining", remaining.orNull()).add("nextAvailable", nextAvailable.orNull()).toString(); + } +} diff --git a/apis/openstack-keystone/src/main/java/org/jclouds/openstack/v2_0/domain/Limits.java b/apis/openstack-keystone/src/main/java/org/jclouds/openstack/v2_0/domain/Limits.java new file mode 100644 index 0000000000..23f47472c6 --- /dev/null +++ b/apis/openstack-keystone/src/main/java/org/jclouds/openstack/v2_0/domain/Limits.java @@ -0,0 +1,75 @@ +/** + * 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.v2_0.domain; + +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 java.beans.ConstructorProperties; +import java.util.Map; + +import javax.inject.Named; + +import com.google.common.base.Objects; + +/** + * @author Everett Toews + */ +public final class Limits { + + @Named("rate") + private final Iterable rateLimits; + @Named("absolute") + private final Map absoluteLimits; + + @ConstructorProperties({ "rate", "absolute" }) + private Limits(Iterable rateLimits, Map absoluteLimits) { + this.rateLimits = checkNotNull(rateLimits, "rateLimits"); + this.absoluteLimits = checkNotNull(absoluteLimits, "absoluteLimits"); + } + + public Iterable getRateLimits() { + return rateLimits; + } + + public Map getAbsoluteLimits() { + return absoluteLimits; + } + + @Override + public int hashCode() { + return Objects.hashCode(rateLimits, absoluteLimits); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null || getClass() != obj.getClass()) + return false; + Limits that = Limits.class.cast(obj); + return equal(this.rateLimits, that.rateLimits) && equal(this.absoluteLimits, that.absoluteLimits); + } + + @Override + public String toString() { + return toStringHelper(this).add("rateLimits", rateLimits).add("absoluteLimits", absoluteLimits).toString(); + } +} diff --git a/apis/openstack-keystone/src/main/java/org/jclouds/openstack/v2_0/domain/RateLimit.java b/apis/openstack-keystone/src/main/java/org/jclouds/openstack/v2_0/domain/RateLimit.java new file mode 100644 index 0000000000..5a3ef1c657 --- /dev/null +++ b/apis/openstack-keystone/src/main/java/org/jclouds/openstack/v2_0/domain/RateLimit.java @@ -0,0 +1,79 @@ +/** + * 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.v2_0.domain; + +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 java.beans.ConstructorProperties; + +import javax.inject.Named; + +import com.google.common.base.Objects; + +/** + * @author Everett Toews + */ +public final class RateLimit { + + private final String uri; + private final String regex; + @Named("limit") + private final Iterable limits; + + @ConstructorProperties({ "uri", "regex", "limit" }) + private RateLimit(String uri, String regex, Iterable limits) { + this.uri = checkNotNull(uri, "uri"); + this.regex = checkNotNull(regex, "regex"); + this.limits = checkNotNull(limits, "limit"); + } + + public String getUri() { + return uri; + } + + public String getRegex() { + return regex; + } + + public Iterable getLimits() { + return limits; + } + + @Override + public int hashCode() { + return Objects.hashCode(uri); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null || getClass() != obj.getClass()) + return false; + RateLimit that = RateLimit.class.cast(obj); + return equal(this.uri, that.uri); + } + + @Override + public String toString() { + return toStringHelper(this).add("uri", uri).add("regex", regex).add("limits", limits).toString(); + } +} diff --git a/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v2_0/KeystoneApiExpectTest.java b/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v2_0/KeystoneApiExpectTest.java index a1e6b2fd43..37f23372a7 100644 --- a/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v2_0/KeystoneApiExpectTest.java +++ b/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v2_0/KeystoneApiExpectTest.java @@ -38,7 +38,7 @@ public class KeystoneApiExpectTest extends BaseKeystoneRestApiExpectTest { + + @Retention(RUNTIME) + @Target(TYPE) + @Qualifier + static @interface DNS { + } + + @ConfiguresRestClient + public static class DNSRestClientModule extends RestClientModule { + @Override + public void configure() { + bind(new TypeLiteral>() {}).annotatedWith(DNS.class).to(new TypeLiteral>() {}); + bind(DateAdapter.class).to(Iso8601DateAdapter.class); + super.configure(); + } + } + + static interface DNSApi { + boolean zoneExists(@PathParam("zoneName") String zoneName); + } + + @org.jclouds.rest.annotations.Endpoint(DNS.class) + static interface DNSAsyncApi { + @HEAD + @Path("/zones/{zoneName}") + @Fallback(FalseOnNotFoundOr404.class) + public ListenableFuture zoneExists(@PathParam("zoneName") String zoneName); + } + + public void testDNSEndpointApplied() { + KeystoneAuth keystoneAuth = new KeystoneAuth(); + + DNSApi api = requestsSendResponses( + keystoneAuth.getKeystoneAuthWithUsernameAndPassword(), + keystoneAuth.getResponseWithKeystoneAccess(), + HttpRequest.builder().method("HEAD").endpoint("http://172.16.0.1:8776/v1/3456/zones/foo.com").build(), + HttpResponse.builder().statusCode(200).build()); + assertTrue(api.zoneExists("foo.com")); + } + + private static class DNSApiMetadata extends BaseRestApiMetadata { + + @Override + public Builder toBuilder() { + return new Builder().fromApiMetadata(this); + } + + public DNSApiMetadata() { + this(new Builder()); + } + + protected DNSApiMetadata(Builder builder) { + super(builder); + } + + public static Properties defaultProperties() { + Properties properties = BaseRestApiMetadata.defaultProperties(); + properties.setProperty(SERVICE_TYPE, "dns"); + properties.setProperty(CREDENTIAL_TYPE, CredentialTypes.PASSWORD_CREDENTIALS); + return properties; + } + + public static class Builder extends BaseRestApiMetadata.Builder { + + protected Builder() { + super(DNSApi.class, DNSAsyncApi.class); + id("dns") + .name("DNS API") + .identityName("${tenantName}:${userName} or ${userName}, if your keystone supports a default tenant") + .credentialName("${password}") + .endpointName("Keystone base url ending in /v2.0/") + .documentation(URI.create("http://dns")) + .version("1.0") + .defaultEndpoint("http://localhost:5000/v2.0/") + .defaultProperties(DNSApiMetadata.defaultProperties()) + .defaultModules( + ImmutableSet.> builder() + .add(KeystoneAuthenticationModule.class) + .add(ProviderModule.class) + .add(DNSRestClientModule.class) + .build()); + } + + @Override + public DNSApiMetadata build() { + return new DNSApiMetadata(this); + } + + @Override + protected Builder self() { + return this; + } + } + } + + @Override + public ApiMetadata createApiMetadata() { + return new DNSApiMetadata(); + } + + public static class KeystoneAuth extends BaseKeystoneRestApiExpectTest { + public HttpRequest getKeystoneAuthWithUsernameAndPassword() { + return keystoneAuthWithUsernameAndPassword; + } + + public HttpResponse getResponseWithKeystoneAccess() { + return responseWithKeystoneAccess; + } + } +} \ No newline at end of file diff --git a/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v2_0/features/ServiceApiExpectTest.java b/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v2_0/features/ServiceApiExpectTest.java index f5e63a22af..0ac255c649 100644 --- a/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v2_0/features/ServiceApiExpectTest.java +++ b/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v2_0/features/ServiceApiExpectTest.java @@ -44,7 +44,7 @@ public class ServiceApiExpectTest extends BaseKeystoneRestApiExpectTest extends BaseRestApiExpectTest { + protected HttpRequest keystoneAuthWithUsernameAndPasswordAndTenantName; protected HttpRequest keystoneAuthWithUsernameAndPassword; protected HttpRequest keystoneAuthWithAccessKeyAndSecretKey; protected String authToken; @@ -47,10 +48,12 @@ public class BaseKeystoneRestApiExpectTest extends BaseRestApiExpectTest { public BaseKeystoneRestApiExpectTest() { provider = "openstack-keystone"; - keystoneAuthWithUsernameAndPassword = KeystoneFixture.INSTANCE.initialAuthWithUsernameAndPasswordAndTenantName(identity, - credential); - keystoneAuthWithAccessKeyAndSecretKey = KeystoneFixture.INSTANCE.initialAuthWithAccessKeyAndSecretKeyAndTenantName(identity, - credential); + keystoneAuthWithUsernameAndPasswordAndTenantName = KeystoneFixture.INSTANCE + .initialAuthWithUsernameAndPasswordAndTenantName(identity, credential); + keystoneAuthWithUsernameAndPassword = KeystoneFixture.INSTANCE + .initialAuthWithUsernameAndPassword(identity, credential); + keystoneAuthWithAccessKeyAndSecretKey = KeystoneFixture.INSTANCE + .initialAuthWithAccessKeyAndSecretKeyAndTenantName(identity, credential); authToken = KeystoneFixture.INSTANCE.getAuthToken(); responseWithKeystoneAccess = KeystoneFixture.INSTANCE.responseWithAccess(); @@ -59,10 +62,8 @@ public class BaseKeystoneRestApiExpectTest extends BaseRestApiExpectTest { } protected HttpRequest.Builder authenticatedGET() { - return HttpRequest.builder() - .method("GET") - .addHeader("Accept", MediaType.APPLICATION_JSON) - .addHeader("X-Auth-Token", authToken); + return HttpRequest.builder().method("GET").addHeader("Accept", MediaType.APPLICATION_JSON) + .addHeader("X-Auth-Token", authToken); } @Override @@ -75,7 +76,7 @@ public class BaseKeystoneRestApiExpectTest extends BaseRestApiExpectTest { @Override protected HttpRequestComparisonType compareHttpRequestAsType(HttpRequest input) { return Objects.equal("HEAD", input.getMethod()) ? HttpRequestComparisonType.DEFAULT - : HttpRequestComparisonType.JSON; + : HttpRequestComparisonType.JSON; } @Override diff --git a/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v2_0/parse/ParseAccessTest.java b/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v2_0/parse/ParseAccessTest.java index b6d2f0af29..d337e96c85 100644 --- a/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v2_0/parse/ParseAccessTest.java +++ b/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v2_0/parse/ParseAccessTest.java @@ -115,7 +115,12 @@ public class ParseAccessTest extends BaseItemParserTest { .publicURL("http://172.16.0.1:8776/v1/50cdb4c60374463198695d9f798fa34d") .internalURL("http://10.0.2.15:8776/v1/50cdb4c60374463198695d9f798fa34d") .adminURL("http://10.0.2.15:8776/v1/50cdb4c60374463198695d9f798fa34d") - .region("RegionOne").build()).build()).build(); + .region("RegionOne").build()).build()) + .service(Service.builder().name("dns").type("dns") + .endpoint(Endpoint.builder() + .publicURL("http://172.16.0.1:8776/v1/3456") + .tenantId("3456") + .build()).build()).build(); } } diff --git a/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v2_0/parse/ParseRackspaceAccessTest.java b/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v2_0/parse/ParseRackspaceAccessTest.java index c18fa27e70..6474127042 100644 --- a/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v2_0/parse/ParseRackspaceAccessTest.java +++ b/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v2_0/parse/ParseRackspaceAccessTest.java @@ -112,7 +112,7 @@ public class ParseRackspaceAccessTest extends BaseItemParserTest { .endpoint(Endpoint.builder() .tenantId("40806637803162") .publicURL("https://monitoring.api.rackspacecloud.com/v1.0/40806637803162").build()).build()) - .service(Service.builder().name("cloudDNS").type("dnsextension:dns") + .service(Service.builder().name("cloudDNS").type("rax:dns") .endpoint(Endpoint.builder() .tenantId("40806637803162") .publicURL("https://dns.api.rackspacecloud.com/v1.0/40806637803162").build()).build()) diff --git a/apis/openstack-keystone/src/test/resources/keystoneAuthResponse.json b/apis/openstack-keystone/src/test/resources/keystoneAuthResponse.json index a35f9f90a8..3798ff59a0 100644 --- a/apis/openstack-keystone/src/test/resources/keystoneAuthResponse.json +++ b/apis/openstack-keystone/src/test/resources/keystoneAuthResponse.json @@ -138,6 +138,16 @@ } ], "endpoints_links": [] + }, + { + "type": "dns", + "name": "dns", + "endpoints": [ + { + "publicURL": "http://172.16.0.1:8776/v1/3456", + "tenantId": "3456" + } + ] } ] } diff --git a/apis/openstack-keystone/src/test/resources/raxAuth.json b/apis/openstack-keystone/src/test/resources/raxAuth.json index 1044effa3f..aeb96dd5c6 100644 --- a/apis/openstack-keystone/src/test/resources/raxAuth.json +++ b/apis/openstack-keystone/src/test/resources/raxAuth.json @@ -87,7 +87,7 @@ "publicURL": "https:\/\/dns.api.rackspacecloud.com\/v1.0\/40806637803162" }], "name": "cloudDNS", - "type": "dnsextension:dns" + "type": "rax:dns" }, { "endpoints": [{ "region": "DFW", diff --git a/apis/rackspace-cloudidentity/src/main/java/org/jclouds/rackspace/cloudidentity/v2_0/ServiceType.java b/apis/rackspace-cloudidentity/src/main/java/org/jclouds/rackspace/cloudidentity/v2_0/ServiceType.java index b79d631bad..1b91aa6f48 100644 --- a/apis/rackspace-cloudidentity/src/main/java/org/jclouds/rackspace/cloudidentity/v2_0/ServiceType.java +++ b/apis/rackspace-cloudidentity/src/main/java/org/jclouds/rackspace/cloudidentity/v2_0/ServiceType.java @@ -30,4 +30,9 @@ public interface ServiceType { * Cloud Load Balancers */ public static final String LOAD_BALANCERS = "rax:load-balancer"; + + /** + * Cloud Load DNS + */ + public static final String DNS = "rax:dns"; } diff --git a/core/src/main/java/org/jclouds/rest/internal/RestAnnotationProcessor.java b/core/src/main/java/org/jclouds/rest/internal/RestAnnotationProcessor.java index f5d629724b..05b3677101 100644 --- a/core/src/main/java/org/jclouds/rest/internal/RestAnnotationProcessor.java +++ b/core/src/main/java/org/jclouds/rest/internal/RestAnnotationProcessor.java @@ -818,8 +818,8 @@ public class RestAnnotationProcessor implements Function + + + 4.0.0 + + org.jclouds + jclouds-project + 1.6.0-SNAPSHOT + ../../project/pom.xml + + org.jclouds.labs + rackspace-clouddns + jclouds rackspace clouddns api + jclouds components for Rackspace Cloud DNS + bundle + + + https://identity.api.rackspacecloud.com/v2.0/ + 1.0 + + ${test.rackspace.identity} + ${test.rackspace.credential} + + org.jclouds.rackspace.clouddns.v1*;version="${project.version}" + + org.jclouds.rest.internal;version="${project.version}", + org.jclouds*;version="${project.version}", + * + + + + + + org.jclouds + jclouds-core + ${project.version} + + + org.jclouds.api + openstack-keystone + ${project.version} + + + org.jclouds.api + rackspace-cloudidentity + ${project.version} + + + org.jclouds + jclouds-core + ${project.version} + test-jar + test + + + org.jclouds.api + openstack-keystone + ${project.version} + test-jar + test + + + org.jclouds.api + rackspace-cloudidentity + ${project.version} + test-jar + test + + + org.jclouds.driver + jclouds-slf4j + ${project.version} + test + + + ch.qos.logback + logback-classic + test + + + + + + live + + + + org.apache.maven.plugins + maven-surefire-plugin + + + integration + integration-test + + test + + + + 1 + + ${test.rackspace-clouddns.endpoint} + ${test.rackspace-clouddns.api-version} + ${test.rackspace-clouddns.build-version} + ${test.rackspace-clouddns.identity} + ${test.rackspace-clouddns.credential} + + + + + + + + + + + diff --git a/labs/rackspace-clouddns/src/main/java/org/jclouds/rackspace/clouddns/v1/CloudDNSApi.java b/labs/rackspace-clouddns/src/main/java/org/jclouds/rackspace/clouddns/v1/CloudDNSApi.java new file mode 100644 index 0000000000..c347ffe7e2 --- /dev/null +++ b/labs/rackspace-clouddns/src/main/java/org/jclouds/rackspace/clouddns/v1/CloudDNSApi.java @@ -0,0 +1,37 @@ +/** + * 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.rackspace.clouddns.v1; + +import org.jclouds.rackspace.clouddns.v1.features.LimitApi; +import org.jclouds.rest.annotations.Delegate; + +/** + * Provides access to the Rackspace Cloud DNS API. + *

    + * See Cloud DNS Developer Guide + * @see CloudDNSAsyncApi + * @author Everett Toews + */ +public interface CloudDNSApi { + /** + * Provides synchronous access to Limit features. + */ + @Delegate + LimitApi getLimitApi(); +} diff --git a/labs/rackspace-clouddns/src/main/java/org/jclouds/rackspace/clouddns/v1/CloudDNSApiMetadata.java b/labs/rackspace-clouddns/src/main/java/org/jclouds/rackspace/clouddns/v1/CloudDNSApiMetadata.java new file mode 100644 index 0000000000..e2c0f6f5aa --- /dev/null +++ b/labs/rackspace-clouddns/src/main/java/org/jclouds/rackspace/clouddns/v1/CloudDNSApiMetadata.java @@ -0,0 +1,101 @@ +/** + * 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.rackspace.clouddns.v1; + +import static org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties.CREDENTIAL_TYPE; +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.KeystoneAuthenticationModule.ProviderModule; +import org.jclouds.rackspace.clouddns.v1.config.CloudDNSRestClientModule; +import org.jclouds.rackspace.cloudidentity.v2_0.ServiceType; +import org.jclouds.rackspace.cloudidentity.v2_0.config.CloudIdentityAuthenticationModule; +import org.jclouds.rackspace.cloudidentity.v2_0.config.CloudIdentityCredentialTypes; +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 ApiMetadata} for DynECT 1.0 API + * + * @author Everett Toews + */ +public class CloudDNSApiMetadata extends BaseRestApiMetadata { + + public static final TypeToken> CONTEXT_TOKEN = new TypeToken>() { + private static final long serialVersionUID = 1L; + }; + + @Override + public Builder toBuilder() { + return new Builder().fromApiMetadata(this); + } + + public CloudDNSApiMetadata() { + this(new Builder()); + } + + protected CloudDNSApiMetadata(Builder builder) { + super(builder); + } + + public static Properties defaultProperties() { + Properties properties = BaseRestApiMetadata.defaultProperties(); + properties.setProperty(SERVICE_TYPE, ServiceType.DNS); + properties.setProperty(CREDENTIAL_TYPE, CloudIdentityCredentialTypes.API_KEY_CREDENTIALS); + return properties; + } + + public static class Builder extends BaseRestApiMetadata.Builder { + + protected Builder() { + super(CloudDNSApi.class, CloudDNSAsyncApi.class); + id("rackspace-clouddns") + .name("Rackspace Cloud DNS API") + .identityName("Username") + .credentialName("API Key") + .documentation(URI.create("http://docs.rackspace.com/cdns/api/v1.0/cdns-devguide/content/index.html")) + .version("1.0") + .defaultEndpoint("https://identity.api.rackspacecloud.com/v2.0/") + .defaultProperties(CloudDNSApiMetadata.defaultProperties()) + .defaultModules( + ImmutableSet.> builder() + .add(CloudIdentityAuthenticationModule.class) + .add(ProviderModule.class) + .add(CloudDNSRestClientModule.class) + .build()); + } + + @Override + public CloudDNSApiMetadata build() { + return new CloudDNSApiMetadata(this); + } + + @Override + protected Builder self() { + return this; + } + } +} diff --git a/labs/rackspace-clouddns/src/main/java/org/jclouds/rackspace/clouddns/v1/CloudDNSAsyncApi.java b/labs/rackspace-clouddns/src/main/java/org/jclouds/rackspace/clouddns/v1/CloudDNSAsyncApi.java new file mode 100644 index 0000000000..0992a7a984 --- /dev/null +++ b/labs/rackspace-clouddns/src/main/java/org/jclouds/rackspace/clouddns/v1/CloudDNSAsyncApi.java @@ -0,0 +1,37 @@ +/** + * 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.rackspace.clouddns.v1; + +import org.jclouds.rackspace.clouddns.v1.features.LimitAsyncApi; +import org.jclouds.rest.annotations.Delegate; + +/** + * Provides access to the Rackspace Cloud DNS API. + *

    + * + * @see CloudDNSApi + * @author Everett Toews + */ +public interface CloudDNSAsyncApi { + /** + * Provides asynchronous access to Limit features. + */ + @Delegate + LimitAsyncApi getLimitApi(); +} diff --git a/labs/rackspace-clouddns/src/main/java/org/jclouds/rackspace/clouddns/v1/config/CloudDNS.java b/labs/rackspace-clouddns/src/main/java/org/jclouds/rackspace/clouddns/v1/config/CloudDNS.java new file mode 100644 index 0000000000..764e0c9aa6 --- /dev/null +++ b/labs/rackspace-clouddns/src/main/java/org/jclouds/rackspace/clouddns/v1/config/CloudDNS.java @@ -0,0 +1,38 @@ +/** + * 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.rackspace.clouddns.v1.config; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import javax.inject.Qualifier; + +/** + * Represents a component related to Rackspace Cloud DNS. + * + * @author Everett Toews + */ +@Retention(value = RetentionPolicy.RUNTIME) +@Target(value = { ElementType.TYPE, ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD }) +@Qualifier +public @interface CloudDNS { + +} diff --git a/labs/rackspace-clouddns/src/main/java/org/jclouds/rackspace/clouddns/v1/config/CloudDNSRestClientModule.java b/labs/rackspace-clouddns/src/main/java/org/jclouds/rackspace/clouddns/v1/config/CloudDNSRestClientModule.java new file mode 100644 index 0000000000..1e99a7c29b --- /dev/null +++ b/labs/rackspace-clouddns/src/main/java/org/jclouds/rackspace/clouddns/v1/config/CloudDNSRestClientModule.java @@ -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.rackspace.clouddns.v1.config; + +import java.net.URI; +import java.util.Map; + +import org.jclouds.json.config.GsonModule.DateAdapter; +import org.jclouds.json.config.GsonModule.Iso8601DateAdapter; +import org.jclouds.rackspace.clouddns.v1.CloudDNSApi; +import org.jclouds.rackspace.clouddns.v1.CloudDNSAsyncApi; +import org.jclouds.rackspace.clouddns.v1.features.LimitApi; +import org.jclouds.rackspace.clouddns.v1.features.LimitAsyncApi; +import org.jclouds.rest.ConfiguresRestClient; +import org.jclouds.rest.config.RestClientModule; + +import com.google.common.base.Supplier; +import com.google.common.collect.ImmutableMap; +import com.google.inject.TypeLiteral; + +/** + * Configures Rackspace Cloud DNS. + * + * @author Everett Toews + */ +@ConfiguresRestClient +public class CloudDNSRestClientModule extends RestClientModule { + + public static final Map, Class> DELEGATE_MAP = ImmutableMap., Class> builder() + .put(LimitApi.class, LimitAsyncApi.class) + .build(); + + public CloudDNSRestClientModule() { + super(DELEGATE_MAP); + } + + @Override + protected void configure() { + bind(new TypeLiteral>() {}).annotatedWith(CloudDNS.class).to(new TypeLiteral>() {}); + bind(DateAdapter.class).to(Iso8601DateAdapter.class); + super.configure(); + } +} diff --git a/labs/rackspace-clouddns/src/main/java/org/jclouds/rackspace/clouddns/v1/features/LimitApi.java b/labs/rackspace-clouddns/src/main/java/org/jclouds/rackspace/clouddns/v1/features/LimitApi.java new file mode 100644 index 0000000000..c749dc10fa --- /dev/null +++ b/labs/rackspace-clouddns/src/main/java/org/jclouds/rackspace/clouddns/v1/features/LimitApi.java @@ -0,0 +1,44 @@ +/** + * 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, String 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.rackspace.clouddns.v1.features; + +import org.jclouds.openstack.keystone.v2_0.filters.AuthenticateRequest; +import org.jclouds.openstack.v2_0.domain.Limits; +import org.jclouds.rest.annotations.RequestFilters; + +/** + * All accounts, by default, have a preconfigured set of thresholds (or limits) to manage capacity and prevent abuse + * of the system. The system recognizes two kinds of limits: rate limits and absolute limits. Rate limits are + * thresholds that are reset after a certain amount of time passes. Absolute limits are fixed. + * + * @see LimitApi + * @author Everett Toews + */ +@RequestFilters(AuthenticateRequest.class) +public interface LimitApi { + /** + * Provides a list of all applicable limits. + */ + Limits list(); + + /** + * All applicable limit types. + */ + Iterable listTypes(); +} diff --git a/labs/rackspace-clouddns/src/main/java/org/jclouds/rackspace/clouddns/v1/features/LimitAsyncApi.java b/labs/rackspace-clouddns/src/main/java/org/jclouds/rackspace/clouddns/v1/features/LimitAsyncApi.java new file mode 100644 index 0000000000..210466db0c --- /dev/null +++ b/labs/rackspace-clouddns/src/main/java/org/jclouds/rackspace/clouddns/v1/features/LimitAsyncApi.java @@ -0,0 +1,67 @@ +/** + * 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, String 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.rackspace.clouddns.v1.features; + +import javax.inject.Named; +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.core.MediaType; + +import org.jclouds.Fallbacks.EmptyListOnNotFoundOr404; +import org.jclouds.Fallbacks.NullOnNotFoundOr404; +import org.jclouds.openstack.keystone.v2_0.filters.AuthenticateRequest; +import org.jclouds.openstack.v2_0.domain.Limits; +import org.jclouds.rackspace.clouddns.v1.config.CloudDNS; +import org.jclouds.rest.annotations.Endpoint; +import org.jclouds.rest.annotations.Fallback; +import org.jclouds.rest.annotations.RequestFilters; +import org.jclouds.rest.annotations.SelectJson; + +import com.google.common.util.concurrent.ListenableFuture; + +/** + * @see LimitAsyncApi + * @author Everett Toews + */ +@Endpoint(CloudDNS.class) +@RequestFilters(AuthenticateRequest.class) +public interface LimitAsyncApi { + /** + * @see LimitApi#list() + */ + @Named("limits:list") + @GET + @Consumes(MediaType.APPLICATION_JSON) + @Fallback(NullOnNotFoundOr404.class) + @SelectJson("limits") + @Path("/limits") + ListenableFuture list(); + + /** + * @see LimitApi#listTypes() + */ + @Named("limits:list") + @GET + @Consumes(MediaType.APPLICATION_JSON) + @Fallback(EmptyListOnNotFoundOr404.class) + @SelectJson("limitTypes") + @Path("/limits/types") + ListenableFuture> listTypes(); +} diff --git a/labs/rackspace-clouddns/src/main/resources/META-INF/services/org.jclouds.apis.ApiMetadata b/labs/rackspace-clouddns/src/main/resources/META-INF/services/org.jclouds.apis.ApiMetadata new file mode 100644 index 0000000000..eae6b81b84 --- /dev/null +++ b/labs/rackspace-clouddns/src/main/resources/META-INF/services/org.jclouds.apis.ApiMetadata @@ -0,0 +1 @@ +org.jclouds.rackspace.clouddns.v1.CloudDNSApiMetadata \ No newline at end of file diff --git a/labs/rackspace-clouddns/src/test/java/org/jclouds/rackspace/clouddns/v1/features/LimitApiExpectTest.java b/labs/rackspace-clouddns/src/test/java/org/jclouds/rackspace/clouddns/v1/features/LimitApiExpectTest.java new file mode 100644 index 0000000000..1ff83f61be --- /dev/null +++ b/labs/rackspace-clouddns/src/test/java/org/jclouds/rackspace/clouddns/v1/features/LimitApiExpectTest.java @@ -0,0 +1,83 @@ +/** + * 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.rackspace.clouddns.v1.features; + +import static org.testng.Assert.assertEquals; + +import java.net.URI; + +import org.jclouds.http.HttpResponse; +import org.jclouds.openstack.v2_0.domain.Limits; +import org.jclouds.openstack.v2_0.domain.RateLimit; +import org.jclouds.rackspace.clouddns.v1.CloudDNSApi; +import org.jclouds.rackspace.clouddns.v1.internal.BaseCloudDNSApiExpectTest; +import org.testng.annotations.Test; + +import com.google.common.base.Predicate; +import com.google.common.collect.Iterables; + +/** + * @author Everett Toews + */ +@Test(groups = "unit") +public class LimitApiExpectTest extends BaseCloudDNSApiExpectTest { + public void testListLimits() { + URI endpoint = URI.create("https://dns.api.rackspacecloud.com/v1.0/123123/limits"); + LimitApi api = requestsSendResponses( + rackspaceAuthWithUsernameAndApiKey, + responseWithAccess, + authenticatedGET().endpoint(endpoint).build(), + HttpResponse.builder().statusCode(200).payload(payloadFromResource("/limit-list.json")).build() + ).getLimitApi(); + + Limits limits = api.list(); + assertEquals(limits.getAbsoluteLimits().get("records per domain"), Integer.valueOf(500)); + assertEquals(limits.getAbsoluteLimits().get("domains"), Integer.valueOf(500)); + assertEquals(Iterables.size(limits.getRateLimits()), 2); + + RateLimit statusRateLimit = Iterables.tryFind(limits.getRateLimits(), isStatusRateLimit()).orNull(); + assertEquals(statusRateLimit.getRegex(), ".*/v\\d+\\.\\d+/(\\d+/status).*"); + assertEquals(Iterables.get(statusRateLimit.getLimits(), 0).getVerb(), "GET"); + assertEquals(Iterables.get(statusRateLimit.getLimits(), 0).getValue(), 5); + assertEquals(Iterables.get(statusRateLimit.getLimits(), 0).getRemaining().get(), Integer.valueOf(5)); + assertEquals(Iterables.get(statusRateLimit.getLimits(), 0).getUnit(), "SECOND"); + } + + public void testListLimitTypes() { + URI endpoint = URI.create("https://dns.api.rackspacecloud.com/v1.0/123123/limits/types"); + LimitApi api = requestsSendResponses( + rackspaceAuthWithUsernameAndApiKey, + responseWithAccess, + authenticatedGET().endpoint(endpoint).build(), + HttpResponse.builder().statusCode(200).payload(payloadFromResource("/limit-types-list.json")).build() + ).getLimitApi(); + + Iterable limitTypes = api.listTypes(); + assertEquals(Iterables.size(limitTypes), 3); + } + + private static Predicate isStatusRateLimit() { + return new Predicate() { + @Override + public boolean apply(RateLimit rateLimit) { + return rateLimit.getUri().contains("status"); + } + }; + } +} diff --git a/labs/rackspace-clouddns/src/test/java/org/jclouds/rackspace/clouddns/v1/features/LimitApiLiveTest.java b/labs/rackspace-clouddns/src/test/java/org/jclouds/rackspace/clouddns/v1/features/LimitApiLiveTest.java new file mode 100644 index 0000000000..27d338acee --- /dev/null +++ b/labs/rackspace-clouddns/src/test/java/org/jclouds/rackspace/clouddns/v1/features/LimitApiLiveTest.java @@ -0,0 +1,64 @@ +/** + * 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.rackspace.clouddns.v1.features; + +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; + +import org.jclouds.openstack.v2_0.domain.Limits; +import org.jclouds.rackspace.clouddns.v1.internal.BaseCloudDNSApiLiveTest; +import org.testng.annotations.AfterGroups; +import org.testng.annotations.BeforeGroups; +import org.testng.annotations.Test; + +import com.google.common.collect.Iterables; + +/** + * @author Everett Toews + */ +@Test(groups = "live", singleThreaded = true, testName = "LimitApiLiveTest") +public class LimitApiLiveTest extends BaseCloudDNSApiLiveTest { + @Override + @BeforeGroups(groups = { "live" }) + public void setupContext() { + super.setupContext(); + } + + @Test + public void testList() throws Exception { + Limits limits = cloudDNSApi.getLimitApi().list(); + assertNotNull(limits.getAbsoluteLimits()); + assertNotNull(limits.getRateLimits()); + assertTrue(limits.getAbsoluteLimits().size() > 1); + assertTrue(Iterables.size(limits.getRateLimits()) > 1); + } + + @Test + public void testListTypes() throws Exception { + Iterable limitTypes = cloudDNSApi.getLimitApi().listTypes(); + assertNotNull(limitTypes); + assertTrue(Iterables.size(limitTypes) > 1); + } + + @Override + @AfterGroups(groups = "live") + protected void tearDownContext() { + super.tearDownContext(); + } +} diff --git a/labs/rackspace-clouddns/src/test/java/org/jclouds/rackspace/clouddns/v1/internal/BaseCloudDNSApiExpectTest.java b/labs/rackspace-clouddns/src/test/java/org/jclouds/rackspace/clouddns/v1/internal/BaseCloudDNSApiExpectTest.java new file mode 100644 index 0000000000..6d02a4706c --- /dev/null +++ b/labs/rackspace-clouddns/src/test/java/org/jclouds/rackspace/clouddns/v1/internal/BaseCloudDNSApiExpectTest.java @@ -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.rackspace.clouddns.v1.internal; + +import javax.ws.rs.core.MediaType; + +import org.jclouds.http.HttpRequest; +import org.jclouds.http.HttpResponse; +import org.jclouds.rackspace.cloudidentity.v2_0.internal.RackspaceFixture; +import org.jclouds.rest.internal.BaseRestApiExpectTest; + +/** + * @author Everett Toews + */ +public class BaseCloudDNSApiExpectTest extends BaseRestApiExpectTest { + protected HttpRequest rackspaceAuthWithUsernameAndApiKey; + + protected String authToken; + protected HttpResponse responseWithAccess; + + public BaseCloudDNSApiExpectTest() { + provider = "rackspace-clouddns"; + + rackspaceAuthWithUsernameAndApiKey = RackspaceFixture.INSTANCE + .initialAuthWithUsernameAndApiKey(identity, credential); + + authToken = RackspaceFixture.INSTANCE.getAuthToken(); + responseWithAccess = RackspaceFixture.INSTANCE.responseWithAccess(); + } + + @Override + protected HttpRequestComparisonType compareHttpRequestAsType(HttpRequest input) { + return HttpRequestComparisonType.JSON; + } + + protected HttpRequest.Builder authenticatedGET() { + return HttpRequest.builder() + .method("GET") + .addHeader("Accept", MediaType.APPLICATION_JSON) + .addHeader("X-Auth-Token", authToken); + } +} diff --git a/labs/rackspace-clouddns/src/test/java/org/jclouds/rackspace/clouddns/v1/internal/BaseCloudDNSApiLiveTest.java b/labs/rackspace-clouddns/src/test/java/org/jclouds/rackspace/clouddns/v1/internal/BaseCloudDNSApiLiveTest.java new file mode 100644 index 0000000000..c0c7469f77 --- /dev/null +++ b/labs/rackspace-clouddns/src/test/java/org/jclouds/rackspace/clouddns/v1/internal/BaseCloudDNSApiLiveTest.java @@ -0,0 +1,62 @@ +/** + * 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.rackspace.clouddns.v1.internal; + +import java.util.Properties; + +import org.jclouds.apis.BaseContextLiveTest; +import org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties; +import org.jclouds.rackspace.clouddns.v1.CloudDNSApi; +import org.jclouds.rackspace.clouddns.v1.CloudDNSApiMetadata; +import org.jclouds.rackspace.clouddns.v1.CloudDNSAsyncApi; +import org.jclouds.rest.RestContext; +import org.testng.annotations.BeforeGroups; + +import com.google.common.reflect.TypeToken; + +/** + * @author Everett Toews + */ +public class BaseCloudDNSApiLiveTest extends BaseContextLiveTest> { + protected CloudDNSApi cloudDNSApi; + + public BaseCloudDNSApiLiveTest() { + provider = "rackspace-clouddns"; + } + + @BeforeGroups(groups = { "integration", "live" }) + @Override + public void setupContext() { + super.setupContext(); + + cloudDNSApi = context.getApi(); + } + + @Override + protected Properties setupProperties() { + Properties props = super.setupProperties(); + setIfTestSystemPropertyPresent(props, KeystoneProperties.CREDENTIAL_TYPE); + return props; + } + + @Override + protected TypeToken> contextType() { + return CloudDNSApiMetadata.CONTEXT_TOKEN; + } +} diff --git a/labs/rackspace-clouddns/src/test/resources/limit-list.json b/labs/rackspace-clouddns/src/test/resources/limit-list.json new file mode 100644 index 0000000000..27896a3d49 --- /dev/null +++ b/labs/rackspace-clouddns/src/test/resources/limit-list.json @@ -0,0 +1,57 @@ +{ + "limits": { + "absolute": { + "records per domain": 500, + "domains": 500 + }, + "rate": [ + { + "limit": [ + { + "verb": "GET", + "value": 5, + "remaining": 5, + "unit": "SECOND", + "next-available": "2013-03-06T20:11:14.000Z" + } + ], + "uri": "*/status/*", + "regex": ".*/v\\d+\\.\\d+/(\\d+/status).*" + }, + { + "limit": [ + { + "verb": "GET", + "value": 100, + "remaining": 100, + "unit": "MINUTE", + "next-available": "2013-03-06T20:11:14.000Z" + }, + { + "verb": "POST", + "value": 25, + "remaining": 25, + "unit": "MINUTE", + "next-available": "2013-03-06T20:11:14.000Z" + }, + { + "verb": "PUT", + "value": 50, + "remaining": 50, + "unit": "MINUTE", + "next-available": "2013-03-06T20:11:14.000Z" + }, + { + "verb": "DELETE", + "value": 50, + "remaining": 50, + "unit": "MINUTE", + "next-available": "2013-03-06T20:11:14.000Z" + } + ], + "uri": "*/domains*", + "regex": ".*/v\\d+\\.\\d+/(\\d+/domains).*" + } + ] + } +} \ No newline at end of file diff --git a/labs/rackspace-clouddns/src/test/resources/limit-types-list.json b/labs/rackspace-clouddns/src/test/resources/limit-types-list.json new file mode 100644 index 0000000000..8952e2c628 --- /dev/null +++ b/labs/rackspace-clouddns/src/test/resources/limit-types-list.json @@ -0,0 +1,7 @@ +{ + "limitTypes": [ + "RATE_LIMIT", + "DOMAIN_LIMIT", + "DOMAIN_RECORD_LIMIT" + ] +} \ No newline at end of file diff --git a/labs/rackspace-clouddns/src/test/resources/logback.xml b/labs/rackspace-clouddns/src/test/resources/logback.xml new file mode 100644 index 0000000000..9679b2e03a --- /dev/null +++ b/labs/rackspace-clouddns/src/test/resources/logback.xml @@ -0,0 +1,38 @@ + + + + target/test-data/jclouds.log + + + %d %-5p [%c] [%thread] %m%n + + + + + target/test-data/jclouds-wire.log + + + %d %-5p [%c] [%thread] %m%n + + + + + + + + + + + + + + + + + + + + + + +