diff --git a/api/src/com/cloud/api/BaseCmd.java b/api/src/com/cloud/api/BaseCmd.java index 09a5dfd7f8f..1a1be969a1f 100755 --- a/api/src/com/cloud/api/BaseCmd.java +++ b/api/src/com/cloud/api/BaseCmd.java @@ -36,6 +36,7 @@ import com.cloud.domain.Domain; import com.cloud.exception.ConcurrentOperationException; import com.cloud.exception.InsufficientCapacityException; import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.NetworkRuleConflictException; import com.cloud.exception.PermissionDeniedException; import com.cloud.exception.ResourceAllocationException; import com.cloud.exception.ResourceUnavailableException; @@ -158,7 +159,7 @@ public abstract class BaseCmd { _storageNetworkService = locator.getManager(StorageNetworkService.class); } - public abstract void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException; + public abstract void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException; public String getResponseType() { if (responseType == null) { diff --git a/api/src/com/cloud/api/commands/DisableStaticNatCmd.java b/api/src/com/cloud/api/commands/DisableStaticNatCmd.java index 3835001aa98..0e21d8713bc 100644 --- a/api/src/com/cloud/api/commands/DisableStaticNatCmd.java +++ b/api/src/com/cloud/api/commands/DisableStaticNatCmd.java @@ -28,7 +28,9 @@ import com.cloud.api.Parameter; import com.cloud.api.ServerApiException; import com.cloud.api.response.SuccessResponse; import com.cloud.event.EventTypes; +import com.cloud.exception.InsufficientAddressCapacityException; import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.NetworkRuleConflictException; import com.cloud.exception.ResourceUnavailableException; import com.cloud.network.IpAddress; @@ -77,7 +79,7 @@ public class DisableStaticNatCmd extends BaseAsyncCmd { } @Override - public void execute() throws ResourceUnavailableException { + public void execute() throws ResourceUnavailableException, NetworkRuleConflictException, InsufficientAddressCapacityException { boolean result = _rulesService.disableStaticNat(ipAddressId); if (result) { diff --git a/api/src/com/cloud/network/rules/RulesService.java b/api/src/com/cloud/network/rules/RulesService.java index c41b1e85f15..1588d7d633e 100644 --- a/api/src/com/cloud/network/rules/RulesService.java +++ b/api/src/com/cloud/network/rules/RulesService.java @@ -20,6 +20,7 @@ package com.cloud.network.rules; import java.util.List; import com.cloud.api.commands.ListPortForwardingRulesCmd; +import com.cloud.exception.InsufficientAddressCapacityException; import com.cloud.exception.NetworkRuleConflictException; import com.cloud.exception.ResourceUnavailableException; import com.cloud.user.Account; @@ -69,6 +70,6 @@ public interface RulesService { List getSourceCidrs(long ruleId); - boolean disableStaticNat(long ipId) throws ResourceUnavailableException; + boolean disableStaticNat(long ipId) throws ResourceUnavailableException, NetworkRuleConflictException, InsufficientAddressCapacityException; } diff --git a/server/src/com/cloud/network/rules/RulesManager.java b/server/src/com/cloud/network/rules/RulesManager.java index ca97a7ea72c..4c5b3537786 100644 --- a/server/src/com/cloud/network/rules/RulesManager.java +++ b/server/src/com/cloud/network/rules/RulesManager.java @@ -72,7 +72,7 @@ public interface RulesManager extends RulesService { boolean applyStaticNatsForNetwork(long networkId, boolean continueOnError, Account caller); - void enableElasticIpAndStaticNatForVm(UserVm vm) throws InsufficientAddressCapacityException; + void enableElasticIpAndStaticNatForVm(UserVm vm, boolean getNewIp) throws InsufficientAddressCapacityException; boolean disableStaticNat(long ipAddressId, Account caller, long callerUserId, boolean releaseIpIfElastic) throws ResourceUnavailableException; diff --git a/server/src/com/cloud/network/rules/RulesManagerImpl.java b/server/src/com/cloud/network/rules/RulesManagerImpl.java index c2200691a62..cab099e170c 100755 --- a/server/src/com/cloud/network/rules/RulesManagerImpl.java +++ b/server/src/com/cloud/network/rules/RulesManagerImpl.java @@ -400,12 +400,11 @@ public class RulesManagerImpl implements RulesManager, RulesService, Manager { } else if (ipAddress.getAssociatedWithVmId() != null && ipAddress.getAssociatedWithVmId().longValue() != vmId) { throw new NetworkRuleConflictException("Failed to enable static for the ip address " + ipAddress + " and vm id=" + vmId + " as it's already assigned to antoher vm"); } - - - // If there is public ip address already associated with the vm, throw an exception + IPAddressVO oldIP = _ipAddressDao.findByAssociatedVmId(vmId); if (oldIP != null) { + //If elasticIP functionality is supported in the network, we always have to disable static nat on the old ip in order to re-enable it on the new one Long networkId = oldIP.getAssociatedWithNetworkId(); boolean reassignStaticNat = false; if (networkId != null) { @@ -415,6 +414,8 @@ public class RulesManagerImpl implements RulesManager, RulesService, Manager { reassignStaticNat = true; } } + + // If there is public ip address already associated with the vm, throw an exception if (!reassignStaticNat) { throw new InvalidParameterValueException("Failed to enable static nat for the ip address id=" + ipAddress.getId() + " as vm id=" + vmId + " is already associated with ip id=" + oldIP.getId()); } @@ -423,7 +424,7 @@ public class RulesManagerImpl implements RulesManager, RulesService, Manager { if (!disableStaticNat(oldIP.getId(), caller, callerUserId, true)) { throw new CloudRuntimeException("Failed to disable old static nat rule for vm id=" + vmId + " and ip " + oldIP); } - } + } } @@ -1018,18 +1019,31 @@ public class RulesManagerImpl implements RulesManager, RulesService, Manager { } @Override - public boolean disableStaticNat(long ipId) throws ResourceUnavailableException{ + public boolean disableStaticNat(long ipId) throws ResourceUnavailableException, NetworkRuleConflictException, InsufficientAddressCapacityException{ UserContext ctx = UserContext.current(); Account caller = ctx.getCaller(); IPAddressVO ipAddress = _ipAddressDao.findById(ipId); checkIpAndUserVm(ipAddress, null, caller); if (ipAddress.getElastic()) { - throw new InvalidParameterValueException("Can't release elastic IP address " + ipAddress); + throw new InvalidParameterValueException("Can't disable static nat for elastic IP address " + ipAddress); } - - return disableStaticNat(ipId, caller, ctx.getCallerUserId(), false); - + + Long vmId = ipAddress.getAssociatedWithVmId(); + if (vmId == null) { + throw new InvalidParameterValueException("IP address " + ipAddress + " is not associated with any vm Id"); + } + + //if network has elastic IP functionality supported, we first have to disable static nat on old ip in order to re-enable it on the new one + //enable static nat takes care of that + Network guestNetwork = _networkMgr.getNetwork(ipAddress.getAssociatedWithNetworkId()); + NetworkOffering offering = _configMgr.getNetworkOffering(guestNetwork.getNetworkOfferingId()); + if (offering.getElasticIp()) { + enableElasticIpAndStaticNatForVm(_vmDao.findById(vmId), true); + return true; + } else { + return disableStaticNat(ipId, caller, ctx.getCallerUserId(), false); + } } @Override @DB @@ -1159,7 +1173,7 @@ public class RulesManagerImpl implements RulesManager, RulesService, Manager { @Override - public void enableElasticIpAndStaticNatForVm(UserVm vm) throws InsufficientAddressCapacityException{ + public void enableElasticIpAndStaticNatForVm(UserVm vm, boolean getNewIp) throws InsufficientAddressCapacityException{ boolean success = true; //enable static nat if eIp capability is supported @@ -1170,7 +1184,7 @@ public class RulesManagerImpl implements RulesManager, RulesService, Manager { if (offering.getElasticIp()) { //check if there is already static nat enabled - if (_ipAddressDao.findByAssociatedVmId(vm.getId()) != null) { + if (_ipAddressDao.findByAssociatedVmId(vm.getId()) != null && !getNewIp) { s_logger.debug("Vm " + vm + " already has elastic ip associated with it in guest network " + guestNetwork); continue; } diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index 7bb49e539aa..56955da1601 100755 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -2720,7 +2720,7 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager } //enable elastic ip for vm - _rulesMgr.enableElasticIpAndStaticNatForVm(profile.getVirtualMachine()); + _rulesMgr.enableElasticIpAndStaticNatForVm(profile.getVirtualMachine(), false); return true; }