mirror of https://github.com/apache/jclouds.git
JCLOUDS-126 - Support and tests for region selection in swift-keystone BlobStore
This commit is contained in:
parent
335f5943f4
commit
8db0218cf7
|
@ -17,6 +17,7 @@
|
||||||
package org.jclouds.openstack.swift;
|
package org.jclouds.openstack.swift;
|
||||||
|
|
||||||
import static org.jclouds.location.reference.LocationConstants.PROPERTY_REGIONS;
|
import static org.jclouds.location.reference.LocationConstants.PROPERTY_REGIONS;
|
||||||
|
import static org.jclouds.location.reference.LocationConstants.PROPERTY_REGION;
|
||||||
import static org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties.CREDENTIAL_TYPE;
|
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.jclouds.openstack.keystone.v2_0.config.KeystoneProperties.SERVICE_TYPE;
|
||||||
|
|
||||||
|
@ -69,6 +70,7 @@ public class SwiftKeystoneApiMetadata extends SwiftApiMetadata {
|
||||||
Properties properties = SwiftApiMetadata.defaultProperties();
|
Properties properties = SwiftApiMetadata.defaultProperties();
|
||||||
properties.setProperty(SERVICE_TYPE, ServiceType.OBJECT_STORE);
|
properties.setProperty(SERVICE_TYPE, ServiceType.OBJECT_STORE);
|
||||||
properties.setProperty(CREDENTIAL_TYPE, CredentialTypes.PASSWORD_CREDENTIALS);
|
properties.setProperty(CREDENTIAL_TYPE, CredentialTypes.PASSWORD_CREDENTIALS);
|
||||||
|
properties.setProperty(PROPERTY_REGION, "");
|
||||||
properties.remove(PROPERTY_REGIONS);
|
properties.remove(PROPERTY_REGIONS);
|
||||||
return properties;
|
return properties;
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,18 +17,23 @@
|
||||||
package org.jclouds.openstack.swift.config;
|
package org.jclouds.openstack.swift.config;
|
||||||
import static org.jclouds.reflect.Reflection2.typeToken;
|
import static org.jclouds.reflect.Reflection2.typeToken;
|
||||||
import static org.jclouds.util.Suppliers2.getLastValueInMap;
|
import static org.jclouds.util.Suppliers2.getLastValueInMap;
|
||||||
|
import static org.jclouds.util.Suppliers2.getValueInMapOrNull;
|
||||||
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import javax.inject.Named;
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
import org.jclouds.http.HttpErrorHandler;
|
import org.jclouds.http.HttpErrorHandler;
|
||||||
import org.jclouds.http.annotation.ClientError;
|
import org.jclouds.http.annotation.ClientError;
|
||||||
import org.jclouds.http.annotation.Redirection;
|
import org.jclouds.http.annotation.Redirection;
|
||||||
import org.jclouds.http.annotation.ServerError;
|
import org.jclouds.http.annotation.ServerError;
|
||||||
|
import org.jclouds.javax.annotation.Nullable;
|
||||||
import org.jclouds.json.config.GsonModule.DateAdapter;
|
import org.jclouds.json.config.GsonModule.DateAdapter;
|
||||||
import org.jclouds.json.config.GsonModule.Iso8601DateAdapter;
|
import org.jclouds.json.config.GsonModule.Iso8601DateAdapter;
|
||||||
|
import org.jclouds.location.reference.LocationConstants;
|
||||||
import org.jclouds.location.suppliers.RegionIdToURISupplier;
|
import org.jclouds.location.suppliers.RegionIdToURISupplier;
|
||||||
import org.jclouds.openstack.config.OpenStackAuthenticationModule;
|
import org.jclouds.openstack.config.OpenStackAuthenticationModule;
|
||||||
import org.jclouds.openstack.functions.URIFromAuthenticationResponseForService;
|
import org.jclouds.openstack.functions.URIFromAuthenticationResponseForService;
|
||||||
|
@ -45,8 +50,14 @@ import org.jclouds.rest.ConfiguresRestClient;
|
||||||
import org.jclouds.rest.annotations.ApiVersion;
|
import org.jclouds.rest.annotations.ApiVersion;
|
||||||
import org.jclouds.rest.config.RestClientModule;
|
import org.jclouds.rest.config.RestClientModule;
|
||||||
|
|
||||||
|
import com.google.common.base.Function;
|
||||||
|
import com.google.common.base.Functions;
|
||||||
|
import com.google.common.base.Predicates;
|
||||||
|
import com.google.common.base.Strings;
|
||||||
import com.google.common.base.Supplier;
|
import com.google.common.base.Supplier;
|
||||||
|
import com.google.common.base.Suppliers;
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
import com.google.common.collect.Maps;
|
||||||
import com.google.common.reflect.TypeToken;
|
import com.google.common.reflect.TypeToken;
|
||||||
import com.google.inject.Provides;
|
import com.google.inject.Provides;
|
||||||
import com.google.inject.Scopes;
|
import com.google.inject.Scopes;
|
||||||
|
@ -80,14 +91,25 @@ public class SwiftRestClientModule<S extends CommonSwiftClient, A extends Common
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class KeystoneStorageEndpointModule extends KeystoneAuthenticationModule {
|
public static class KeystoneStorageEndpointModule extends KeystoneAuthenticationModule {
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
@Storage
|
@Storage
|
||||||
protected Supplier<URI> provideStorageUrl(RegionIdToURISupplier.Factory factory, @ApiVersion String apiVersion) {
|
protected Supplier<URI> provideStorageUrl(RegionIdToURISupplier.Factory factory,
|
||||||
return getLastValueInMap(factory.createForApiTypeAndVersion(ServiceType.OBJECT_STORE, apiVersion));
|
@ApiVersion String apiVersion,
|
||||||
}
|
@Named(LocationConstants.PROPERTY_REGION) String region) {
|
||||||
|
|
||||||
|
//Get the URI's keyed by their region name
|
||||||
|
Supplier<Map<String, Supplier<URI>>> endpointsSupplier = factory.createForApiTypeAndVersion(ServiceType.OBJECT_STORE, apiVersion);
|
||||||
|
|
||||||
|
//Pick the matching region name (if any) otherwise just return an arbitrary URL if no region name is set
|
||||||
|
//NOTE: The region string should never be null (it can be empty) if this object was instantiated via guice
|
||||||
|
// as it pulls these named strings from a Properties object.
|
||||||
|
if (region.isEmpty()) {
|
||||||
|
return getLastValueInMap(endpointsSupplier);
|
||||||
|
} else {
|
||||||
|
return getValueInMapOrNull(endpointsSupplier, region);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -0,0 +1,131 @@
|
||||||
|
/*
|
||||||
|
* 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.swift.config;
|
||||||
|
|
||||||
|
import static org.easymock.EasyMock.createStrictMock;
|
||||||
|
import static org.easymock.EasyMock.replay;
|
||||||
|
import static org.easymock.EasyMock.expect;
|
||||||
|
|
||||||
|
import static org.testng.Assert.assertEquals;
|
||||||
|
import static org.testng.Assert.assertNotNull;
|
||||||
|
import static org.testng.Assert.assertNull;
|
||||||
|
import static org.testng.Assert.assertTrue;
|
||||||
|
import static org.testng.Assert.fail;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.jclouds.location.suppliers.RegionIdToURISupplier;
|
||||||
|
import org.jclouds.openstack.services.ServiceType;
|
||||||
|
import org.jclouds.openstack.swift.config.SwiftRestClientModule.KeystoneStorageEndpointModule;
|
||||||
|
import org.testng.annotations.BeforeTest;
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
import com.google.common.base.Supplier;
|
||||||
|
import com.google.common.base.Suppliers;
|
||||||
|
|
||||||
|
@Test(groups = "unit")
|
||||||
|
public class KeystoneStorageEndpointModuleTest {
|
||||||
|
|
||||||
|
private final String apiVersion = "9.8.7";
|
||||||
|
private final RegionIdToURISupplier.Factory mockFactory = createStrictMock(RegionIdToURISupplier.Factory.class);
|
||||||
|
private final RegionIdToURISupplier mockSupplier = createStrictMock(RegionIdToURISupplier.class);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setup the expectations for our mock factory to return 3 region urls keyed
|
||||||
|
* by test region names
|
||||||
|
*/
|
||||||
|
@BeforeTest
|
||||||
|
public void setup() {
|
||||||
|
Map<String, Supplier<URI>> endpoints = new HashMap<String, Supplier<URI>>();
|
||||||
|
|
||||||
|
try {
|
||||||
|
endpoints.put("region1", Suppliers.ofInstance(new URI("http://region1.example.org/")));
|
||||||
|
endpoints.put("region2", Suppliers.ofInstance(new URI("http://region2.example.org/")));
|
||||||
|
endpoints.put("region3", Suppliers.ofInstance(new URI("http://region3.example.org/")));
|
||||||
|
} catch (URISyntaxException ex) {
|
||||||
|
fail("static test Strings do not parse to URI: " + ex.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(mockSupplier.get())
|
||||||
|
.andReturn(endpoints)
|
||||||
|
.anyTimes();
|
||||||
|
expect(mockFactory.createForApiTypeAndVersion(ServiceType.OBJECT_STORE,apiVersion))
|
||||||
|
.andReturn(mockSupplier)
|
||||||
|
.anyTimes();
|
||||||
|
|
||||||
|
replay(mockSupplier);
|
||||||
|
replay(mockFactory);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that specifying an empty region will return an arbitrary URL
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testEmptyRegion() {
|
||||||
|
final KeystoneStorageEndpointModule moduleToTest = new KeystoneStorageEndpointModule();
|
||||||
|
|
||||||
|
// Test with an empty Region - just ensure we get either a region 1,2 or 3
|
||||||
|
// URI
|
||||||
|
Supplier<URI> resultingSupplier = moduleToTest.provideStorageUrl(mockFactory, apiVersion, "");
|
||||||
|
assertNotNull(resultingSupplier);
|
||||||
|
URI resultingUri = resultingSupplier.get();
|
||||||
|
assertNotNull(resultingUri);
|
||||||
|
|
||||||
|
// Without a region our choice is arbitrary. We can't enforce an ordering
|
||||||
|
// on the map
|
||||||
|
// as that varies from JVM to JVM - easier to just assume its one of the
|
||||||
|
// possible values
|
||||||
|
assertTrue(resultingUri.toString().equals("http://region1.example.org/")
|
||||||
|
|| resultingUri.toString().equals("http://region2.example.org/")
|
||||||
|
|| resultingUri.toString().equals("http://region3.example.org/"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that specifying a region will return the correct URL
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testSpecificRegion() {
|
||||||
|
final KeystoneStorageEndpointModule moduleToTest = new KeystoneStorageEndpointModule();
|
||||||
|
|
||||||
|
// Iterate through our region names
|
||||||
|
for (int i = 1; i <= 3; i++) {
|
||||||
|
Supplier<URI> resultingSupplier = moduleToTest.provideStorageUrl(mockFactory, apiVersion, String.format("region%1$s", i));
|
||||||
|
assertNotNull(resultingSupplier);
|
||||||
|
URI resultingUri = resultingSupplier.get();
|
||||||
|
assertNotNull(resultingUri);
|
||||||
|
|
||||||
|
assertEquals(resultingUri.toString(),
|
||||||
|
String.format("http://region%1$s.example.org/", i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that specifying an undefined region will return null
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testUndefinedRegion() {
|
||||||
|
final KeystoneStorageEndpointModule moduleToTest = new KeystoneStorageEndpointModule();
|
||||||
|
|
||||||
|
Supplier<URI> resultingSupplier = moduleToTest.provideStorageUrl(mockFactory, apiVersion, "region-that-dne");
|
||||||
|
assertNotNull(resultingSupplier);
|
||||||
|
URI resultingUri = resultingSupplier.get();
|
||||||
|
assertNull(resultingUri);
|
||||||
|
}
|
||||||
|
}
|
|
@ -47,6 +47,21 @@ public class Suppliers2 {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static <K, V> Supplier<V> getValueInMapOrNull(final Supplier<Map<K, Supplier<V>>> input, final K keyValue) {
|
||||||
|
return new Supplier<V>() {
|
||||||
|
@Override
|
||||||
|
public V get() {
|
||||||
|
Map<K, Supplier<V>> map = input.get();
|
||||||
|
return map.containsKey(keyValue) ? map.get(keyValue).get() : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return String.format("getValueInMapOrNull('%1$s')", keyValue);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
public static <X> Function<X, Supplier<X>> ofInstanceFunction() {
|
public static <X> Function<X, Supplier<X>> ofInstanceFunction() {
|
||||||
return new Function<X, Supplier<X>>() {
|
return new Function<X, Supplier<X>>() {
|
||||||
|
|
||||||
|
|
|
@ -37,6 +37,15 @@ public class Suppliers2Test {
|
||||||
Suppliers.ofInstance("bar")))).get(), "bar");
|
Suppliers.ofInstance("bar")))).get(), "bar");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetSpecificValueInMap() {
|
||||||
|
Supplier<Map<String, Supplier<String>>> testMap = Suppliers.<Map<String, Supplier<String>>> ofInstance(
|
||||||
|
ImmutableMap.of("foo", Suppliers.ofInstance("bar")));
|
||||||
|
|
||||||
|
assertEquals(Suppliers2.<String, String> getValueInMapOrNull(testMap, "foo").get(), "bar");
|
||||||
|
assertEquals(Suppliers2.<String, String> getValueInMapOrNull(testMap, "baz").get(), null);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testOfInstanceFunction() {
|
public void testOfInstanceFunction() {
|
||||||
assertEquals(Suppliers2.ofInstanceFunction().apply("foo").get(), "foo");
|
assertEquals(Suppliers2.ofInstanceFunction().apply("foo").get(), "foo");
|
||||||
|
|
Loading…
Reference in New Issue