Merge pull request #1389 from rackspace/rax-dns

Initial commit for the Rackspace DNS API.
This commit is contained in:
Adrian Cole 2013-03-06 15:59:49 -08:00
commit 254eace992
33 changed files with 1424 additions and 62 deletions

View File

@ -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;
@ -76,6 +81,47 @@ import com.google.inject.assistedinject.FactoryModuleBuilder;
*/
public class KeystoneAuthenticationModule extends AbstractModule {
/**
* For global services who have no regions, such as DNS. To use, do the following
* <ol>
* <li>add this module to your {@link org.jclouds.apis.ApiMetadata#getDefaultModules()}</li>
* <li>create a service-specific annotation, such as {@code @CloudDNS}, and make sure that has the meta-annotation
* {@link javax.inject.Qualifier}</li>
* <li>add the above annotation to any {@link AsyncApi} classes by placing it on the type. ex.
* {@code @Endpoint(CloudDNS.class)}</li>
* <li>add the following to your {@link RestClientModule}</li>
*
* <pre>
* bind(new TypeLiteral&lt;Supplier&lt;URI&gt;&gt;() {
* }).annotatedWith(CloudDNS.class).to(new TypeLiteral&lt;Supplier&lt;URI&gt;&gt;() {
* });
* </pre>
*/
public static class ProviderModule extends AbstractModule {
@Override
protected void configure() {
install(new FactoryModuleBuilder().build(LocationIdToURIFromAccessForTypeAndVersion.Factory.class));
}
@Provides
@Singleton
protected Supplier<URI> provideZoneIdToURISupplierForApiVersion(
@Named(KeystoneProperties.SERVICE_TYPE) String serviceType, @ApiVersion String apiVersion,
LocationIdToURIFromAccessForTypeAndVersion.Factory factory) {
return getLastValueInMap(factory.createForApiTypeAndVersion(serviceType, apiVersion));
}
@Provides
@Singleton
Function<Endpoint, String> provideProvider(@Provider final String provider) {
return new Function<Endpoint, String>() {
public String apply(Endpoint in) {
return provider;
}
};
}
}
public static class RegionModule extends AbstractModule {
@Override
protected void configure() {

View File

@ -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<Integer> remaining;
@Named("next-available")
private final Optional<Date> 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<Integer> getRemaining() {
return remaining;
}
public Optional<Date> 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();
}
}

View File

@ -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<RateLimit> rateLimits;
@Named("absolute")
private final Map<String, Integer> absoluteLimits;
@ConstructorProperties({ "rate", "absolute" })
private Limits(Iterable<RateLimit> rateLimits, Map<String, Integer> absoluteLimits) {
this.rateLimits = checkNotNull(rateLimits, "rateLimits");
this.absoluteLimits = checkNotNull(absoluteLimits, "absoluteLimits");
}
public Iterable<RateLimit> getRateLimits() {
return rateLimits;
}
public Map<String, Integer> 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();
}
}

View File

@ -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<Limit> limits;
@ConstructorProperties({ "uri", "regex", "limit" })
private RateLimit(String uri, String regex, Iterable<Limit> 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<Limit> 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();
}
}

View File

@ -38,7 +38,7 @@ public class KeystoneApiExpectTest extends BaseKeystoneRestApiExpectTest<Keyston
public void testGetApiMetaData() {
KeystoneApi api = requestsSendResponses(
keystoneAuthWithUsernameAndPassword, responseWithKeystoneAccess,
keystoneAuthWithUsernameAndPasswordAndTenantName, responseWithKeystoneAccess,
HttpRequest.builder().method("GET").endpoint(endpoint + "/v2.0/").
addHeader("Accept", APPLICATION_JSON).build(),
HttpResponse.builder().statusCode(200).
@ -50,7 +50,7 @@ public class KeystoneApiExpectTest extends BaseKeystoneRestApiExpectTest<Keyston
public void testGetApiMetaDataFailNotFound() {
KeystoneApi api = requestsSendResponses(
keystoneAuthWithUsernameAndPassword, responseWithKeystoneAccess,
keystoneAuthWithUsernameAndPasswordAndTenantName, responseWithKeystoneAccess,
HttpRequest.builder().method("GET").endpoint(endpoint + "/v2.0/").addHeader("Accept", APPLICATION_JSON).build(),
HttpResponse.builder().statusCode(404).build());
assertNull(api.getApiMetadata());

View File

@ -0,0 +1,157 @@
package org.jclouds.openstack.keystone.v2_0.config;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
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 static org.testng.Assert.assertTrue;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.net.URI;
import java.util.Properties;
import javax.inject.Qualifier;
import javax.ws.rs.HEAD;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import org.jclouds.Fallbacks.FalseOnNotFoundOr404;
import org.jclouds.apis.ApiMetadata;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse;
import org.jclouds.json.config.GsonModule.DateAdapter;
import org.jclouds.json.config.GsonModule.Iso8601DateAdapter;
import org.jclouds.openstack.keystone.v2_0.KeystoneApi;
import org.jclouds.openstack.keystone.v2_0.config.KeystoneAuthenticationModule.ProviderModule;
import org.jclouds.openstack.keystone.v2_0.internal.BaseKeystoneRestApiExpectTest;
import org.jclouds.rest.ConfiguresRestClient;
import org.jclouds.rest.annotations.Fallback;
import org.jclouds.rest.config.RestClientModule;
import org.jclouds.rest.internal.BaseRestApiExpectTest;
import org.jclouds.rest.internal.BaseRestApiMetadata;
import org.testng.annotations.Test;
import com.google.common.base.Supplier;
import com.google.common.collect.ImmutableSet;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.inject.Module;
import com.google.inject.TypeLiteral;
/**
* Tests configuration via {@link ProviderModule}
*
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "ProviderModuleExpectTest")
public class ProviderModuleExpectTest extends BaseRestApiExpectTest<ProviderModuleExpectTest.DNSApi> {
@Retention(RUNTIME)
@Target(TYPE)
@Qualifier
static @interface DNS {
}
@ConfiguresRestClient
public static class DNSRestClientModule extends RestClientModule<DNSApi, DNSAsyncApi> {
@Override
public void configure() {
bind(new TypeLiteral<Supplier<URI>>() {}).annotatedWith(DNS.class).to(new TypeLiteral<Supplier<URI>>() {});
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<Boolean> 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<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.<Class<? extends Module>> 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<KeystoneApi> {
public HttpRequest getKeystoneAuthWithUsernameAndPassword() {
return keystoneAuthWithUsernameAndPassword;
}
public HttpResponse getResponseWithKeystoneAccess() {
return responseWithKeystoneAccess;
}
}
}

View File

@ -44,7 +44,7 @@ public class ServiceApiExpectTest extends BaseKeystoneRestApiExpectTest<Keystone
public void testListTenants() {
ServiceApi api = requestsSendResponses(
keystoneAuthWithUsernameAndPassword,
keystoneAuthWithUsernameAndPasswordAndTenantName,
responseWithKeystoneAccess,
authenticatedGET().endpoint(endpoint + "/v2.0/tenants").build(),
HttpResponse.builder().statusCode(200)
@ -61,7 +61,7 @@ public class ServiceApiExpectTest extends BaseKeystoneRestApiExpectTest<Keystone
}
public void testListTenantsFailNotFound() {
ServiceApi api = requestsSendResponses(keystoneAuthWithUsernameAndPassword, responseWithKeystoneAccess,
ServiceApi api = requestsSendResponses(keystoneAuthWithUsernameAndPasswordAndTenantName, responseWithKeystoneAccess,
authenticatedGET().endpoint(endpoint + "/v2.0/tenants").build(),
HttpResponse.builder().statusCode(404).build()).getServiceApi();
assertTrue(api.listTenants().isEmpty());

View File

@ -54,7 +54,7 @@ public class TenantApiExpectTest extends BaseKeystoneRestApiExpectTest<KeystoneA
public void testListTenants() {
TenantApi api = requestsSendResponses(
keystoneAuthWithUsernameAndPassword,
keystoneAuthWithUsernameAndPasswordAndTenantName,
responseWithKeystoneAccess,
authenticatedGET().endpoint(endpoint + "/v2.0/tenants").build(),
HttpResponse.builder().statusCode(200).payload(
@ -66,7 +66,7 @@ public class TenantApiExpectTest extends BaseKeystoneRestApiExpectTest<KeystoneA
public void testListTenantsPage() {
TenantApi api = requestsSendResponses(
keystoneAuthWithUsernameAndPassword,
keystoneAuthWithUsernameAndPasswordAndTenantName,
responseWithKeystoneAccess,
authenticatedGET().endpoint(endpoint + "/v2.0/tenants").build(),
HttpResponse.builder().statusCode(200).payload(
@ -84,7 +84,7 @@ public class TenantApiExpectTest extends BaseKeystoneRestApiExpectTest<KeystoneA
@Test(enabled = false)
public void testListTenantsATT() {
TenantApi api = requestsSendResponses(
keystoneAuthWithUsernameAndPassword,
keystoneAuthWithUsernameAndPasswordAndTenantName,
responseWithKeystoneAccess,
authenticatedGET().endpoint(endpoint + "/v2.0/tenants").build(),
HttpResponse.builder().statusCode(200).payload(
@ -100,7 +100,7 @@ public class TenantApiExpectTest extends BaseKeystoneRestApiExpectTest<KeystoneA
// http://docs.openstack.org/api/openstack-identity-service/2.0/content/Paginated_Collections-d1e325.html
@Test(enabled = false)
public void testListTenantsFailNotFound() {
TenantApi api = requestsSendResponses(keystoneAuthWithUsernameAndPassword, responseWithKeystoneAccess,
TenantApi api = requestsSendResponses(keystoneAuthWithUsernameAndPasswordAndTenantName, responseWithKeystoneAccess,
authenticatedGET().endpoint(endpoint + "/v2.0/tenants").build(), HttpResponse.builder().statusCode(404).build())
.getTenantApi().get();
assertTrue(api.list().isEmpty());
@ -108,7 +108,7 @@ public class TenantApiExpectTest extends BaseKeystoneRestApiExpectTest<KeystoneA
public void testGetTenant() {
TenantApi api = requestsSendResponses(
keystoneAuthWithUsernameAndPassword,
keystoneAuthWithUsernameAndPasswordAndTenantName,
responseWithKeystoneAccess,
authenticatedGET().endpoint(endpoint + "/v2.0/tenants/013ba41150a14830bec85ffe93353bcc").build(),
HttpResponse.builder().statusCode(200).payload(
@ -121,7 +121,7 @@ public class TenantApiExpectTest extends BaseKeystoneRestApiExpectTest<KeystoneA
@Test(expectedExceptions = AuthorizationException.class)
public void testListTenantsFailNotAuthorized() {
TenantApi api = requestsSendResponses(keystoneAuthWithUsernameAndPassword, responseWithKeystoneAccess,
TenantApi api = requestsSendResponses(keystoneAuthWithUsernameAndPasswordAndTenantName, responseWithKeystoneAccess,
authenticatedGET().endpoint(endpoint + "/v2.0/tenants/013ba41150a14830bec85ffe93353bcc").build(),
HttpResponse.builder().statusCode(401).build()).getTenantApi().get();
api.get("013ba41150a14830bec85ffe93353bcc");
@ -129,7 +129,7 @@ public class TenantApiExpectTest extends BaseKeystoneRestApiExpectTest<KeystoneA
public void testGetTenantByName() {
TenantApi api = requestsSendResponses(
keystoneAuthWithUsernameAndPassword,
keystoneAuthWithUsernameAndPasswordAndTenantName,
responseWithKeystoneAccess,
authenticatedGET().endpoint(endpoint + "/v2.0/tenants?name=admin").build(),
HttpResponse.builder().statusCode(200).payload(
@ -141,7 +141,7 @@ public class TenantApiExpectTest extends BaseKeystoneRestApiExpectTest<KeystoneA
}
public void testGetTenantByNameFailNotFound() {
TenantApi api = requestsSendResponses(keystoneAuthWithUsernameAndPassword, responseWithKeystoneAccess,
TenantApi api = requestsSendResponses(keystoneAuthWithUsernameAndPasswordAndTenantName, responseWithKeystoneAccess,
authenticatedGET().endpoint(endpoint + "/v2.0/tenants?name=admin").build(),
HttpResponse.builder().statusCode(404).build()).getTenantApi().get();
assertNull(api.getByName("admin"));

View File

@ -60,7 +60,7 @@ public class TokenApiExpectTest extends BaseKeystoneRestApiExpectTest<KeystoneAp
public void testGetToken() {
TokenApi api = requestsSendResponses(
keystoneAuthWithUsernameAndPassword, responseWithKeystoneAccess,
keystoneAuthWithUsernameAndPasswordAndTenantName, responseWithKeystoneAccess,
authenticatedGET().endpoint(endpoint + "/v2.0/tokens/sometokenorother").build(),
HttpResponse.builder().statusCode(200).payload(payloadFromResourceWithContentType("/token_details.json", APPLICATION_JSON)).build())
.getTokenApi().get();
@ -73,7 +73,7 @@ public class TokenApiExpectTest extends BaseKeystoneRestApiExpectTest<KeystoneAp
public void testGetTokenFailNotFound() {
TokenApi api = requestsSendResponses(
keystoneAuthWithUsernameAndPassword, responseWithKeystoneAccess,
keystoneAuthWithUsernameAndPasswordAndTenantName, responseWithKeystoneAccess,
authenticatedGET().endpoint(endpoint + "/v2.0/tokens/sometokenorother").build(),
HttpResponse.builder().statusCode(404).build())
.getTokenApi().get();
@ -83,7 +83,7 @@ public class TokenApiExpectTest extends BaseKeystoneRestApiExpectTest<KeystoneAp
@Test(expectedExceptions = HttpResponseException.class)
public void testGetTokenFail500() {
TokenApi api = requestsSendResponses(
keystoneAuthWithUsernameAndPassword, responseWithKeystoneAccess,
keystoneAuthWithUsernameAndPasswordAndTenantName, responseWithKeystoneAccess,
authenticatedGET().endpoint(endpoint + "/v2.0/tokens/sometokenorother").build(),
HttpResponse.builder().statusCode(500).build()).getTokenApi().get();
api.get("sometokenorother");
@ -91,7 +91,7 @@ public class TokenApiExpectTest extends BaseKeystoneRestApiExpectTest<KeystoneAp
public void testGetUserOfToken() {
TokenApi api = requestsSendResponses(
keystoneAuthWithUsernameAndPassword, responseWithKeystoneAccess,
keystoneAuthWithUsernameAndPasswordAndTenantName, responseWithKeystoneAccess,
authenticatedGET().endpoint(endpoint + "/v2.0/tokens/sometokenorother").build(),
HttpResponse.builder().statusCode(200).payload(payloadFromResourceWithContentType("/token_details.json", APPLICATION_JSON)).build())
.getTokenApi().get();
@ -104,7 +104,7 @@ public class TokenApiExpectTest extends BaseKeystoneRestApiExpectTest<KeystoneAp
public void testGetUserOfTokenFailNotFound() {
TokenApi api = requestsSendResponses(
keystoneAuthWithUsernameAndPassword, responseWithKeystoneAccess,
keystoneAuthWithUsernameAndPasswordAndTenantName, responseWithKeystoneAccess,
authenticatedGET().endpoint(endpoint + "/v2.0/tokens/sometokenorother").build(),
HttpResponse.builder().statusCode(404).build()).getTokenApi().get();
assertNull(api.getUserOfToken("sometokenorother"));
@ -112,7 +112,7 @@ public class TokenApiExpectTest extends BaseKeystoneRestApiExpectTest<KeystoneAp
public void testCheckTokenIsValid() {
TokenApi api = requestsSendResponses(
keystoneAuthWithUsernameAndPassword, responseWithKeystoneAccess,
keystoneAuthWithUsernameAndPasswordAndTenantName, responseWithKeystoneAccess,
HttpRequest.builder().method("HEAD")
.endpoint(endpoint + "/v2.0/tokens/sometokenorother")
.addHeader("X-Auth-Token", authToken).build(),
@ -123,7 +123,7 @@ public class TokenApiExpectTest extends BaseKeystoneRestApiExpectTest<KeystoneAp
public void testCheckTokenIsValidFailNotValid() {
TokenApi api = requestsSendResponses(
keystoneAuthWithUsernameAndPassword, responseWithKeystoneAccess,
keystoneAuthWithUsernameAndPasswordAndTenantName, responseWithKeystoneAccess,
HttpRequest.builder().method("HEAD")
.endpoint(endpoint + "/v2.0/tokens/sometokenorother")
.addHeader("X-Auth-Token", authToken).build(),
@ -134,7 +134,7 @@ public class TokenApiExpectTest extends BaseKeystoneRestApiExpectTest<KeystoneAp
@Test
public void testGetEndpointsForToken() {
TokenApi api = requestsSendResponses(
keystoneAuthWithUsernameAndPassword, responseWithKeystoneAccess,
keystoneAuthWithUsernameAndPasswordAndTenantName, responseWithKeystoneAccess,
authenticatedGET().endpoint(endpoint + "/v2.0/tokens/XXXXXX/endpoints").build(),
HttpResponse.builder().statusCode(200).payload(payloadFromResourceWithContentType("/user_endpoints.json", APPLICATION_JSON)).build())
.getTokenApi().get();
@ -150,7 +150,7 @@ public class TokenApiExpectTest extends BaseKeystoneRestApiExpectTest<KeystoneAp
@Test
public void testGetEndpointsForTokenFailNotFound() {
TokenApi api = requestsSendResponses(
keystoneAuthWithUsernameAndPassword, responseWithKeystoneAccess,
keystoneAuthWithUsernameAndPasswordAndTenantName, responseWithKeystoneAccess,
authenticatedGET().endpoint(endpoint + "/v2.0/tokens/XXXXXX/endpoints").build(),
HttpResponse.builder().statusCode(404).build())
.getTokenApi().get();

View File

@ -61,7 +61,7 @@ public class UserApiExpectTest extends BaseKeystoneRestApiExpectTest<KeystoneApi
public void testListUsers() {
UserApi api = requestsSendResponses(
keystoneAuthWithUsernameAndPassword, responseWithKeystoneAccess,
keystoneAuthWithUsernameAndPasswordAndTenantName, responseWithKeystoneAccess,
authenticatedGET().endpoint(endpoint + "/v2.0/users").build(),
HttpResponse.builder().statusCode(200).payload(payloadFromResourceWithContentType("/user_list.json", APPLICATION_JSON)).build())
.getUserApi().get();
@ -71,7 +71,7 @@ public class UserApiExpectTest extends BaseKeystoneRestApiExpectTest<KeystoneApi
public void testListUsersPage() {
UserApi api = requestsSendResponses(
keystoneAuthWithUsernameAndPassword, responseWithKeystoneAccess,
keystoneAuthWithUsernameAndPasswordAndTenantName, responseWithKeystoneAccess,
authenticatedGET().endpoint(endpoint + "/v2.0/users").build(),
HttpResponse.builder().statusCode(200).payload(payloadFromResourceWithContentType("/user_list.json", APPLICATION_JSON)).build())
.getUserApi().get();
@ -85,7 +85,7 @@ public class UserApiExpectTest extends BaseKeystoneRestApiExpectTest<KeystoneApi
public void testListUsersNotFound() {
UserApi api = requestsSendResponses(
keystoneAuthWithUsernameAndPassword, responseWithKeystoneAccess,
keystoneAuthWithUsernameAndPasswordAndTenantName, responseWithKeystoneAccess,
authenticatedGET().endpoint(endpoint + "/v2.0/users").build(),
HttpResponse.builder().statusCode(404).build()).getUserApi().get();
assertEquals( api.list(new PaginationOptions()).size(), 0);
@ -94,7 +94,7 @@ public class UserApiExpectTest extends BaseKeystoneRestApiExpectTest<KeystoneApi
@Test(expectedExceptions = AuthorizationException.class)
public void testListUsersFailNotAuth() {
UserApi api = requestsSendResponses(
keystoneAuthWithUsernameAndPassword, responseWithKeystoneAccess,
keystoneAuthWithUsernameAndPasswordAndTenantName, responseWithKeystoneAccess,
authenticatedGET().endpoint(endpoint + "/v2.0/users").build(),
HttpResponse.builder().statusCode(401).build()).getUserApi().get();
api.list(new PaginationOptions());
@ -102,7 +102,7 @@ public class UserApiExpectTest extends BaseKeystoneRestApiExpectTest<KeystoneApi
public void testGetUser() {
UserApi api = requestsSendResponses(
keystoneAuthWithUsernameAndPassword, responseWithKeystoneAccess,
keystoneAuthWithUsernameAndPasswordAndTenantName, responseWithKeystoneAccess,
authenticatedGET().endpoint(endpoint + "/v2.0/users/e021dfd758eb44a89f1c57c8ef3be8e2").build(),
HttpResponse.builder().statusCode(200).payload(payloadFromResourceWithContentType("/user_details.json", APPLICATION_JSON)).build())
.getUserApi().get();
@ -113,7 +113,7 @@ public class UserApiExpectTest extends BaseKeystoneRestApiExpectTest<KeystoneApi
public void testGetUserFailNotFound() {
UserApi api = requestsSendResponses(
keystoneAuthWithUsernameAndPassword, responseWithKeystoneAccess,
keystoneAuthWithUsernameAndPasswordAndTenantName, responseWithKeystoneAccess,
authenticatedGET().endpoint(endpoint + "/v2.0/users/f021dfd758eb44a89f1c57c8ef3be8e2").build(),
HttpResponse.builder().statusCode(404).build()).getUserApi().get();
assertNull(api.get("f021dfd758eb44a89f1c57c8ef3be8e2"));
@ -121,7 +121,7 @@ public class UserApiExpectTest extends BaseKeystoneRestApiExpectTest<KeystoneApi
public void testGetUserByName() {
UserApi api = requestsSendResponses(
keystoneAuthWithUsernameAndPassword, responseWithKeystoneAccess,
keystoneAuthWithUsernameAndPasswordAndTenantName, responseWithKeystoneAccess,
authenticatedGET().endpoint(endpoint + "/v2.0/users?name=nova").build(),
HttpResponse.builder().statusCode(200).payload(payloadFromResourceWithContentType("/user_details.json", APPLICATION_JSON)).build())
.getUserApi().get();
@ -132,7 +132,7 @@ public class UserApiExpectTest extends BaseKeystoneRestApiExpectTest<KeystoneApi
public void testGetUserByNameFailNotFound() {
UserApi api = requestsSendResponses(
keystoneAuthWithUsernameAndPassword, responseWithKeystoneAccess,
keystoneAuthWithUsernameAndPasswordAndTenantName, responseWithKeystoneAccess,
authenticatedGET().endpoint(endpoint + "/v2.0/users?name=fred").build(),
HttpResponse.builder().statusCode(404).build()).getUserApi().get();
assertNull(api.getByName("fred"));
@ -140,7 +140,7 @@ public class UserApiExpectTest extends BaseKeystoneRestApiExpectTest<KeystoneApi
public void testListRolesOfUser() {
UserApi api = requestsSendResponses(
keystoneAuthWithUsernameAndPassword, responseWithKeystoneAccess,
keystoneAuthWithUsernameAndPasswordAndTenantName, responseWithKeystoneAccess,
authenticatedGET().endpoint(endpoint + "/v2.0/users/3f6c1c9ba993495ead7d2eb2192e284f/roles").build(),
HttpResponse.builder().statusCode(200).payload(payloadFromResourceWithContentType("/user_role_list.json", APPLICATION_JSON)).build())
.getUserApi().get();
@ -154,7 +154,7 @@ public class UserApiExpectTest extends BaseKeystoneRestApiExpectTest<KeystoneApi
public void testListRolesOfUserFailNotFound() {
UserApi api = requestsSendResponses(
keystoneAuthWithUsernameAndPassword, responseWithKeystoneAccess,
keystoneAuthWithUsernameAndPasswordAndTenantName, responseWithKeystoneAccess,
authenticatedGET().endpoint(endpoint + "/v2.0/users/4f6c1c9ba993495ead7d2eb2192e284f/roles").build(),
HttpResponse.builder().statusCode(404).build()).getUserApi().get();
assertTrue(api.listRolesOfUser("4f6c1c9ba993495ead7d2eb2192e284f").isEmpty());
@ -163,7 +163,7 @@ public class UserApiExpectTest extends BaseKeystoneRestApiExpectTest<KeystoneApi
@Test(expectedExceptions = HttpResponseException.class)
public void testListRolesOfUserFailNotImplemented() {
UserApi api = requestsSendResponses(
keystoneAuthWithUsernameAndPassword, responseWithKeystoneAccess,
keystoneAuthWithUsernameAndPasswordAndTenantName, responseWithKeystoneAccess,
authenticatedGET().endpoint(endpoint + "/v2.0/users/5f6c1c9ba993495ead7d2eb2192e284f/roles").build(),
HttpResponse.builder().statusCode(501).build()).getUserApi().get();
assertTrue(api.listRolesOfUser("5f6c1c9ba993495ead7d2eb2192e284f").isEmpty());
@ -171,7 +171,7 @@ public class UserApiExpectTest extends BaseKeystoneRestApiExpectTest<KeystoneApi
public void testListRolesOfUserInTenant() {
UserApi api = requestsSendResponses(
keystoneAuthWithUsernameAndPassword, responseWithKeystoneAccess,
keystoneAuthWithUsernameAndPasswordAndTenantName, responseWithKeystoneAccess,
authenticatedGET().endpoint(endpoint + "/v2.0/users/3f6c1c9ba993495ead7d2eb2192e284f/roles").build(),
HttpResponse.builder().statusCode(200).payload(payloadFromResourceWithContentType("/user_tenant_role_list.json", APPLICATION_JSON)).build())
.getUserApi().get();
@ -186,7 +186,7 @@ public class UserApiExpectTest extends BaseKeystoneRestApiExpectTest<KeystoneApi
public void testListRolesOfUserInTenantFailNotFound() {
UserApi api = requestsSendResponses(
keystoneAuthWithUsernameAndPassword, responseWithKeystoneAccess,
keystoneAuthWithUsernameAndPasswordAndTenantName, responseWithKeystoneAccess,
authenticatedGET().endpoint(endpoint + "/v2.0/users/3f6c1c9ba993495ead7d2eb2192e284f/roles").build(),
HttpResponse.builder().statusCode(404).build()).getUserApi().get();
assertTrue(api.listRolesOfUser("3f6c1c9ba993495ead7d2eb2192e284f").isEmpty());

View File

@ -39,6 +39,7 @@ import com.google.common.base.Objects;
* @author Adam Lowe
*/
public class BaseKeystoneRestApiExpectTest<S> extends BaseRestApiExpectTest<S> {
protected HttpRequest keystoneAuthWithUsernameAndPasswordAndTenantName;
protected HttpRequest keystoneAuthWithUsernameAndPassword;
protected HttpRequest keystoneAuthWithAccessKeyAndSecretKey;
protected String authToken;
@ -47,10 +48,12 @@ public class BaseKeystoneRestApiExpectTest<S> extends BaseRestApiExpectTest<S> {
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,9 +62,7 @@ public class BaseKeystoneRestApiExpectTest<S> extends BaseRestApiExpectTest<S> {
}
protected HttpRequest.Builder<?> authenticatedGET() {
return HttpRequest.builder()
.method("GET")
.addHeader("Accept", MediaType.APPLICATION_JSON)
return HttpRequest.builder().method("GET").addHeader("Accept", MediaType.APPLICATION_JSON)
.addHeader("X-Auth-Token", authToken);
}

View File

@ -115,7 +115,12 @@ public class ParseAccessTest extends BaseItemParserTest<Access> {
.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();
}
}

View File

@ -112,7 +112,7 @@ public class ParseRackspaceAccessTest extends BaseItemParserTest<Access> {
.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())

View File

@ -138,6 +138,16 @@
}
],
"endpoints_links": []
},
{
"type": "dns",
"name": "dns",
"endpoints": [
{
"publicURL": "http://172.16.0.1:8776/v1/3456",
"tenantId": "3456"
}
]
}
]
}

View File

@ -87,7 +87,7 @@
"publicURL": "https:\/\/dns.api.rackspacecloud.com\/v1.0\/40806637803162"
}],
"name": "cloudDNS",
"type": "dnsextension:dns"
"type": "rax:dns"
}, {
"endpoints": [{
"region": "DFW",

View File

@ -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";
}

View File

@ -818,8 +818,8 @@ public class RestAnnotationProcessor implements Function<Invocation, HttpRequest
@Override
public String toString() {
String callerString = String.format("%s.%s%s", caller.getInvokable().getOwnerType().getRawType().getSimpleName(),
caller.getInvokable().getName(), caller.getArgs());
String callerString = caller != null ? String.format("%s.%s%s", caller.getInvokable().getOwnerType().getRawType().getSimpleName(),
caller.getInvokable().getName(), caller.getArgs()) : null;
return Objects.toStringHelper("").omitNullValues().add("caller", callerString).toString();
}
}

View File

@ -0,0 +1,135 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to jclouds, Inc. (jclouds) under one or more
contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. jclouds licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.jclouds</groupId>
<artifactId>jclouds-project</artifactId>
<version>1.6.0-SNAPSHOT</version>
<relativePath>../../project/pom.xml</relativePath>
</parent>
<groupId>org.jclouds.labs</groupId>
<artifactId>rackspace-clouddns</artifactId>
<name>jclouds rackspace clouddns api</name>
<description>jclouds components for Rackspace Cloud DNS</description>
<packaging>bundle</packaging>
<properties>
<test.rackspace-clouddns.endpoint>https://identity.api.rackspacecloud.com/v2.0/</test.rackspace-clouddns.endpoint>
<test.rackspace-clouddns.api-version>1.0</test.rackspace-clouddns.api-version>
<test.rackspace-clouddns.build-version />
<test.rackspace-clouddns.identity>${test.rackspace.identity}</test.rackspace-clouddns.identity>
<test.rackspace-clouddns.credential>${test.rackspace.credential}</test.rackspace-clouddns.credential>
<jclouds.osgi.export>org.jclouds.rackspace.clouddns.v1*;version="${project.version}"</jclouds.osgi.export>
<jclouds.osgi.import>
org.jclouds.rest.internal;version="${project.version}",
org.jclouds*;version="${project.version}",
*
</jclouds.osgi.import>
</properties>
<dependencies>
<dependency>
<groupId>org.jclouds</groupId>
<artifactId>jclouds-core</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.jclouds.api</groupId>
<artifactId>openstack-keystone</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.jclouds.api</groupId>
<artifactId>rackspace-cloudidentity</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.jclouds</groupId>
<artifactId>jclouds-core</artifactId>
<version>${project.version}</version>
<type>test-jar</type>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jclouds.api</groupId>
<artifactId>openstack-keystone</artifactId>
<version>${project.version}</version>
<type>test-jar</type>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jclouds.api</groupId>
<artifactId>rackspace-cloudidentity</artifactId>
<version>${project.version}</version>
<type>test-jar</type>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jclouds.driver</groupId>
<artifactId>jclouds-slf4j</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<profiles>
<profile>
<id>live</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<executions>
<execution>
<id>integration</id>
<phase>integration-test</phase>
<goals>
<goal>test</goal>
</goals>
<configuration>
<!-- TODO: remove when multiple jobs/session are supported -->
<threadCount>1</threadCount>
<systemPropertyVariables>
<test.rackspace-clouddns.endpoint>${test.rackspace-clouddns.endpoint}</test.rackspace-clouddns.endpoint>
<test.rackspace-clouddns.api-version>${test.rackspace-clouddns.api-version}</test.rackspace-clouddns.api-version>
<test.rackspace-clouddns.build-version>${test.rackspace-clouddns.build-version}</test.rackspace-clouddns.build-version>
<test.rackspace-clouddns.identity>${test.rackspace-clouddns.identity}</test.rackspace-clouddns.identity>
<test.rackspace-clouddns.credential>${test.rackspace-clouddns.credential}</test.rackspace-clouddns.credential>
</systemPropertyVariables>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>

View File

@ -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.
* <p/>
* See <a href="http://docs.rackspace.com/cdns/api/v1.0/cdns-devguide/content/index.html">Cloud DNS Developer Guide</a>
* @see CloudDNSAsyncApi
* @author Everett Toews
*/
public interface CloudDNSApi {
/**
* Provides synchronous access to Limit features.
*/
@Delegate
LimitApi getLimitApi();
}

View File

@ -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<RestContext<CloudDNSApi, CloudDNSAsyncApi>> CONTEXT_TOKEN = new TypeToken<RestContext<CloudDNSApi, CloudDNSAsyncApi>>() {
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<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.<Class<? extends Module>> 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;
}
}
}

View File

@ -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.
* <p/>
*
* @see CloudDNSApi
* @author Everett Toews
*/
public interface CloudDNSAsyncApi {
/**
* Provides asynchronous access to Limit features.
*/
@Delegate
LimitAsyncApi getLimitApi();
}

View File

@ -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 {
}

View File

@ -0,0 +1,59 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.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<CloudDNSApi, CloudDNSAsyncApi> {
public static final Map<Class<?>, Class<?>> DELEGATE_MAP = ImmutableMap.<Class<?>, Class<?>> builder()
.put(LimitApi.class, LimitAsyncApi.class)
.build();
public CloudDNSRestClientModule() {
super(DELEGATE_MAP);
}
@Override
protected void configure() {
bind(new TypeLiteral<Supplier<URI>>() {}).annotatedWith(CloudDNS.class).to(new TypeLiteral<Supplier<URI>>() {});
bind(DateAdapter.class).to(Iso8601DateAdapter.class);
super.configure();
}
}

View File

@ -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<String> listTypes();
}

View File

@ -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<Limits> list();
/**
* @see LimitApi#listTypes()
*/
@Named("limits:list")
@GET
@Consumes(MediaType.APPLICATION_JSON)
@Fallback(EmptyListOnNotFoundOr404.class)
@SelectJson("limitTypes")
@Path("/limits/types")
ListenableFuture<Iterable<String>> listTypes();
}

View File

@ -0,0 +1 @@
org.jclouds.rackspace.clouddns.v1.CloudDNSApiMetadata

View File

@ -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<CloudDNSApi> {
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<String> limitTypes = api.listTypes();
assertEquals(Iterables.size(limitTypes), 3);
}
private static Predicate<RateLimit> isStatusRateLimit() {
return new Predicate<RateLimit>() {
@Override
public boolean apply(RateLimit rateLimit) {
return rateLimit.getUri().contains("status");
}
};
}
}

View File

@ -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<String> limitTypes = cloudDNSApi.getLimitApi().listTypes();
assertNotNull(limitTypes);
assertTrue(Iterables.size(limitTypes) > 1);
}
@Override
@AfterGroups(groups = "live")
protected void tearDownContext() {
super.tearDownContext();
}
}

View File

@ -0,0 +1,58 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.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<T> extends BaseRestApiExpectTest<T> {
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);
}
}

View File

@ -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<RestContext<CloudDNSApi, CloudDNSAsyncApi>> {
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<RestContext<CloudDNSApi, CloudDNSAsyncApi>> contextType() {
return CloudDNSApiMetadata.CONTEXT_TOKEN;
}
}

View File

@ -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).*"
}
]
}
}

View File

@ -0,0 +1,7 @@
{
"limitTypes": [
"RATE_LIMIT",
"DOMAIN_LIMIT",
"DOMAIN_RECORD_LIMIT"
]
}

View File

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