From ca377677d290160debdf9ef412210285816aec9d Mon Sep 17 00:00:00 2001 From: Alena Prokharchyk Date: Tue, 24 Apr 2012 15:43:27 -0700 Subject: [PATCH] Account specific vlan ranges - fixed deleteVlanRange --- .../api/commands/DeleteVlanIpRangeCmd.java | 3 +- .../configuration/ConfigurationManager.java | 3 +- .../ConfigurationManagerImpl.java | 83 ++++++++++++++++--- .../com/cloud/network/NetworkManagerImpl.java | 8 +- 4 files changed, 79 insertions(+), 18 deletions(-) diff --git a/api/src/com/cloud/api/commands/DeleteVlanIpRangeCmd.java b/api/src/com/cloud/api/commands/DeleteVlanIpRangeCmd.java index 913f55c6430..2c67ad2eb92 100644 --- a/api/src/com/cloud/api/commands/DeleteVlanIpRangeCmd.java +++ b/api/src/com/cloud/api/commands/DeleteVlanIpRangeCmd.java @@ -12,8 +12,6 @@ // Automatically generated by addcopyright.py at 04/02/2012 package com.cloud.api.commands; -import java.util.UUID; - import org.apache.log4j.Logger; import com.cloud.api.ApiConstants; @@ -23,6 +21,7 @@ import com.cloud.api.Implementation; import com.cloud.api.Parameter; import com.cloud.api.ServerApiException; import com.cloud.api.response.SuccessResponse; +import com.cloud.exception.ConcurrentOperationException; import com.cloud.user.Account; @Implementation(description="Creates a VLAN IP range.", responseObject=SuccessResponse.class) diff --git a/server/src/com/cloud/configuration/ConfigurationManager.java b/server/src/com/cloud/configuration/ConfigurationManager.java index e33cec10a65..3d2aa76ed6e 100644 --- a/server/src/com/cloud/configuration/ConfigurationManager.java +++ b/server/src/com/cloud/configuration/ConfigurationManager.java @@ -139,9 +139,10 @@ public interface ConfigurationManager extends ConfigurationService, Manager { * * @param userId * @param vlanDbId + * @param caller TODO * @return success/failure */ - boolean deleteVlanAndPublicIpRange(long userId, long vlanDbId); + boolean deleteVlanAndPublicIpRange(long userId, long vlanDbId, Account caller); /** * Adds/deletes private IPs diff --git a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java index a2a0f7fc7a1..ef1a89baaf3 100755 --- a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java +++ b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java @@ -38,8 +38,8 @@ import org.apache.log4j.Logger; import com.cloud.acl.SecurityChecker; import com.cloud.alert.AlertManager; -import com.cloud.api.ApiDBUtils; import com.cloud.api.ApiConstants.LDAPParams; +import com.cloud.api.ApiDBUtils; import com.cloud.api.commands.CreateDiskOfferingCmd; import com.cloud.api.commands.CreateNetworkOfferingCmd; import com.cloud.api.commands.CreateServiceOfferingCmd; @@ -112,6 +112,7 @@ import com.cloud.network.Networks.BroadcastDomainType; import com.cloud.network.Networks.TrafficType; import com.cloud.network.PhysicalNetwork; import com.cloud.network.PhysicalNetworkVO; +import com.cloud.network.dao.FirewallRulesDao; import com.cloud.network.dao.IPAddressDao; import com.cloud.network.dao.NetworkDao; import com.cloud.network.dao.PhysicalNetworkDao; @@ -160,6 +161,7 @@ import com.cloud.utils.net.NetUtils; import com.cloud.vm.VirtualMachine; import com.cloud.vm.dao.ConsoleProxyDao; import com.cloud.vm.dao.DomainRouterDao; +import com.cloud.vm.dao.NicDao; import com.cloud.vm.dao.SecondaryStorageVmDao; import com.cloud.vm.dao.VMInstanceDao; @@ -240,6 +242,10 @@ public class ConfigurationManagerImpl implements ConfigurationManager, Configura SwiftManager _swiftMgr; @Inject PhysicalNetworkTrafficTypeDao _trafficTypeDao; + @Inject + NicDao _nicDao; + @Inject + FirewallRulesDao _firewallDao; // FIXME - why don't we have interface for DataCenterLinkLocalIpAddressDao? protected static final DataCenterLinkLocalIpAddressDaoImpl _LinkLocalIpAllocDao = ComponentLocator.inject(DataCenterLinkLocalIpAddressDaoImpl.class); @@ -2507,24 +2513,78 @@ public class ConfigurationManagerImpl implements ConfigurationManager, Configura } @Override - public boolean deleteVlanAndPublicIpRange(long userId, long vlanDbId) { + @DB + public boolean deleteVlanAndPublicIpRange(long userId, long vlanDbId, Account caller) { VlanVO vlan = _vlanDao.findById(vlanDbId); if (vlan == null) { throw new InvalidParameterValueException("Please specify a valid IP range id."); } + + boolean isAccountSpecific = false; + List acctVln = _accountVlanMapDao.listAccountVlanMapsByVlan(vlan.getId()); + // Check for account wide pool. It will have an entry for account_vlan_map. + if (acctVln != null && !acctVln.isEmpty()) { + isAccountSpecific = true; + } // Check if the VLAN has any allocated public IPs - if (_publicIpAddressDao.countIPs(vlan.getDataCenterId(), vlanDbId, true) > 0) { - throw new InvalidParameterValueException("The IP range can't be deleted because it has allocated public IP addresses."); + long allocIpCount = _publicIpAddressDao.countIPs(vlan.getDataCenterId(), vlanDbId, true); + boolean success = true; + if (allocIpCount > 0) { + if (isAccountSpecific) { + try { + vlan = _vlanDao.acquireInLockTable(vlanDbId, 30); + if (vlan == null) { + throw new CloudRuntimeException("Unable to acquire vlan configuration: " + vlanDbId); + } + + if (s_logger.isDebugEnabled()) { + s_logger.debug("lock vlan " + vlanDbId + " is acquired"); + } + + List ips = _publicIpAddressDao.listByVlanId(vlanDbId); + + for (IPAddressVO ip : ips) { + if (ip.isOneToOneNat()) { + throw new InvalidParameterValueException("Can't delete account specific vlan " + vlanDbId + + " as ip " + ip + " belonging to the range is used for static nat purposes. Cleanup the rules first"); + } + + if (ip.isSourceNat() && _nicDao.findByIp4AddressAndNetworkId(ip.getAddress().addr(), ip.getSourceNetworkId()) != null) { + throw new InvalidParameterValueException("Can't delete account specific vlan " + vlanDbId + + " as ip " + ip + " belonging to the range is a source nat ip for the network id=" + ip.getSourceNetworkId() + + ". Either delete the network, or Virtual Router instance using this ip address"); + } + + if (_firewallDao.countRulesByIpId(ip.getId()) > 0) { + throw new InvalidParameterValueException("Can't delete account specific vlan " + vlanDbId + + " as ip " + ip + " belonging to the range has firewall rules applied. Cleanup the rules first"); + } + //release public ip address here + success = success && _networkMgr.releasePublicIpAddress(ip.getId(), userId, caller); + } + if (!success) { + s_logger.warn("Some ip addresses failed to be released as a part of vlan " + vlanDbId + " removal"); + } + } finally { + _vlanDao.releaseFromLockTable(vlanDbId); + } + } else { + throw new InvalidParameterValueException("The IP range can't be deleted because it has allocated public IP addresses."); + } } - // Delete all public IPs in the VLAN - if (!deletePublicIPRange(vlanDbId)) { + if (success) { + // Delete all public IPs in the VLAN + if (!deletePublicIPRange(vlanDbId)) { + return false; + } + + // Delete the VLAN + return _vlanDao.expunge(vlanDbId); + } else { return false; } - - // Delete the VLAN - return _vlanDao.expunge(vlanDbId); } @Override @@ -2958,7 +3018,7 @@ public class ConfigurationManagerImpl implements ConfigurationManager, Configura throw new InvalidParameterValueException("Please specify a valid IP range id."); } - return deleteVlanAndPublicIpRange(userId, vlanDbId); + return deleteVlanAndPublicIpRange(userId, vlanDbId, UserContext.current().getCaller()); } @@ -3827,7 +3887,8 @@ public class ConfigurationManagerImpl implements ConfigurationManager, Configura Transaction txn = Transaction.currentTxn(); txn.start(); for (AccountVlanMapVO map : maps) { - if (!deleteVlanAndPublicIpRange(_accountMgr.getSystemUser().getId(), map.getVlanDbId())) { + if (!deleteVlanAndPublicIpRange(_accountMgr.getSystemUser().getId(), map.getVlanDbId(), + _accountMgr.getAccount(Account.ACCOUNT_ID_SYSTEM))) { result = false; } } diff --git a/server/src/com/cloud/network/NetworkManagerImpl.java b/server/src/com/cloud/network/NetworkManagerImpl.java index b56b9547ffe..25571a5676c 100755 --- a/server/src/com/cloud/network/NetworkManagerImpl.java +++ b/server/src/com/cloud/network/NetworkManagerImpl.java @@ -605,7 +605,7 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag } else if (addr.getState() == IpAddress.State.Releasing) { // Cleanup all the resources for ip address if there are any, and only then un-assign ip in the -// system + // system if (cleanupIpResources(addr.getId(), Account.ACCOUNT_ID_SYSTEM, _accountMgr.getSystemAccount())) { _ipAddressDao.unassignIpAddress(addr.getId()); } else { @@ -3042,7 +3042,7 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag txn.start(); guru.trash(network, _networkOfferingDao.findById(network.getNetworkOfferingId()), owner); - if (!deleteVlansInNetwork(network.getId(), context.getCaller().getId())) { + if (!deleteVlansInNetwork(network.getId(), context.getCaller().getId(), callerAccount)) { success = false; s_logger.warn("Failed to delete network " + network + "; was unable to cleanup corresponding ip ranges"); } else { @@ -3057,11 +3057,11 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag return success; } - private boolean deleteVlansInNetwork(long networkId, long userId) { + private boolean deleteVlansInNetwork(long networkId, long userId, Account callerAccount) { List vlans = _vlanDao.listVlansByNetworkId(networkId); boolean result = true; for (VlanVO vlan : vlans) { - if (!_configMgr.deleteVlanAndPublicIpRange(_accountMgr.getSystemUser().getId(), vlan.getId())) { + if (!_configMgr.deleteVlanAndPublicIpRange(_accountMgr.getSystemUser().getId(), vlan.getId(), callerAccount)) { s_logger.warn("Failed to delete vlan " + vlan.getId() + ");"); result = false; }