Enhance the way openstack extensions are resolved. Needed for new openstack versions.

This commit is contained in:
Zack Shoylev 2016-02-11 16:49:59 -06:00
parent 27b3a844f8
commit c8bbb44f37
4 changed files with 56 additions and 38 deletions

View File

@ -36,7 +36,7 @@ import org.jclouds.openstack.keystone.v2_0.suppliers.RegionIdToAdminURIFromAcces
import org.jclouds.openstack.keystone.v2_0.suppliers.RegionIdToAdminURISupplier;
import org.jclouds.openstack.v2_0.ServiceType;
import org.jclouds.openstack.v2_0.domain.Extension;
import org.jclouds.openstack.v2_0.functions.PresentWhenExtensionAnnotationNamespaceEqualsAnyNamespaceInExtensionsSet;
import org.jclouds.openstack.v2_0.functions.PresentWhenExtensionAnnotationMatchesExtensionSet;
import org.jclouds.openstack.v2_0.services.Identity;
import org.jclouds.rest.ConfiguresHttpApi;
import org.jclouds.rest.annotations.ApiVersion;
@ -98,7 +98,7 @@ public class KeystoneHttpApiModule extends HttpApiModule<KeystoneApi> {
@Override
protected void configure() {
bind(ImplicitOptionalConverter.class).to(PresentWhenExtensionAnnotationNamespaceEqualsAnyNamespaceInExtensionsSet.class);
bind(ImplicitOptionalConverter.class).to(PresentWhenExtensionAnnotationMatchesExtensionSet.class);
super.configure();
namespaceAliasBinder(binder());
}

View File

@ -18,6 +18,7 @@ package org.jclouds.openstack.v2_0.functions;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.collect.Iterables.any;
import static org.jclouds.openstack.v2_0.predicates.ExtensionPredicates.aliasEquals;
import static org.jclouds.openstack.v2_0.predicates.ExtensionPredicates.nameEquals;
import static org.jclouds.openstack.v2_0.predicates.ExtensionPredicates.namespaceOrAliasEquals;
import static org.jclouds.util.Optionals2.unwrapIfOptional;
@ -42,19 +43,46 @@ import com.google.common.collect.Sets;
/**
* We use the annotation {@link Extension} to bind a class that implements an extension
* API to an {@link Extension}.
*
* Match in the following order:
*
* 1. Match by namespace
* 2. Match by namespace aliases
* 3. Match by alias
* 4. Match by name
*
* New versions of openstack have no namespaces anymore.
* Alias is different than a namespace alias - it's an alternative namespace URL to match against.
*/
public class PresentWhenExtensionAnnotationNamespaceEqualsAnyNamespaceInExtensionsSet implements
public class PresentWhenExtensionAnnotationMatchesExtensionSet implements
ImplicitOptionalConverter {
private final LoadingCache<String, Set<? extends Extension>> extensions;
private final Map<URI, Set<URI>> aliases;
@Inject
PresentWhenExtensionAnnotationNamespaceEqualsAnyNamespaceInExtensionsSet(
PresentWhenExtensionAnnotationMatchesExtensionSet(
LoadingCache<String, Set<? extends Extension>> extensions, @NamespaceAliases Map<URI, Set<URI>> aliases) {
this.extensions = extensions;
this.aliases = aliases == null ? ImmutableMap.<URI, Set<URI>> of() : ImmutableMap.copyOf(aliases);
}
private boolean checkExtension(String invocationArg, URI namespace,
Set<URI> aliasesForNamespace, String alias, String name) {
if (any(extensions.getUnchecked(invocationArg), namespaceOrAliasEquals(namespace, aliasesForNamespace)))
return true;
// Could not find extension by namespace or namespace alias. Try to find it by alias next:
if ( !"".equals(alias)) {
if (any(extensions.getUnchecked(invocationArg), aliasEquals(alias)))
return true;
}
// Could not find extension by namespace or namespace alias or alias. Try to find it by name next:
if ( !"".equals(name)) {
if (any(extensions.getUnchecked(invocationArg), nameEquals(name)))
return true;
}
return false;
}
@Override
public Optional<Object> apply(InvocationSuccess input) {
Class<?> target = unwrapIfOptional(input.getInvocation().getInvokable().getReturnType());
@ -65,23 +93,16 @@ public class PresentWhenExtensionAnnotationNamespaceEqualsAnyNamespaceInExtensio
List<Object> args = input.getInvocation().getArgs();
Set<URI> aliasesForNamespace = aliases.containsKey(namespace) ? aliases.get(namespace) : Sets.<URI> newHashSet();
String name = ext.get().name();
String alias = ext.get().alias();
if (args.isEmpty()) {
if (any(extensions.getUnchecked(""), namespaceOrAliasEquals(namespace, aliasesForNamespace)))
if (checkExtension("", namespace, aliasesForNamespace, alias, name)) {
return input.getResult();
// Could not find extension by namespace or namespace alias. Try to find it by name next:
if ( !"".equals(name)) {
if (any(extensions.getUnchecked(""), nameEquals(name)))
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, aliasesForNamespace)))
if (checkExtension(arg0, namespace, aliasesForNamespace, alias, name)) {
return input.getResult();
// Could not find extension by namespace or namespace alias. Try to find it by name next:
if (!"".equals(name)) {
if (any(extensions.getUnchecked(arg0), nameEquals(name)))
return input.getResult();
}
} else {
throw new RuntimeException(String.format("expecting zero or one args %s", input));
@ -96,7 +117,7 @@ public class PresentWhenExtensionAnnotationNamespaceEqualsAnyNamespaceInExtensio
@Override
public String toString() {
return "presentWhenExtensionAnnotationNamespaceEqualsAnyNamespaceInExtensionsSet()";
return "PresentWhenExtensionAnnotationMatchesExtensionSet()";
}
}

View File

@ -65,24 +65,16 @@ public class PresentWhenExtensionAnnotationNamespaceEqualsAnyNamespaceInExtensio
new SimpleDateFormatDateService().iso8601SecondsDateParse("2011-06-16T00:00:00+00:00")).description(
"Floating IPs support").build();
@org.jclouds.openstack.v2_0.services.Extension(of = ServiceType.COMPUTE, namespace = "http://docs.openstack.org/ext/floating_ips/api/v1.1")
@org.jclouds.openstack.v2_0.services.Extension(of = ServiceType.COMPUTE, name = "Floating_ips", alias = "os-floating-ips", namespace = "http://docs.openstack.org/ext/floating_ips/api/v1.1")
interface FloatingIPApi {
}
@org.jclouds.openstack.v2_0.services.Extension(of = ServiceType.COMPUTE, name = "Floating_ips", namespace = "http://docs.openstack.org/fake")
interface FloatingIPNamedApi {
}
interface NovaApi {
@Delegate
Optional<FloatingIPApi> getFloatingIPExtensionApi(String region);
@Delegate
Optional<FloatingIPNamedApi> getFloatingIPNamedExtensionApi(String region);
@Delegate
Optional<KeyPairApi> getKeyPairExtensionApi(String region);
@ -93,11 +85,6 @@ public class PresentWhenExtensionAnnotationNamespaceEqualsAnyNamespaceInExtensio
Invocation.create(method(NovaApi.class, "getFloatingIPExtensionApi", String.class), args), "foo");
}
InvocationSuccess getFloatingIPNamedExtension(List<Object> args) throws SecurityException, NoSuchMethodException {
return InvocationSuccess.create(
Invocation.create(method(NovaApi.class, "getFloatingIPNamedExtensionApi", String.class), args), "foo");
}
InvocationSuccess getKeyPairExtension(List<Object> args) throws SecurityException, NoSuchMethodException {
return InvocationSuccess.create(
Invocation.create(method(NovaApi.class, "getKeyPairExtensionApi", String.class), args), "foo");
@ -144,28 +131,38 @@ public class PresentWhenExtensionAnnotationNamespaceEqualsAnyNamespaceInExtensio
*
*/
public void testPresentWhenNameSpaceIsMissingAndMatchByNameOrAlias() throws SecurityException, NoSuchMethodException {
Extension floatingIpsWithFakeNamespace = floatingIps.toBuilder()
// Revert to alias
Extension floatingIpsWithMissingNamespace = floatingIps.toBuilder()
.namespace(URI.create("http://docs.openstack.org/ext/fake"))
.build();
// Revert to name
Extension floatingIpsWithMissingNamespaceAndAlias = floatingIps.toBuilder()
.namespace(URI.create("http://docs.openstack.org/ext/fake"))
.alias("fake")
.build();
Multimap<URI, URI> aliases = ImmutableMultimap.of();
assertEquals(whenExtensionsAndAliasesInRegionInclude("region", ImmutableSet.of(floatingIpsWithFakeNamespace), aliases).apply(
getFloatingIPNamedExtension(ImmutableList.<Object> of("region"))), Optional.of("foo"));
assertEquals(whenExtensionsAndAliasesInRegionInclude("region", ImmutableSet.of(floatingIpsWithMissingNamespace), aliases).apply(
getFloatingIPExtension(ImmutableList.<Object> of("region"))), Optional.of("foo"));
assertEquals(whenExtensionsAndAliasesInRegionInclude("region", ImmutableSet.of(floatingIpsWithMissingNamespaceAndAlias), aliases).apply(
getFloatingIPExtension(ImmutableList.<Object> of("region"))), Optional.of("foo"));
}
private PresentWhenExtensionAnnotationNamespaceEqualsAnyNamespaceInExtensionsSet whenExtensionsInRegionInclude(
private PresentWhenExtensionAnnotationMatchesExtensionSet whenExtensionsInRegionInclude(
String region, Extension... extensions) {
return whenExtensionsAndAliasesInRegionInclude(region, ImmutableSet.copyOf(extensions), ImmutableMultimap.<URI, URI> of());
}
private PresentWhenExtensionAnnotationNamespaceEqualsAnyNamespaceInExtensionsSet whenExtensionsAndAliasesInRegionInclude(
private PresentWhenExtensionAnnotationMatchesExtensionSet whenExtensionsAndAliasesInRegionInclude(
String region, final Set<Extension> extensions, final Multimap<URI, URI> aliases) {
final LoadingCache<String, Set<? extends Extension>> extensionsForRegion = CacheBuilder.newBuilder().build(
CacheLoader.from(Functions.forMap(ImmutableMap.<String, Set<? extends Extension>>of(region, extensions, "differentregion",
ImmutableSet.<Extension> of()))));
PresentWhenExtensionAnnotationNamespaceEqualsAnyNamespaceInExtensionsSet fn = Guice.createInjector(
PresentWhenExtensionAnnotationMatchesExtensionSet fn = Guice.createInjector(
new AbstractModule() {
@Override
protected void configure() {
@ -183,7 +180,7 @@ public class PresentWhenExtensionAnnotationNamespaceEqualsAnyNamespaceInExtensio
return extensionsForRegion;
}
}).getInstance(PresentWhenExtensionAnnotationNamespaceEqualsAnyNamespaceInExtensionsSet.class);
}).getInstance(PresentWhenExtensionAnnotationMatchesExtensionSet.class);
return fn;
}

View File

@ -29,7 +29,7 @@ import org.jclouds.openstack.nova.v2_0.NovaApi;
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.openstack.v2_0.functions.PresentWhenExtensionAnnotationMatchesExtensionSet;
import org.jclouds.rest.ConfiguresHttpApi;
import org.jclouds.rest.config.HttpApiModule;
import org.jclouds.rest.functions.ImplicitOptionalConverter;
@ -54,7 +54,7 @@ public class NovaHttpApiModule extends HttpApiModule<NovaApi> {
@Override
protected void configure() {
bind(ImplicitOptionalConverter.class).to(PresentWhenExtensionAnnotationNamespaceEqualsAnyNamespaceInExtensionsSet.class);
bind(ImplicitOptionalConverter.class).to(PresentWhenExtensionAnnotationMatchesExtensionSet.class);
super.configure();
bindDefaultAliases();
}