mirror of https://github.com/apache/jclouds.git
JCLOUDS-607: ComputeService.createNodesInGroup throws NPE on FloatingIPApi.create()
This commit is contained in:
parent
f52a264b87
commit
7641bd61cd
|
@ -19,8 +19,9 @@ import static com.google.common.base.Preconditions.checkNotNull;
|
|||
import static com.google.common.base.Preconditions.checkState;
|
||||
import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_RUNNING;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
@ -32,6 +33,7 @@ import org.jclouds.compute.domain.NodeMetadataBuilder;
|
|||
import org.jclouds.compute.reference.ComputeServiceConstants;
|
||||
import org.jclouds.logging.Logger;
|
||||
import org.jclouds.openstack.nova.v2_0.NovaApi;
|
||||
import org.jclouds.openstack.nova.v2_0.compute.options.NodeAndNovaTemplateOptions;
|
||||
import org.jclouds.openstack.nova.v2_0.domain.FloatingIP;
|
||||
import org.jclouds.openstack.nova.v2_0.domain.zonescoped.ZoneAndId;
|
||||
import org.jclouds.openstack.nova.v2_0.extensions.FloatingIPApi;
|
||||
|
@ -39,6 +41,7 @@ import org.jclouds.rest.InsufficientResourcesException;
|
|||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Objects;
|
||||
import com.google.common.base.Optional;
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
|
@ -51,7 +54,7 @@ import com.google.common.collect.Lists;
|
|||
* @author Adrian Cole
|
||||
*/
|
||||
public class AllocateAndAddFloatingIpToNode implements
|
||||
Function<AtomicReference<NodeMetadata>, AtomicReference<NodeMetadata>> {
|
||||
Function<AtomicReference<NodeAndNovaTemplateOptions>, AtomicReference<NodeMetadata>> {
|
||||
|
||||
@Resource
|
||||
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
|
||||
|
@ -70,39 +73,77 @@ public class AllocateAndAddFloatingIpToNode implements
|
|||
}
|
||||
|
||||
@Override
|
||||
public AtomicReference<NodeMetadata> apply(AtomicReference<NodeMetadata> input) {
|
||||
checkState(nodeRunning.apply(input), "node never achieved state running %s", input.get());
|
||||
NodeMetadata node = input.get();
|
||||
public AtomicReference<NodeMetadata> apply(AtomicReference<NodeAndNovaTemplateOptions> input) {
|
||||
checkState(nodeRunning.apply(input.get().getNodeMetadata()), "node never achieved state running %s", input.get().getNodeMetadata());
|
||||
NodeMetadata node = input.get().getNodeMetadata().get();
|
||||
// node's location is a host
|
||||
String zoneId = node.getLocation().getParent().getId();
|
||||
FloatingIPApi floatingIpApi = novaApi.getFloatingIPExtensionForZone(zoneId).get();
|
||||
Optional<Set<String>> poolNames = input.get().getNovaTemplateOptions().get().getFloatingIpPoolNames();
|
||||
|
||||
Optional<FloatingIP> ip = allocateFloatingIPForNode(floatingIpApi, poolNames, node.getId());
|
||||
if (!ip.isPresent()) {
|
||||
throw new InsufficientResourcesException("Failed to allocate a FloatingIP for node(" + node.getId() + ")");
|
||||
}
|
||||
logger.debug(">> adding floatingIp(%s) to node(%s)", ip.get().getIp(), node.getId());
|
||||
|
||||
floatingIpApi.addToServer(ip.get().getIp(), node.getProviderId());
|
||||
input.get().getNodeMetadata().set(NodeMetadataBuilder.fromNodeMetadata(node).publicAddresses(ImmutableSet.of(ip.get().getIp())).build());
|
||||
floatingIpCache.invalidate(ZoneAndId.fromSlashEncoded(node.getId()));
|
||||
return input.get().getNodeMetadata();
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocates a FloatingIP for a given Node
|
||||
*
|
||||
* @param floatingIpApi FloatingIPApi to create or query for a valid FloatingIP
|
||||
* @param poolNames optional set of pool names from which we will attempt to allocate an IP from. Most cases this is null
|
||||
* @param nodeID optional id of the Node we are trying to allocate a FloatingIP for. Used here only for logging purposes
|
||||
* @return Optional<FloatingIP>
|
||||
*/
|
||||
private Optional<FloatingIP> allocateFloatingIPForNode(FloatingIPApi floatingIpApi, Optional<Set<String>> poolNames, String nodeID) {
|
||||
|
||||
FloatingIP ip = null;
|
||||
try {
|
||||
logger.debug(">> allocating or reassigning floating ip for node(%s)", node.getId());
|
||||
ip = floatingIpApi.create();
|
||||
} catch (InsufficientResourcesException e) {
|
||||
logger.trace("<< [%s] allocating a new floating ip for node(%s)", e.getMessage(), node.getId());
|
||||
logger.trace(">> searching for existing, unassigned floating ip for node(%s)", node.getId());
|
||||
ArrayList<FloatingIP> unassignedIps = Lists.newArrayList(Iterables.filter(floatingIpApi.list(),
|
||||
new Predicate<FloatingIP>() {
|
||||
|
||||
@Override
|
||||
public boolean apply(FloatingIP arg0) {
|
||||
return arg0.getFixedIp() == null;
|
||||
}
|
||||
|
||||
}));
|
||||
// try to prevent multiple parallel launches from choosing the same ip.
|
||||
Collections.shuffle(unassignedIps);
|
||||
ip = Iterables.getLast(unassignedIps);
|
||||
// 1.) Attempt to allocate from optionally passed poolNames
|
||||
if (poolNames.isPresent()) {
|
||||
for (String poolName : poolNames.get()){
|
||||
try {
|
||||
logger.debug(">> allocating floating IP from pool %s for node(%s)", poolName, nodeID);
|
||||
ip = floatingIpApi.allocateFromPool(poolName);
|
||||
if (ip != null)
|
||||
return Optional.of(ip);
|
||||
} catch (InsufficientResourcesException ire){
|
||||
logger.trace("<< [%s] failed to allocate floating IP from pool %s for node(%s)", ire.getMessage(), poolName, nodeID);
|
||||
}
|
||||
}
|
||||
}
|
||||
logger.debug(">> adding floatingIp(%s) to node(%s)", ip.getIp(), node.getId());
|
||||
|
||||
floatingIpApi.addToServer(ip.getIp(), node.getProviderId());
|
||||
input.set(NodeMetadataBuilder.fromNodeMetadata(node).publicAddresses(ImmutableSet.of(ip.getIp())).build());
|
||||
floatingIpCache.invalidate(ZoneAndId.fromSlashEncoded(node.getId()));
|
||||
return input;
|
||||
// 2.) Attempt to allocate, if necessary, via 'create()' call
|
||||
try {
|
||||
logger.debug(">> creating floating IP for node(%s)", nodeID);
|
||||
ip = floatingIpApi.create();
|
||||
if(ip != null)
|
||||
return Optional.of(ip);
|
||||
} catch (InsufficientResourcesException ire){
|
||||
logger.trace("<< [%s] failed to create floating IP for node(%s)", ire.getMessage(), nodeID);
|
||||
}
|
||||
|
||||
// 3.) If no IP was found make final attempt by searching through list of available IP's
|
||||
logger.trace(">> searching for existing, unassigned floating IP for node(%s)", nodeID);
|
||||
List<FloatingIP> unassignedIps = Lists.newArrayList(Iterables.filter(floatingIpApi.list(),
|
||||
new Predicate<FloatingIP>() {
|
||||
|
||||
@Override
|
||||
public boolean apply(FloatingIP arg0) {
|
||||
return arg0.getFixedIp() == null;
|
||||
}
|
||||
|
||||
}));
|
||||
// try to prevent multiple parallel launches from choosing the same ip.
|
||||
Collections.shuffle(unassignedIps);
|
||||
ip = Iterables.getLast(unassignedIps);
|
||||
return Optional.fromNullable(ip);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* 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.nova.v2_0.compute.options;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import org.jclouds.compute.domain.NodeMetadata;
|
||||
|
||||
import com.google.common.util.concurrent.Atomics;
|
||||
|
||||
/**
|
||||
* Simple data-structure for holding a NodeMetadata object along with a
|
||||
* corresponding NovaTemplateOptions object.
|
||||
*/
|
||||
public class NodeAndNovaTemplateOptions {
|
||||
|
||||
private final AtomicReference<NodeMetadata> nodeMetadata;
|
||||
private final AtomicReference<NovaTemplateOptions> novaTemplateOptions;
|
||||
|
||||
protected NodeAndNovaTemplateOptions(AtomicReference<NodeMetadata> nodeMetadata, AtomicReference<NovaTemplateOptions> novaTemplateOptions){
|
||||
this.nodeMetadata = nodeMetadata;
|
||||
this.novaTemplateOptions = novaTemplateOptions;
|
||||
}
|
||||
|
||||
public AtomicReference<NodeMetadata> getNodeMetadata() {
|
||||
return nodeMetadata;
|
||||
}
|
||||
|
||||
public AtomicReference<NovaTemplateOptions> getNovaTemplateOptions() {
|
||||
return novaTemplateOptions;
|
||||
}
|
||||
|
||||
public static NodeAndNovaTemplateOptions newReference(AtomicReference<NodeMetadata> node, AtomicReference<NovaTemplateOptions> options){
|
||||
return new NodeAndNovaTemplateOptions(node, options);
|
||||
}
|
||||
|
||||
public static AtomicReference<NodeAndNovaTemplateOptions> newAtomicReference(AtomicReference<NodeMetadata> node, AtomicReference<NovaTemplateOptions> options){
|
||||
return Atomics.newReference(NodeAndNovaTemplateOptions.newReference(node, options));
|
||||
}
|
||||
}
|
|
@ -66,6 +66,8 @@ public class NovaTemplateOptions extends TemplateOptions implements Cloneable {
|
|||
if (to instanceof NovaTemplateOptions) {
|
||||
NovaTemplateOptions eTo = NovaTemplateOptions.class.cast(to);
|
||||
eTo.autoAssignFloatingIp(shouldAutoAssignFloatingIp());
|
||||
if (getFloatingIpPoolNames().isPresent())
|
||||
eTo.floatingIpPoolNames(getFloatingIpPoolNames().get());
|
||||
if (getSecurityGroupNames().isPresent())
|
||||
eTo.securityGroupNames(getSecurityGroupNames().get());
|
||||
eTo.generateKeyPair(shouldGenerateKeyPair());
|
||||
|
@ -83,6 +85,7 @@ public class NovaTemplateOptions extends TemplateOptions implements Cloneable {
|
|||
}
|
||||
|
||||
protected boolean autoAssignFloatingIp = false;
|
||||
protected Optional<Set<String>> floatingIpPoolNames = Optional.absent();
|
||||
protected Optional<Set<String>> securityGroupNames = Optional.absent();
|
||||
protected boolean generateKeyPair = false;
|
||||
protected String keyPairName;
|
||||
|
@ -99,6 +102,7 @@ public class NovaTemplateOptions extends TemplateOptions implements Cloneable {
|
|||
return false;
|
||||
NovaTemplateOptions that = NovaTemplateOptions.class.cast(o);
|
||||
return super.equals(that) && equal(this.autoAssignFloatingIp, that.autoAssignFloatingIp)
|
||||
&& equal(this.floatingIpPoolNames, that.floatingIpPoolNames)
|
||||
&& equal(this.securityGroupNames, that.securityGroupNames)
|
||||
&& equal(this.generateKeyPair, that.generateKeyPair)
|
||||
&& equal(this.keyPairName, that.keyPairName)
|
||||
|
@ -110,7 +114,7 @@ public class NovaTemplateOptions extends TemplateOptions implements Cloneable {
|
|||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hashCode(super.hashCode(), autoAssignFloatingIp, securityGroupNames, generateKeyPair, keyPairName, userData, diskConfig, configDrive, novaNetworks);
|
||||
return Objects.hashCode(super.hashCode(), autoAssignFloatingIp, floatingIpPoolNames, securityGroupNames, generateKeyPair, keyPairName, userData, diskConfig, configDrive, novaNetworks);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -118,6 +122,8 @@ public class NovaTemplateOptions extends TemplateOptions implements Cloneable {
|
|||
ToStringHelper toString = super.string();
|
||||
if (!autoAssignFloatingIp)
|
||||
toString.add("autoAssignFloatingIp", autoAssignFloatingIp);
|
||||
if (floatingIpPoolNames.isPresent())
|
||||
toString.add("floatingIpPoolNames", floatingIpPoolNames.get());
|
||||
if (securityGroupNames.isPresent())
|
||||
toString.add("securityGroupNames", securityGroupNames.get());
|
||||
if (generateKeyPair)
|
||||
|
@ -133,13 +139,30 @@ public class NovaTemplateOptions extends TemplateOptions implements Cloneable {
|
|||
public static final NovaTemplateOptions NONE = new NovaTemplateOptions();
|
||||
|
||||
/**
|
||||
* @see #shouldAutoAssignFloatingIp()
|
||||
* @see #getFloatingIpPoolNames()
|
||||
*/
|
||||
public NovaTemplateOptions autoAssignFloatingIp(boolean enable) {
|
||||
this.autoAssignFloatingIp = enable;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #getFloatingIpPoolNames()
|
||||
*/
|
||||
public NovaTemplateOptions floatingIpPoolNames(String... floatingIpPoolNames) {
|
||||
return floatingIpPoolNames(ImmutableSet.copyOf(checkNotNull(floatingIpPoolNames, "floatingIpPoolNames")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #getFloatingIpPoolNames()
|
||||
*/
|
||||
public NovaTemplateOptions floatingIpPoolNames(Iterable<String> floatingIpPoolNames) {
|
||||
for (String groupName : checkNotNull(floatingIpPoolNames, "floatingIpPoolNames"))
|
||||
checkNotNull(emptyToNull(groupName), "all floating-ip-pool-names must be non-empty");
|
||||
this.floatingIpPoolNames = Optional.<Set<String>> of(ImmutableSet.copyOf(floatingIpPoolNames));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #shouldGenerateKeyPair()
|
||||
*/
|
||||
|
@ -186,6 +209,18 @@ public class NovaTemplateOptions extends TemplateOptions implements Cloneable {
|
|||
return autoAssignFloatingIp;
|
||||
}
|
||||
|
||||
/**
|
||||
* The floating IP pool name(s) to use when allocating a FloatingIP. Applicable
|
||||
* only if #shouldAutoAssignFloatingIp() returns true. If not set will attempt to
|
||||
* use whatever FloatingIP(s) can be found regardless of which pool they originated
|
||||
* from
|
||||
*
|
||||
* @return floating-ip-pool names to use
|
||||
*/
|
||||
public Optional<Set<String>> getFloatingIpPoolNames() {
|
||||
return floatingIpPoolNames;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the keypair used to run instances with
|
||||
* @return the keypair to be used
|
||||
|
@ -250,6 +285,22 @@ public class NovaTemplateOptions extends TemplateOptions implements Cloneable {
|
|||
return new NovaTemplateOptions().autoAssignFloatingIp(enable);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #getFloatingIpPoolNames()
|
||||
*/
|
||||
public NovaTemplateOptions floatingIpPoolNames(String... floatingIpPoolNames) {
|
||||
NovaTemplateOptions options = new NovaTemplateOptions();
|
||||
return NovaTemplateOptions.class.cast(options.floatingIpPoolNames(floatingIpPoolNames));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #getFloatingIpPoolNames()
|
||||
*/
|
||||
public NovaTemplateOptions floatingIpPoolNames(Iterable<String> floatingIpPoolNames) {
|
||||
NovaTemplateOptions options = new NovaTemplateOptions();
|
||||
return NovaTemplateOptions.class.cast(options.floatingIpPoolNames(floatingIpPoolNames));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see NovaTemplateOptions#shouldGenerateKeyPair()
|
||||
*/
|
||||
|
|
|
@ -42,16 +42,19 @@ import org.jclouds.compute.strategy.ListNodesStrategy;
|
|||
import org.jclouds.compute.strategy.impl.CreateNodesWithGroupEncodedIntoNameThenAddToSet;
|
||||
import org.jclouds.openstack.nova.v2_0.NovaApi;
|
||||
import org.jclouds.openstack.nova.v2_0.compute.functions.AllocateAndAddFloatingIpToNode;
|
||||
import org.jclouds.openstack.nova.v2_0.compute.options.NodeAndNovaTemplateOptions;
|
||||
import org.jclouds.openstack.nova.v2_0.compute.options.NovaTemplateOptions;
|
||||
import org.jclouds.openstack.nova.v2_0.domain.KeyPair;
|
||||
import org.jclouds.openstack.nova.v2_0.domain.zonescoped.SecurityGroupInZone;
|
||||
import org.jclouds.openstack.nova.v2_0.domain.zonescoped.ZoneAndName;
|
||||
import org.jclouds.openstack.nova.v2_0.domain.zonescoped.ZoneSecurityGroupNameAndPorts;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Throwables;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
import com.google.common.collect.Multimap;
|
||||
import com.google.common.primitives.Ints;
|
||||
import com.google.common.util.concurrent.Atomics;
|
||||
import com.google.common.util.concurrent.Futures;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import com.google.common.util.concurrent.ListeningExecutorService;
|
||||
|
@ -153,13 +156,21 @@ public class ApplyNovaTemplateOptionsCreateNodesWithGroupEncodedIntoNameThenAddT
|
|||
final String name, Template template) {
|
||||
|
||||
ListenableFuture<AtomicReference<NodeMetadata>> future = super.createNodeInGroupWithNameAndTemplate(group, name, template);
|
||||
NovaTemplateOptions templateOptions = NovaTemplateOptions.class.cast(template.getOptions());
|
||||
|
||||
final NovaTemplateOptions templateOptions = NovaTemplateOptions.class.cast(template.getOptions());
|
||||
if (templateOptions.shouldAutoAssignFloatingIp()) {
|
||||
return Futures.transform(future, createAndAddFloatingIpToNode, userExecutor);
|
||||
|
||||
ListenableFuture<AtomicReference<NodeAndNovaTemplateOptions>> nodeAndNovaTemplateOptions = Futures.transform(future,
|
||||
new Function<AtomicReference<NodeMetadata>, AtomicReference<NodeAndNovaTemplateOptions>>(){
|
||||
|
||||
@Override
|
||||
public AtomicReference<NodeAndNovaTemplateOptions> apply(AtomicReference<NodeMetadata> input) {
|
||||
return NodeAndNovaTemplateOptions.newAtomicReference(input, Atomics.newReference(templateOptions));
|
||||
}
|
||||
}
|
||||
);
|
||||
return Futures.transform(nodeAndNovaTemplateOptions, createAndAddFloatingIpToNode, userExecutor);
|
||||
} else {
|
||||
return future;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -31,6 +31,8 @@ import org.jclouds.domain.LocationScope;
|
|||
import org.jclouds.domain.LoginCredentials;
|
||||
import org.jclouds.http.HttpRequest;
|
||||
import org.jclouds.http.HttpResponse;
|
||||
import org.jclouds.openstack.nova.v2_0.compute.options.NodeAndNovaTemplateOptions;
|
||||
import org.jclouds.openstack.nova.v2_0.compute.options.NovaTemplateOptions;
|
||||
import org.jclouds.openstack.nova.v2_0.internal.BaseNovaComputeServiceExpectTest;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
|
@ -55,6 +57,7 @@ public class AllocateAndAddFloatingIpToNodeExpectTest extends BaseNovaComputeSer
|
|||
final NodeMetadata node = new NodeMetadataBuilder().id("az-1.region-a.geo-1/71592").providerId("71592").location(
|
||||
host).name("Server 71592").status(Status.RUNNING).privateAddresses(ImmutableSet.of("10.4.27.237"))
|
||||
.credentials(LoginCredentials.builder().password("foo").build()).build();
|
||||
final NovaTemplateOptions options = NovaTemplateOptions.Builder.autoAssignFloatingIp(false);
|
||||
|
||||
HttpRequest createFloatingIP = HttpRequest.builder().method("POST").endpoint(
|
||||
URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/os-floating-ips")).headers(
|
||||
|
@ -77,9 +80,13 @@ public class AllocateAndAddFloatingIpToNodeExpectTest extends BaseNovaComputeSer
|
|||
.getInstance(AllocateAndAddFloatingIpToNode.class);
|
||||
|
||||
AtomicReference<NodeMetadata> nodeRef = Atomics.newReference(node);
|
||||
fn.apply(nodeRef);
|
||||
AtomicReference<NovaTemplateOptions> optionsRef = Atomics.newReference(options);
|
||||
AtomicReference<NodeAndNovaTemplateOptions> nodeNovaRef = NodeAndNovaTemplateOptions.newAtomicReference(nodeRef, optionsRef);
|
||||
|
||||
fn.apply(nodeNovaRef);
|
||||
NodeMetadata node1 = nodeRef.get();
|
||||
assertNotNull(node1);
|
||||
assertNotNull(optionsRef.get());
|
||||
assertEquals(node1.getPublicAddresses(), ImmutableSet.of("10.0.0.3"));
|
||||
assertEquals(node1.getCredentials(), node.getCredentials());
|
||||
|
||||
|
@ -96,7 +103,7 @@ public class AllocateAndAddFloatingIpToNodeExpectTest extends BaseNovaComputeSer
|
|||
return addFloatingIPRequest;
|
||||
}
|
||||
|
||||
public void testAllocateWhenAllocationFailsLookupUnusedIpAddToServerAndUpdatesNodeMetadata() throws Exception {
|
||||
public void testAllocateWhenAllocationFailsOn400LookupUnusedIpAddToServerAndUpdatesNodeMetadata() throws Exception {
|
||||
HttpResponse createFloatingIPResponse = HttpResponse
|
||||
.builder()
|
||||
.statusCode(400)
|
||||
|
@ -124,10 +131,51 @@ public class AllocateAndAddFloatingIpToNodeExpectTest extends BaseNovaComputeSer
|
|||
.getInstance(AllocateAndAddFloatingIpToNode.class);
|
||||
|
||||
AtomicReference<NodeMetadata> nodeRef = Atomics.newReference(node);
|
||||
fn.apply(nodeRef);
|
||||
AtomicReference<NovaTemplateOptions> optionsRef = Atomics.newReference(options);
|
||||
AtomicReference<NodeAndNovaTemplateOptions> nodeNovaRef = NodeAndNovaTemplateOptions.newAtomicReference(nodeRef, optionsRef);
|
||||
|
||||
fn.apply(nodeNovaRef);
|
||||
NodeMetadata node1 = nodeRef.get();
|
||||
assertNotNull(node1);
|
||||
assertNotNull(optionsRef.get());
|
||||
assertEquals(node1.getPublicAddresses(), ImmutableSet.of("10.0.0.5"));
|
||||
}
|
||||
|
||||
public void testAllocateWhenAllocationFailsOn404LookupUnusedIpAddToServerAndUpdatesNodeMetadata() throws Exception {
|
||||
HttpResponse createFloatingIPResponse = HttpResponse
|
||||
.builder()
|
||||
.statusCode(404)
|
||||
.payload(
|
||||
payloadFromStringWithContentType(
|
||||
"{\"badRequest\": {\"message\": \"AddressLimitExceeded: Address quota exceeded. You cannot create any more addresses\", \"code\": 404}}",
|
||||
"application/json")).build();
|
||||
|
||||
HttpRequest list = HttpRequest.builder().method("GET").endpoint(
|
||||
URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/os-floating-ips")).headers(
|
||||
ImmutableMultimap.<String, String> builder().put("Accept", "application/json").put("X-Auth-Token",
|
||||
authToken).build()).build();
|
||||
|
||||
HttpResponse listResponseForUnassigned = HttpResponse.builder().statusCode(200).payload(
|
||||
payloadFromResource("/floatingip_list.json")).build();
|
||||
|
||||
HttpRequest addFloatingIPRequest = addFloatingIPForAddress("10.0.0.5");
|
||||
|
||||
AllocateAndAddFloatingIpToNode fn = requestsSendResponses(
|
||||
ImmutableMap.<HttpRequest, HttpResponse> builder().put(keystoneAuthWithUsernameAndPasswordAndTenantName,
|
||||
responseWithKeystoneAccess).put(extensionsOfNovaRequest, extensionsOfNovaResponse).put(
|
||||
createFloatingIP, createFloatingIPResponse)
|
||||
.put(addFloatingIPRequest, addFloatingIPResponse).put(list,
|
||||
listResponseForUnassigned).build()).getContext().utils().injector()
|
||||
.getInstance(AllocateAndAddFloatingIpToNode.class);
|
||||
|
||||
AtomicReference<NodeMetadata> nodeRef = Atomics.newReference(node);
|
||||
AtomicReference<NovaTemplateOptions> optionsRef = Atomics.newReference(options);
|
||||
AtomicReference<NodeAndNovaTemplateOptions> nodeNovaRef = NodeAndNovaTemplateOptions.newAtomicReference(nodeRef, optionsRef);
|
||||
|
||||
fn.apply(nodeNovaRef);
|
||||
NodeMetadata node1 = nodeRef.get();
|
||||
assertNotNull(node1);
|
||||
assertNotNull(optionsRef.get());
|
||||
assertEquals(node1.getPublicAddresses(), ImmutableSet.of("10.0.0.5"));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,6 +29,10 @@ public class InsufficientResourcesException extends RuntimeException {
|
|||
super();
|
||||
}
|
||||
|
||||
public InsufficientResourcesException(String arg0) {
|
||||
super(arg0);
|
||||
}
|
||||
|
||||
public InsufficientResourcesException(String arg0, Throwable arg1) {
|
||||
super(arg0, arg1);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue