Fixes OpenStack extension namespace configuration

* Improves extension namespace configuration to use Guice multibindings
  so each provider can cleanly provide their own namespaces.
* Fixes the HPCloud Compute volume attachment namespace and adds the
  corresponding live tests.
* Fixes the Rackspace CloudServers UK volume attachment namespace.
This commit is contained in:
Ignasi Barrera 2015-03-23 22:40:43 +01:00
parent 8217248571
commit 4db2b75add
21 changed files with 342 additions and 159 deletions

View File

@ -75,9 +75,8 @@
</dependency>
<!-- for ohai -->
<dependency>
<groupId>com.google.inject.extensions</groupId>
<artifactId>guice-multibindings</artifactId>
<version>3.0</version>
<groupId>com.google.inject.extensions</groupId>
<artifactId>guice-multibindings</artifactId>
</dependency>
<!-- for transient chef provider -->
<dependency>

View File

@ -51,6 +51,11 @@
<artifactId>jclouds-core</artifactId>
<version>${project.version}</version>
</dependency>
<!-- for the extension namespaces -->
<dependency>
<groupId>com.google.inject.extensions</groupId>
<artifactId>guice-multibindings</artifactId>
</dependency>
<dependency>
<groupId>org.apache.jclouds</groupId>
<artifactId>jclouds-core</artifactId>

View File

@ -0,0 +1,31 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.openstack.keystone.v2_0.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;
@Retention(value = RetentionPolicy.RUNTIME)
@Target(value = { ElementType.TYPE, ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD })
@Qualifier
public @interface Aliases {
}

View File

@ -49,11 +49,11 @@ import com.google.common.base.Suppliers;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.Multimap;
import com.google.inject.AbstractModule;
import com.google.inject.Binder;
import com.google.inject.Provides;
import com.google.inject.assistedinject.FactoryModuleBuilder;
import com.google.inject.multibindings.MapBinder;
/**
* Configures the Keystone API.
@ -91,17 +91,16 @@ public class KeystoneHttpApiModule extends HttpApiModule<KeystoneApi> {
}
}
// Allow providers to cleanly contribute their own aliases
public static MapBinder<URI, URI> aliasBinder(Binder binder) {
return MapBinder.newMapBinder(binder, URI.class, URI.class, Aliases.class).permitDuplicates();
}
@Override
protected void configure() {
bind(ImplicitOptionalConverter.class).to(PresentWhenExtensionAnnotationNamespaceEqualsAnyNamespaceInExtensionsSet.class);
super.configure();
}
@Provides
@Singleton
public Multimap<URI, URI> aliases() {
return ImmutableMultimap.<URI, URI>builder()
.build();
aliasBinder(binder());
}
@Provides

View File

@ -23,18 +23,20 @@ import static org.jclouds.util.Optionals2.unwrapIfOptional;
import java.net.URI;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.inject.Inject;
import org.jclouds.openstack.keystone.v2_0.config.Aliases;
import org.jclouds.openstack.v2_0.domain.Extension;
import org.jclouds.reflect.InvocationSuccess;
import org.jclouds.rest.functions.ImplicitOptionalConverter;
import com.google.common.base.Optional;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.Multimap;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Sets;
/**
* We use the annotation {@link org.jclouds.openstack.services.Extension} to bind a class that implements an extension
@ -43,13 +45,13 @@ import com.google.common.collect.Multimap;
public class PresentWhenExtensionAnnotationNamespaceEqualsAnyNamespaceInExtensionsSet implements
ImplicitOptionalConverter {
private final LoadingCache<String, Set<? extends Extension>> extensions;
private final Multimap<URI, URI> aliases;
private final Map<URI, Set<URI>> aliases;
@Inject
public PresentWhenExtensionAnnotationNamespaceEqualsAnyNamespaceInExtensionsSet(
LoadingCache<String, Set<? extends Extension>> extensions, Multimap<URI, URI> aliases) {
this.extensions = checkNotNull(extensions, "extensions");
this.aliases = aliases == null ? ImmutableMultimap.<URI, URI> of() : ImmutableMultimap.copyOf(aliases);
PresentWhenExtensionAnnotationNamespaceEqualsAnyNamespaceInExtensionsSet(
LoadingCache<String, Set<? extends Extension>> extensions, @Aliases Map<URI, Set<URI>> aliases) {
this.extensions = extensions;
this.aliases = aliases == null ? ImmutableMap.<URI, Set<URI>> of() : ImmutableMap.copyOf(aliases);
}
@Override
@ -60,12 +62,13 @@ public class PresentWhenExtensionAnnotationNamespaceEqualsAnyNamespaceInExtensio
if (ext.isPresent()) {
URI namespace = URI.create(ext.get().namespace());
List<Object> args = input.getInvocation().getArgs();
Set<URI> aliasesForNamespace = aliases.containsKey(namespace) ? aliases.get(namespace) : Sets.<URI> newHashSet();
if (args.isEmpty()) {
if (any(extensions.getUnchecked(""), namespaceOrAliasEquals(namespace, aliases.get(namespace))))
if (any(extensions.getUnchecked(""), namespaceOrAliasEquals(namespace, aliasesForNamespace)))
return input.getResult();
} else if (args.size() == 1) {
String arg0 = checkNotNull(args.get(0), "arg[0] in %s", input).toString();
if (any(extensions.getUnchecked(arg0), namespaceOrAliasEquals(namespace, aliases.get(namespace))))
if (any(extensions.getUnchecked(arg0), namespaceOrAliasEquals(namespace, aliasesForNamespace)))
return input.getResult();
} else {
throw new RuntimeException(String.format("expecting zero or one args %s", input));

View File

@ -24,6 +24,7 @@ import java.util.List;
import java.util.Set;
import org.jclouds.date.internal.SimpleDateFormatDateService;
import org.jclouds.openstack.keystone.v2_0.config.Aliases;
import org.jclouds.openstack.v2_0.ServiceType;
import org.jclouds.openstack.v2_0.domain.Extension;
import org.jclouds.reflect.Invocation;
@ -44,6 +45,7 @@ import com.google.common.collect.Multimap;
import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Provides;
import com.google.inject.multibindings.MapBinder;
@Test(groups = "unit", testName = "PresentWhenExtensionAnnotationNamespaceEqualsAnyNamespaceInExtensionsSetTest")
public class PresentWhenExtensionAnnotationNamespaceEqualsAnyNamespaceInExtensionsSetTest {
@ -138,6 +140,13 @@ public class PresentWhenExtensionAnnotationNamespaceEqualsAnyNamespaceInExtensio
new AbstractModule() {
@Override
protected void configure() {
MapBinder<URI, URI> aliasBindings = MapBinder.newMapBinder(binder(),
URI.class, URI.class, Aliases.class).permitDuplicates();
for (URI key : aliases.keySet()) {
for (URI value : aliases.get(key)) {
aliasBindings.addBinding(key).toInstance(value);
}
}
}
@Provides
@ -145,10 +154,6 @@ public class PresentWhenExtensionAnnotationNamespaceEqualsAnyNamespaceInExtensio
return extensionsForRegion;
}
@Provides
Multimap<URI, URI> getAliases() {
return aliases;
}
}).getInstance(PresentWhenExtensionAnnotationNamespaceEqualsAnyNamespaceInExtensionsSet.class);
return fn;

View File

@ -53,6 +53,11 @@
<artifactId>openstack-keystone</artifactId>
<version>${project.version}</version>
</dependency>
<!-- for the extension namespaces -->
<dependency>
<groupId>com.google.inject.extensions</groupId>
<artifactId>guice-multibindings</artifactId>
</dependency>
<dependency>
<groupId>org.apache.jclouds</groupId>
<artifactId>jclouds-compute</artifactId>

View File

@ -16,6 +16,8 @@
*/
package org.jclouds.openstack.nova.v2_0.config;
import static org.jclouds.openstack.keystone.v2_0.config.KeystoneHttpApiModule.aliasBinder;
import java.net.URI;
import java.util.Set;
import java.util.concurrent.TimeUnit;
@ -39,9 +41,8 @@ import org.jclouds.rest.functions.ImplicitOptionalConverter;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.Multimap;
import com.google.inject.Provides;
import com.google.inject.multibindings.MapBinder;
/**
* Configures the Nova connection.
@ -57,45 +58,44 @@ public class NovaHttpApiModule extends HttpApiModule<NovaApi> {
protected void configure() {
bind(ImplicitOptionalConverter.class).to(PresentWhenExtensionAnnotationNamespaceEqualsAnyNamespaceInExtensionsSet.class);
super.configure();
bindDefaultAliases();
}
@Provides
@Singleton
public Multimap<URI, URI> aliases() {
return ImmutableMultimap.<URI, URI>builder()
.put(URI.create(ExtensionNamespaces.SECURITY_GROUPS),
URI.create("http://docs.openstack.org/compute/ext/securitygroups/api/v1.1"))
.put(URI.create(ExtensionNamespaces.FLOATING_IPS),
URI.create("http://docs.openstack.org/compute/ext/floating_ips/api/v1.1"))
.put(URI.create(ExtensionNamespaces.KEYPAIRS),
URI.create("http://docs.openstack.org/compute/ext/keypairs/api/v1.1"))
.put(URI.create(ExtensionNamespaces.SIMPLE_TENANT_USAGE),
URI.create("http://docs.openstack.org/compute/ext/os-simple-tenant-usage/api/v1.1"))
.put(URI.create(ExtensionNamespaces.HOSTS),
URI.create("http://docs.openstack.org/compute/ext/hosts/api/v1.1"))
.put(URI.create(ExtensionNamespaces.VOLUMES),
URI.create("http://docs.openstack.org/compute/ext/volumes/api/v1.1"))
.put(URI.create(ExtensionNamespaces.VIRTUAL_INTERFACES),
URI.create("http://docs.openstack.org/compute/ext/virtual_interfaces/api/v1.1"))
.put(URI.create(ExtensionNamespaces.CREATESERVEREXT),
URI.create("http://docs.openstack.org/compute/ext/createserverext/api/v1.1"))
.put(URI.create(ExtensionNamespaces.ADMIN_ACTIONS),
URI.create("http://docs.openstack.org/compute/ext/admin-actions/api/v1.1"))
.put(URI.create(ExtensionNamespaces.AGGREGATES),
URI.create("http://docs.openstack.org/compute/ext/aggregates/api/v1.1"))
.put(URI.create(ExtensionNamespaces.FLAVOR_EXTRA_SPECS),
URI.create("http://docs.openstack.org/compute/ext/flavor_extra_specs/api/v1.1"))
.put(URI.create(ExtensionNamespaces.QUOTAS),
URI.create("http://docs.openstack.org/compute/ext/quotas-sets/api/v1.1"))
.put(URI.create(ExtensionNamespaces.VOLUME_TYPES),
URI.create("http://docs.openstack.org/compute/ext/volume_types/api/v1.1"))
.put(URI.create(ExtensionNamespaces.AVAILABILITY_ZONE),
URI.create("http://docs.openstack.org/compute/ext/availabilityzone/api/v1.1"))
.put(URI.create(ExtensionNamespaces.VOLUME_ATTACHMENTS),
URI.create("http://docs.openstack.org/compute/ext/os-volume-attachment-update/api/v2"))
.put(URI.create(ExtensionNamespaces.ATTACH_INTERFACES),
URI.create("http://docs.openstack.org/compute/ext/interfaces/api/v1.1"))
.build();
// Intentionally private so subclasses use the Guice multibindings to contribute their aliases
private void bindDefaultAliases() {
MapBinder<URI, URI> aliases = aliasBinder(binder());
aliases.addBinding(URI.create(ExtensionNamespaces.SECURITY_GROUPS)).toInstance(
URI.create("http://docs.openstack.org/compute/ext/securitygroups/api/v1.1"));
aliases.addBinding(URI.create(ExtensionNamespaces.FLOATING_IPS)).toInstance(
URI.create("http://docs.openstack.org/compute/ext/floating_ips/api/v1.1"));
aliases.addBinding(URI.create(ExtensionNamespaces.KEYPAIRS)).toInstance(
URI.create("http://docs.openstack.org/compute/ext/keypairs/api/v1.1"));
aliases.addBinding(URI.create(ExtensionNamespaces.SIMPLE_TENANT_USAGE)).toInstance(
URI.create("http://docs.openstack.org/compute/ext/os-simple-tenant-usage/api/v1.1"));
aliases.addBinding(URI.create(ExtensionNamespaces.HOSTS)).toInstance(
URI.create("http://docs.openstack.org/compute/ext/hosts/api/v1.1"));
aliases.addBinding(URI.create(ExtensionNamespaces.VOLUMES)).toInstance(
URI.create("http://docs.openstack.org/compute/ext/volumes/api/v1.1"));
aliases.addBinding(URI.create(ExtensionNamespaces.VIRTUAL_INTERFACES)).toInstance(
URI.create("http://docs.openstack.org/compute/ext/virtual_interfaces/api/v1.1"));
aliases.addBinding(URI.create(ExtensionNamespaces.CREATESERVEREXT)).toInstance(
URI.create("http://docs.openstack.org/compute/ext/createserverext/api/v1.1"));
aliases.addBinding(URI.create(ExtensionNamespaces.ADMIN_ACTIONS)).toInstance(
URI.create("http://docs.openstack.org/compute/ext/admin-actions/api/v1.1"));
aliases.addBinding(URI.create(ExtensionNamespaces.AGGREGATES)).toInstance(
URI.create("http://docs.openstack.org/compute/ext/aggregates/api/v1.1"));
aliases.addBinding(URI.create(ExtensionNamespaces.FLAVOR_EXTRA_SPECS)).toInstance(
URI.create("http://docs.openstack.org/compute/ext/flavor_extra_specs/api/v1.1"));
aliases.addBinding(URI.create(ExtensionNamespaces.QUOTAS)).toInstance(
URI.create("http://docs.openstack.org/compute/ext/quotas-sets/api/v1.1"));
aliases.addBinding(URI.create(ExtensionNamespaces.VOLUME_TYPES)).toInstance(
URI.create("http://docs.openstack.org/compute/ext/volume_types/api/v1.1"));
aliases.addBinding(URI.create(ExtensionNamespaces.AVAILABILITY_ZONE)).toInstance(
URI.create("http://docs.openstack.org/compute/ext/availabilityzone/api/v1.1"));
aliases.addBinding(URI.create(ExtensionNamespaces.VOLUME_ATTACHMENTS)).toInstance(
URI.create("http://docs.openstack.org/compute/ext/os-volume-attachment-update/api/v2"));
aliases.addBinding(URI.create(ExtensionNamespaces.ATTACH_INTERFACES)).toInstance(
URI.create("http://docs.openstack.org/compute/ext/interfaces/api/v1.1"));
}
@Provides
@ -104,7 +104,7 @@ public class NovaHttpApiModule extends HttpApiModule<NovaApi> {
return CacheBuilder.newBuilder().expireAfterWrite(23, TimeUnit.HOURS)
.build(new CacheLoader<String, Set<? extends Extension>>() {
@Override
public Set<? extends Extension> load(String key) throws Exception {
public Set<? extends Extension> load(final String key) throws Exception {
return novaApi.get().getExtensionApi(key).list();
}
});

View File

@ -24,6 +24,7 @@ import java.util.concurrent.TimeoutException;
import org.jclouds.ContextBuilder;
import org.jclouds.openstack.cinder.v1.CinderApi;
import org.jclouds.openstack.cinder.v1.CinderApiMetadata;
import org.jclouds.openstack.cinder.v1.domain.Volume;
import org.jclouds.openstack.cinder.v1.features.VolumeApi;
import org.jclouds.openstack.cinder.v1.options.CreateVolumeOptions;
@ -49,6 +50,7 @@ public class VolumeAttachmentApiLiveTest extends BaseNovaApiLiveTest {
private Server server;
protected String volumeProvider;
protected String volumeProviderVersion;
protected int volumeSizeGB;
protected String deviceId = "/dev/wtf";
@ -56,6 +58,8 @@ public class VolumeAttachmentApiLiveTest extends BaseNovaApiLiveTest {
protected Properties setupProperties() {
Properties props = super.setupProperties();
volumeProvider = setIfTestSystemPropertyPresent(props, provider + ".volume-provider", "openstack-cinder");
volumeProviderVersion = setIfTestSystemPropertyPresent(props, provider + ".volume-provider-version",
new CinderApiMetadata().getVersion());
volumeSizeGB = Integer.parseInt(setIfTestSystemPropertyPresent(props, provider + ".volume-size-gb", "1"));
singleRegion = setIfTestSystemPropertyPresent(props, provider + ".region", "RegionOne");
return props;
@ -71,6 +75,7 @@ public class VolumeAttachmentApiLiveTest extends BaseNovaApiLiveTest {
if ("openstack-cinder".equals(volumeProvider)) {
cinderApi = ContextBuilder.newBuilder(volumeProvider)
.endpoint(endpoint)
.apiVersion(volumeProviderVersion)
.credentials(identity, credential)
.buildApi(CinderApi.class);
}

View File

@ -55,12 +55,10 @@
<dependency>
<groupId>com.google.inject.extensions</groupId>
<artifactId>guice-assistedinject</artifactId>
<version>3.0</version>
</dependency>
<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
<version>3.0</version>
</dependency>
<dependency>
<groupId>org.99soft.guice</groupId>

View File

@ -206,6 +206,7 @@
<maven.site.url.base>gitsite:git@github.com/jclouds/jclouds-maven-site.git</maven.site.url.base>
<clojure.version>1.3.0</clojure.version>
<guava.version>16.0.1</guava.version>
<guice.version>3.0</guice.version>
<okhttp.version>2.2.0</okhttp.version>
<surefire.version>2.17</surefire.version>
<assertj-core.version>1.7.0</assertj-core.version>
@ -246,6 +247,21 @@
<artifactId>guava</artifactId>
<version>${guava.version}</version>
</dependency>
<dependency>
<groupId>com.google.inject.extensions</groupId>
<artifactId>guice-assistedinject</artifactId>
<version>${guice.version}</version>
</dependency>
<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
<version>${guice.version}</version>
</dependency>
<dependency>
<groupId>com.google.inject.extensions</groupId>
<artifactId>guice-multibindings</artifactId>
<version>${guice.version}</version>
</dependency>
<dependency>
<groupId>org.easymock</groupId>
<artifactId>easymockclassextension</artifactId>

View File

@ -55,6 +55,11 @@
<artifactId>openstack-nova</artifactId>
<version>${project.version}</version>
</dependency>
<!-- for the extension namespaces -->
<dependency>
<groupId>com.google.inject.extensions</groupId>
<artifactId>guice-multibindings</artifactId>
</dependency>
<dependency>
<groupId>org.apache.jclouds</groupId>
<artifactId>jclouds-core</artifactId>
@ -95,6 +100,12 @@
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.jclouds.api</groupId>
<artifactId>openstack-cinder</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>

View File

@ -26,13 +26,13 @@ import static org.jclouds.openstack.nova.v2_0.config.NovaProperties.AUTO_GENERAT
import java.net.URI;
import java.util.Properties;
import org.jclouds.hpcloud.compute.config.HPCloudComputeHttpApiModule;
import org.jclouds.hpcloud.compute.config.HPCloudComputeServiceContextModule;
import org.jclouds.openstack.keystone.v2_0.config.AuthenticationApiModule;
import org.jclouds.openstack.keystone.v2_0.config.CredentialTypes;
import org.jclouds.openstack.keystone.v2_0.config.KeystoneAuthenticationModule;
import org.jclouds.openstack.keystone.v2_0.config.KeystoneAuthenticationModule.RegionModule;
import org.jclouds.openstack.nova.v2_0.NovaApiMetadata;
import org.jclouds.openstack.nova.v2_0.config.NovaHttpApiModule;
import org.jclouds.openstack.nova.v2_0.config.NovaParserModule;
import org.jclouds.providers.ProviderMetadata;
import org.jclouds.providers.internal.BaseProviderMetadata;
@ -95,7 +95,7 @@ public class HPCloudComputeProviderMetadata extends BaseProviderMetadata {
.add(KeystoneAuthenticationModule.class)
.add(RegionModule.class)
.add(NovaParserModule.class)
.add(NovaHttpApiModule.class)
.add(HPCloudComputeHttpApiModule.class)
.add(HPCloudComputeServiceContextModule.class).build())
.build())
.homepage(URI.create("http://hpcloud.com"))

View File

@ -0,0 +1,40 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.hpcloud.compute.config;
import static org.jclouds.openstack.keystone.v2_0.config.KeystoneHttpApiModule.aliasBinder;
import java.net.URI;
import org.jclouds.openstack.nova.v2_0.config.NovaHttpApiModule;
import org.jclouds.openstack.nova.v2_0.extensions.ExtensionNamespaces;
import org.jclouds.rest.ConfiguresHttpApi;
import com.google.inject.multibindings.MapBinder;
@ConfiguresHttpApi
public class HPCloudComputeHttpApiModule extends NovaHttpApiModule {
@Override
protected void configure() {
super.configure();
MapBinder<URI, URI> aliases = aliasBinder(binder());
aliases.addBinding(URI.create(ExtensionNamespaces.VOLUME_ATTACHMENTS)).toInstance(
URI.create("http://docs.openstack.org/compute/ext/volumes/api/v1.1"));
}
}

View File

@ -0,0 +1,45 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.hpcloud.compute.extensions;
import java.util.Properties;
import org.jclouds.hpcloud.compute.HPCloudComputeProviderMetadata;
import org.jclouds.openstack.keystone.v2_0.config.CredentialTypes;
import org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties;
import org.jclouds.openstack.nova.v2_0.extensions.VolumeAttachmentApiLiveTest;
import org.testng.annotations.Test;
@Test(groups = "live", testName = "HPCloudComputeVolumeAttachmentExtensionLiveTest", singleThreaded = true)
public class HPCloudComputeVolumeAttachmentExtensionLiveTest extends VolumeAttachmentApiLiveTest {
public HPCloudComputeVolumeAttachmentExtensionLiveTest() {
HPCloudComputeProviderMetadata metadata = new HPCloudComputeProviderMetadata();
provider = metadata.getId();
System.setProperty("test." + provider + ".endpoint", metadata.getEndpoint());
System.setProperty(KeystoneProperties.CREDENTIAL_TYPE, CredentialTypes.API_ACCESS_KEY_CREDENTIALS);
}
@Override
protected Properties setupProperties() {
Properties props = super.setupProperties();
volumeProviderVersion = setIfTestSystemPropertyPresent(props, provider + ".volume-provider-version", "1.0");
singleRegion = setIfTestSystemPropertyPresent(props, provider + ".region", "region-a.geo-1");
return props;
}
}

View File

@ -53,6 +53,11 @@
<artifactId>openstack-nova</artifactId>
<version>${project.version}</version>
</dependency>
<!-- for the extension namespaces -->
<dependency>
<groupId>com.google.inject.extensions</groupId>
<artifactId>guice-multibindings</artifactId>
</dependency>
<dependency>
<groupId>org.apache.jclouds</groupId>
<artifactId>jclouds-core</artifactId>
@ -110,6 +115,12 @@
<artifactId>auto-service</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.apache.jclouds.provider</groupId>
<artifactId>rackspace-cloudblockstorage-uk</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<profiles>

View File

@ -27,7 +27,6 @@ import java.util.Properties;
import org.jclouds.openstack.keystone.v2_0.config.KeystoneAuthenticationModule.RegionModule;
import org.jclouds.openstack.nova.v2_0.NovaApiMetadata;
import org.jclouds.openstack.nova.v2_0.config.NovaHttpApiModule;
import org.jclouds.openstack.nova.v2_0.config.NovaParserModule;
import org.jclouds.providers.ProviderMetadata;
import org.jclouds.providers.internal.BaseProviderMetadata;
@ -35,6 +34,7 @@ import org.jclouds.rackspace.cloudidentity.v2_0.config.CloudIdentityAuthenticati
import org.jclouds.rackspace.cloudidentity.v2_0.config.CloudIdentityAuthenticationModule;
import org.jclouds.rackspace.cloudidentity.v2_0.config.CloudIdentityCredentialTypes;
import org.jclouds.rackspace.cloudservers.uk.config.CloudServersUKComputeServiceContextModule;
import org.jclouds.rackspace.cloudservers.uk.config.CloudServersUKHttpApiModule;
import com.google.auto.service.AutoService;
import com.google.common.collect.ImmutableSet;
@ -89,7 +89,7 @@ public class CloudServersUKProviderMetadata extends BaseProviderMetadata {
.add(CloudIdentityAuthenticationModule.class)
.add(RegionModule.class)
.add(NovaParserModule.class)
.add(NovaHttpApiModule.class)
.add(CloudServersUKHttpApiModule.class)
.add(CloudServersUKComputeServiceContextModule.class).build())
.build())
.homepage(URI.create("http://www.rackspace.co.uk/opencloud"))

View File

@ -0,0 +1,43 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.rackspace.cloudservers.uk.config;
import static org.jclouds.openstack.keystone.v2_0.config.KeystoneHttpApiModule.aliasBinder;
import java.net.URI;
import org.jclouds.openstack.nova.v2_0.config.NovaHttpApiModule;
import org.jclouds.openstack.nova.v2_0.extensions.ExtensionNamespaces;
import org.jclouds.rest.ConfiguresHttpApi;
import com.google.inject.multibindings.MapBinder;
/**
* Configures the Rackspace connection.
*/
@ConfiguresHttpApi
public class CloudServersUKHttpApiModule extends NovaHttpApiModule {
@Override
protected void configure() {
super.configure();
MapBinder<URI, URI> aliases = aliasBinder(binder());
aliases.addBinding(URI.create(ExtensionNamespaces.VOLUME_ATTACHMENTS)).toInstance(
URI.create("http://docs.openstack.org/compute/ext/volumes/api/v1.1"));
}
}

View File

@ -0,0 +1,42 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.rackspace.cloudservers.uk.compute.extensions;
import java.util.Properties;
import org.jclouds.openstack.nova.v2_0.extensions.VolumeAttachmentApiLiveTest;
import org.testng.annotations.Test;
@Test(groups = "live", singleThreaded = true, testName = "CloudServersUKVolumeAttachmentExtensionLiveTest")
public class CloudServersUKVolumeAttachmentExtensionLiveTest extends VolumeAttachmentApiLiveTest {
public CloudServersUKVolumeAttachmentExtensionLiveTest() {
provider = "rackspace-cloudservers-uk";
// Specifying a device currently does not work for rackspace and causes issues
deviceId = "";
}
@Override
protected Properties setupProperties() {
Properties props = super.setupProperties();
volumeProvider = "rackspace-cloudblockstorage-uk";
volumeSizeGB = 80;
singleRegion = "LON";
return props;
}
}

View File

@ -53,6 +53,11 @@
<artifactId>openstack-nova</artifactId>
<version>${project.version}</version>
</dependency>
<!-- for the extension namespaces -->
<dependency>
<groupId>com.google.inject.extensions</groupId>
<artifactId>guice-multibindings</artifactId>
</dependency>
<dependency>
<groupId>org.apache.jclouds</groupId>
<artifactId>jclouds-core</artifactId>

View File

@ -16,109 +16,29 @@
*/
package org.jclouds.rackspace.cloudservers.us.config;
import static org.jclouds.openstack.keystone.v2_0.config.KeystoneHttpApiModule.aliasBinder;
import java.net.URI;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import javax.inject.Provider;
import javax.inject.Singleton;
import org.jclouds.http.HttpErrorHandler;
import org.jclouds.http.annotation.ClientError;
import org.jclouds.http.annotation.Redirection;
import org.jclouds.http.annotation.ServerError;
import org.jclouds.openstack.nova.v2_0.NovaApi;
import org.jclouds.openstack.nova.v2_0.config.NovaHttpApiModule;
import org.jclouds.openstack.nova.v2_0.extensions.ExtensionNamespaces;
import org.jclouds.openstack.nova.v2_0.handlers.NovaErrorHandler;
import org.jclouds.openstack.v2_0.domain.Extension;
import org.jclouds.openstack.v2_0.functions.PresentWhenExtensionAnnotationNamespaceEqualsAnyNamespaceInExtensionsSet;
import org.jclouds.rest.ConfiguresHttpApi;
import org.jclouds.rest.config.HttpApiModule;
import org.jclouds.rest.functions.ImplicitOptionalConverter;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.Multimap;
import com.google.inject.Provides;
import com.google.inject.multibindings.MapBinder;
/**
* Configures the Rackspace connection.
*
*/
@ConfiguresHttpApi
public class CloudServersUSHttpApiModule extends HttpApiModule<NovaApi> {
public CloudServersUSHttpApiModule() {
}
public class CloudServersUSHttpApiModule extends NovaHttpApiModule {
@Override
protected void configure() {
bind(ImplicitOptionalConverter.class).to(PresentWhenExtensionAnnotationNamespaceEqualsAnyNamespaceInExtensionsSet.class);
super.configure();
MapBinder<URI, URI> aliases = aliasBinder(binder());
aliases.addBinding(URI.create(ExtensionNamespaces.VOLUME_ATTACHMENTS)).toInstance(
URI.create("http://docs.openstack.org/compute/ext/volumes/api/v1.1"));
}
@Provides
@Singleton
public Multimap<URI, URI> aliases() {
return ImmutableMultimap.<URI, URI>builder()
.put(URI.create(ExtensionNamespaces.SECURITY_GROUPS),
URI.create("http://docs.openstack.org/compute/ext/securitygroups/api/v1.1"))
.put(URI.create(ExtensionNamespaces.FLOATING_IPS),
URI.create("http://docs.openstack.org/compute/ext/floating_ips/api/v1.1"))
.put(URI.create(ExtensionNamespaces.KEYPAIRS),
URI.create("http://docs.openstack.org/compute/ext/keypairs/api/v1.1"))
.put(URI.create(ExtensionNamespaces.SIMPLE_TENANT_USAGE),
URI.create("http://docs.openstack.org/compute/ext/os-simple-tenant-usage/api/v1.1"))
.put(URI.create(ExtensionNamespaces.HOSTS),
URI.create("http://docs.openstack.org/compute/ext/hosts/api/v1.1"))
.put(URI.create(ExtensionNamespaces.VOLUMES),
URI.create("http://docs.openstack.org/compute/ext/volumes/api/v1.1"))
.put(URI.create(ExtensionNamespaces.VIRTUAL_INTERFACES),
URI.create("http://docs.openstack.org/compute/ext/virtual_interfaces/api/v1.1"))
.put(URI.create(ExtensionNamespaces.CREATESERVEREXT),
URI.create("http://docs.openstack.org/compute/ext/createserverext/api/v1.1"))
.put(URI.create(ExtensionNamespaces.ADMIN_ACTIONS),
URI.create("http://docs.openstack.org/compute/ext/admin-actions/api/v1.1"))
.put(URI.create(ExtensionNamespaces.AGGREGATES),
URI.create("http://docs.openstack.org/compute/ext/aggregates/api/v1.1"))
.put(URI.create(ExtensionNamespaces.FLAVOR_EXTRA_SPECS),
URI.create("http://docs.openstack.org/compute/ext/flavor_extra_specs/api/v1.1"))
.put(URI.create(ExtensionNamespaces.QUOTAS),
URI.create("http://docs.openstack.org/compute/ext/quotas-sets/api/v1.1"))
.put(URI.create(ExtensionNamespaces.VOLUME_TYPES),
URI.create("http://docs.openstack.org/compute/ext/volume_types/api/v1.1"))
.put(URI.create(ExtensionNamespaces.AVAILABILITY_ZONE),
URI.create("http://docs.openstack.org/compute/ext/availabilityzone/api/v1.1"))
/**
* Only change - this is to ensure that for rackspace, the extension detection for
* VOLUME_ATTACHMENTS is based on discovering this namespace (VOLUMES).
*/
.put(URI.create(ExtensionNamespaces.VOLUME_ATTACHMENTS),
//URI.create("http://docs.openstack.org/compute/ext/os-volume-attachment-update/api/v2"))
URI.create("http://docs.openstack.org/compute/ext/volumes/api/v1.1"))
.put(URI.create(ExtensionNamespaces.ATTACH_INTERFACES),
URI.create("http://docs.openstack.org/compute/ext/interfaces/api/v1.1"))
.build();
}
@Provides
@Singleton
public LoadingCache<String, Set<? extends Extension>> provideExtensionsByRegion(final Provider<NovaApi> novaApi) {
return CacheBuilder.newBuilder().expireAfterWrite(23, TimeUnit.HOURS)
.build(new CacheLoader<String, Set<? extends Extension>>() {
@Override
public Set<? extends Extension> load(String key) throws Exception {
return novaApi.get().getExtensionApi(key).list();
}
});
}
@Override
protected void bindErrorHandlers() {
bind(HttpErrorHandler.class).annotatedWith(Redirection.class).to(NovaErrorHandler.class);
bind(HttpErrorHandler.class).annotatedWith(ClientError.class).to(NovaErrorHandler.class);
bind(HttpErrorHandler.class).annotatedWith(ServerError.class).to(NovaErrorHandler.class);
}
}