CLOUDSTACK-2700:on network/vpc delete, portable IP should be still

associated with account

Unlike public ip which gets dis-associated (released) with the account
on network/VPC delete, portable IP should continue to be associated with
the account even when the network/VPC with which it is currently
associated in deleted. This fix ensures portable IP are associated to
account even after network/vpc is deleted.
This commit is contained in:
Murali Reddy 2013-05-27 18:42:33 +05:30
parent ad48c83808
commit 883333c214
9 changed files with 56 additions and 24 deletions

View File

@ -55,7 +55,7 @@ public interface NetworkService {
IpAddress allocatePortableIP(Account ipOwner, int regionId, Long zoneId, Long networkId, Long vpcId) throws ResourceAllocationException, IpAddress allocatePortableIP(Account ipOwner, int regionId, Long zoneId, Long networkId, Long vpcId) throws ResourceAllocationException,
InsufficientAddressCapacityException, ConcurrentOperationException; InsufficientAddressCapacityException, ConcurrentOperationException;
boolean releasePortableIpAddress(long ipAddressId) throws InsufficientAddressCapacityException; boolean releasePortableIpAddress(long ipAddressId);
Network createGuestNetwork(CreateNetworkCmd cmd) throws InsufficientCapacityException, ConcurrentOperationException, Network createGuestNetwork(CreateNetworkCmd cmd) throws InsufficientCapacityException, ConcurrentOperationException,
ResourceAllocationException; ResourceAllocationException;

View File

@ -268,6 +268,11 @@ public interface NetworkManager {
IPAddressVO associateIPToGuestNetwork(long ipAddrId, long networkId, boolean releaseOnFailure) throws ResourceAllocationException, ResourceUnavailableException, IPAddressVO associateIPToGuestNetwork(long ipAddrId, long networkId, boolean releaseOnFailure) throws ResourceAllocationException, ResourceUnavailableException,
InsufficientAddressCapacityException, ConcurrentOperationException; InsufficientAddressCapacityException, ConcurrentOperationException;
IpAddress allocatePortableIp(Account ipOwner, Account caller, long dcId, Long networkId, Long vpcID)
throws ConcurrentOperationException, ResourceAllocationException, InsufficientAddressCapacityException;
boolean releasePortableIpAddress(long addrId);
IPAddressVO associatePortableIPToGuestNetwork(long ipAddrId, long networkId, boolean releaseOnFailure) throws ResourceAllocationException, ResourceUnavailableException, IPAddressVO associatePortableIPToGuestNetwork(long ipAddrId, long networkId, boolean releaseOnFailure) throws ResourceAllocationException, ResourceUnavailableException,
InsufficientAddressCapacityException, ConcurrentOperationException; InsufficientAddressCapacityException, ConcurrentOperationException;
@ -362,10 +367,6 @@ public interface NetworkManager {
IpAddress allocateIp(Account ipOwner, boolean isSystem, Account caller, long callerId, IpAddress allocateIp(Account ipOwner, boolean isSystem, Account caller, long callerId,
DataCenter zone) throws ConcurrentOperationException, ResourceAllocationException, InsufficientAddressCapacityException; DataCenter zone) throws ConcurrentOperationException, ResourceAllocationException, InsufficientAddressCapacityException;
IpAddress allocatePortableIp(Account ipOwner, Account caller, long dcId, Long networkId, Long vpcID)
throws ConcurrentOperationException, ResourceAllocationException, InsufficientAddressCapacityException;
Map<String, String> finalizeServicesAndProvidersForNetwork(NetworkOffering offering, Map<String, String> finalizeServicesAndProvidersForNetwork(NetworkOffering offering,
Long physicalNetworkId); Long physicalNetworkId);

View File

@ -1118,7 +1118,8 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L
} }
@DB @DB
private void releasePortableIpAddress(long addrId) { @Override
public boolean releasePortableIpAddress(long addrId) {
Transaction txn = Transaction.currentTxn(); Transaction txn = Transaction.currentTxn();
GlobalLock portableIpLock = GlobalLock.getInternLock("PortablePublicIpRange"); GlobalLock portableIpLock = GlobalLock.getInternLock("PortablePublicIpRange");
@ -1133,12 +1134,13 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L
// removed the provisioned vlan // removed the provisioned vlan
VlanVO vlan = _vlanDao.findById(ip.getVlanId()); VlanVO vlan = _vlanDao.findById(ip.getVlanId());
_vlanDao.expunge(vlan.getId()); _vlanDao.remove(vlan.getId());
// remove the provisioned public ip address // remove the provisioned public ip address
_ipAddressDao.expunge(ip.getId()); _ipAddressDao.remove(ip.getId());
txn.commit(); txn.commit();
return true;
} finally { } finally {
portableIpLock.releaseRef(); portableIpLock.releaseRef();
} }
@ -3537,8 +3539,16 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L
List<IPAddressVO> ipsToRelease = _ipAddressDao.listByAssociatedNetwork(networkId, null); List<IPAddressVO> ipsToRelease = _ipAddressDao.listByAssociatedNetwork(networkId, null);
for (IPAddressVO ipToRelease : ipsToRelease) { for (IPAddressVO ipToRelease : ipsToRelease) {
if (ipToRelease.getVpcId() == null) { if (ipToRelease.getVpcId() == null) {
if (!ipToRelease.isPortable()) {
IPAddressVO ip = markIpAsUnavailable(ipToRelease.getId()); IPAddressVO ip = markIpAsUnavailable(ipToRelease.getId());
assert (ip != null) : "Unable to mark the ip address id=" + ipToRelease.getId() + " as unavailable."; assert (ip != null) : "Unable to mark the ip address id=" + ipToRelease.getId() + " as unavailable.";
} else {
// portable IP address are associated with owner, until explicitly requested to be disassociated
// so as part of network clean up just break IP association with guest network
ipToRelease.setAssociatedWithNetworkId(null);
_ipAddressDao.update(ipToRelease.getId(), ipToRelease);
s_logger.debug("Portable IP address " + ipToRelease + " is no longer associated with any network");
}
} else { } else {
_vpcMgr.unassignIPFromVpcNetwork(ipToRelease.getId(), network.getId()); _vpcMgr.unassignIPFromVpcNetwork(ipToRelease.getId(), network.getId());
} }

View File

@ -591,8 +591,12 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService {
@Override @Override
@ActionEvent(eventType = EventTypes.EVENT_PORTABLE_IP_RELEASE, eventDescription = "disassociating portable Ip", async = true) @ActionEvent(eventType = EventTypes.EVENT_PORTABLE_IP_RELEASE, eventDescription = "disassociating portable Ip", async = true)
public boolean releasePortableIpAddress(long ipAddressId) throws InsufficientAddressCapacityException { public boolean releasePortableIpAddress(long ipAddressId) {
try {
return releaseIpAddressInternal(ipAddressId); return releaseIpAddressInternal(ipAddressId);
} catch (Exception e) {
return false;
}
} }
@Override @Override
@ -880,7 +884,7 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService {
boolean success = _networkMgr.disassociatePublicIpAddress(ipAddressId, userId, caller); boolean success = _networkMgr.disassociatePublicIpAddress(ipAddressId, userId, caller);
if (success) { if (success) {
if (!ipVO.isPortable()) { if (ipVO.isPortable()) {
return success; return success;
} }
Long networkId = ipVO.getAssociatedWithNetworkId(); Long networkId = ipVO.getAssociatedWithNetworkId();

View File

@ -490,10 +490,9 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules
"a part of enable static nat"); "a part of enable static nat");
return false; return false;
} }
performedIpAssoc = true;
} else if (ipAddress.isPortable()) { } else if (ipAddress.isPortable()) {
s_logger.info("Portable IP " + ipAddress.getUuid() + " is not associated with the network, so" + s_logger.info("Portable IP " + ipAddress.getUuid() + " is not associated with the network yet "
"associate IP with the network " + networkId); + " so associate IP with the network " + networkId);
try { try {
// check if StaticNat service is enabled in the network // check if StaticNat service is enabled in the network
_networkModel.checkIpForService(ipAddress, Service.StaticNat, networkId); _networkModel.checkIpForService(ipAddress, Service.StaticNat, networkId);
@ -504,13 +503,12 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules
} }
// associate portable IP with guest network // associate portable IP with guest network
_networkMgr.associatePortableIPToGuestNetwork(ipId, networkId, false); ipAddress = _networkMgr.associatePortableIPToGuestNetwork(ipId, networkId, false);
} catch (Exception e) { } catch (Exception e) {
s_logger.warn("Failed to associate portable id=" + ipId + " to network id=" + networkId + " as " + s_logger.warn("Failed to associate portable id=" + ipId + " to network id=" + networkId + " as " +
"a part of enable static nat"); "a part of enable static nat");
return false; return false;
} }
performedIpAssoc = true;
} }
} else if (ipAddress.getAssociatedWithNetworkId() != networkId) { } else if (ipAddress.getAssociatedWithNetworkId() != networkId) {
if (ipAddress.isPortable()) { if (ipAddress.isPortable()) {
@ -520,14 +518,16 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules
// check if portable IP can be transferred across the networks // check if portable IP can be transferred across the networks
if (_networkMgr.isPortableIpTransferableFromNetwork(ipId, ipAddress.getAssociatedWithNetworkId() )) { if (_networkMgr.isPortableIpTransferableFromNetwork(ipId, ipAddress.getAssociatedWithNetworkId() )) {
try { try {
// transfer the portable IP and refresh IP details
_networkMgr.transferPortableIP(ipId, ipAddress.getAssociatedWithNetworkId(), networkId); _networkMgr.transferPortableIP(ipId, ipAddress.getAssociatedWithNetworkId(), networkId);
ipAddress = _ipAddressDao.findById(ipId);
} catch (Exception e) { } catch (Exception e) {
s_logger.warn("Failed to associate portable id=" + ipId + " to network id=" + networkId + " as " + s_logger.warn("Failed to associate portable id=" + ipId + " to network id=" + networkId + " as " +
"a part of enable static nat"); "a part of enable static nat");
return false; return false;
} }
} else { } else {
throw new InvalidParameterValueException("Portable IP: " + ipId + " has associated services" + throw new InvalidParameterValueException("Portable IP: " + ipId + " has associated services " +
"in network " + ipAddress.getAssociatedWithNetworkId() + " so can not be transferred to " + "in network " + ipAddress.getAssociatedWithNetworkId() + " so can not be transferred to " +
" network " + networkId); " network " + networkId);
} }

View File

@ -1217,11 +1217,20 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis
List<IPAddressVO> ipsToRelease = _ipAddressDao.listByAssociatedVpc(vpcId, null); List<IPAddressVO> ipsToRelease = _ipAddressDao.listByAssociatedVpc(vpcId, null);
s_logger.debug("Releasing ips for vpc id=" + vpcId + " as a part of vpc cleanup"); s_logger.debug("Releasing ips for vpc id=" + vpcId + " as a part of vpc cleanup");
for (IPAddressVO ipToRelease : ipsToRelease) { for (IPAddressVO ipToRelease : ipsToRelease) {
if (ipToRelease.isPortable()) {
// portable IP address are associated with owner, until explicitly requested to be disassociated.
// so as part of VPC clean up just break IP association with VPC
ipToRelease.setVpcId(null);
ipToRelease.setAssociatedWithNetworkId(null);
_ipAddressDao.update(ipToRelease.getId(), ipToRelease);
s_logger.debug("Portable IP address " + ipToRelease + " is no longer associated with any VPC");
} else {
success = success && _ntwkMgr.disassociatePublicIpAddress(ipToRelease.getId(), callerUserId, caller); success = success && _ntwkMgr.disassociatePublicIpAddress(ipToRelease.getId(), callerUserId, caller);
if (!success) { if (!success) {
s_logger.warn("Failed to cleanup ip " + ipToRelease + " as a part of vpc id=" + vpcId + " cleanup"); s_logger.warn("Failed to cleanup ip " + ipToRelease + " as a part of vpc id=" + vpcId + " cleanup");
} }
} }
}
if (success) { if (success) {
s_logger.debug("Released ip addresses for vpc id=" + vpcId + " as a part of cleanup vpc process"); s_logger.debug("Released ip addresses for vpc id=" + vpcId + " as a part of cleanup vpc process");

View File

@ -731,6 +731,14 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
_resourceCountDao.removeEntriesByOwner(accountId, ResourceOwnerType.Account); _resourceCountDao.removeEntriesByOwner(accountId, ResourceOwnerType.Account);
_resourceLimitDao.removeEntriesByOwner(accountId, ResourceOwnerType.Account); _resourceLimitDao.removeEntriesByOwner(accountId, ResourceOwnerType.Account);
// release account specific acquired portable IP's. Since all the portable IP's must have been already
// disassociated with VPC/guest network (due to deletion), so just mark portable IP as free.
List<? extends IpAddress> portableIpsToRelease = _ipAddressDao.listByAccount(accountId);
for (IpAddress ip : portableIpsToRelease) {
s_logger.debug("Releasing portable ip " + ip + " as a part of account id=" + accountId + " cleanup");
_networkMgr.releasePortableIpAddress(ip.getId());
}
return true; return true;
} catch (Exception ex) { } catch (Exception ex) {
s_logger.warn("Failed to cleanup account " + account + " due to ", ex); s_logger.warn("Failed to cleanup account " + account + " due to ", ex);

View File

@ -887,7 +887,7 @@ public class MockNetworkManagerImpl extends ManagerBase implements NetworkManage
} }
@Override @Override
public boolean releasePortableIpAddress(long ipAddressId) throws InsufficientAddressCapacityException { public boolean releasePortableIpAddress(long ipAddressId) {
return false;// TODO Auto-generated method stub return false;// TODO Auto-generated method stub
} }

View File

@ -210,7 +210,7 @@ public class MockNetworkManagerImpl extends ManagerBase implements NetworkManage
} }
@Override @Override
public boolean releasePortableIpAddress(long ipAddressId) throws InsufficientAddressCapacityException { public boolean releasePortableIpAddress(long ipAddressId) {
return false;// TODO Auto-generated method stub return false;// TODO Auto-generated method stub
} }