diff --git a/api/src/com/cloud/event/EventTypes.java b/api/src/com/cloud/event/EventTypes.java index 903454153f3..8561eccda28 100755 --- a/api/src/com/cloud/event/EventTypes.java +++ b/api/src/com/cloud/event/EventTypes.java @@ -101,7 +101,7 @@ public class EventTypes { public static final String EVENT_NET_IP_ASSIGN = "NET.IPASSIGN"; public static final String EVENT_NET_IP_RELEASE = "NET.IPRELEASE"; public static final String EVENT_PORTABLE_IP_ASSIGN = "PORTABLE.IPASSIGN"; - public static final String EVENT_PORTABLE_RELEASE = "PORTABLEIPRELEASE"; + public static final String EVENT_PORTABLE_IP_RELEASE = "PORTABLEIPRELEASE"; public static final String EVENT_NET_RULE_ADD = "NET.RULEADD"; public static final String EVENT_NET_RULE_DELETE = "NET.RULEDELETE"; public static final String EVENT_NET_RULE_MODIFY = "NET.RULEMODIFY"; diff --git a/api/src/com/cloud/network/NetworkService.java b/api/src/com/cloud/network/NetworkService.java index 8f235617393..078aa043b6c 100755 --- a/api/src/com/cloud/network/NetworkService.java +++ b/api/src/com/cloud/network/NetworkService.java @@ -52,10 +52,12 @@ public interface NetworkService { IpAddress allocateIP(Account ipOwner, long zoneId, Long networkId) throws ResourceAllocationException, InsufficientAddressCapacityException, ConcurrentOperationException; + boolean releaseIpAddress(long ipAddressId) throws InsufficientAddressCapacityException; + IpAddress allocatePortableIP(Account ipOwner, int regionId, Long zoneId, Long networkId, Long vpcId) throws ResourceAllocationException, InsufficientAddressCapacityException, ConcurrentOperationException; - boolean releaseIpAddress(long ipAddressId) throws InsufficientAddressCapacityException; + boolean releasePortableIpAddress(long ipAddressId) throws InsufficientAddressCapacityException; Network createGuestNetwork(CreateNetworkCmd cmd) throws InsufficientCapacityException, ConcurrentOperationException, ResourceAllocationException; diff --git a/api/src/org/apache/cloudstack/api/command/user/address/DisassociateIPAddrCmd.java b/api/src/org/apache/cloudstack/api/command/user/address/DisassociateIPAddrCmd.java index 827111902ff..8f78fe3a959 100644 --- a/api/src/org/apache/cloudstack/api/command/user/address/DisassociateIPAddrCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/address/DisassociateIPAddrCmd.java @@ -74,7 +74,12 @@ public class DisassociateIPAddrCmd extends BaseAsyncCmd { @Override public void execute() throws InsufficientAddressCapacityException{ UserContext.current().setEventDetails("Ip Id: " + getIpAddressId()); - boolean result = _networkService.releaseIpAddress(getIpAddressId()); + boolean result = false; + if (!isPortable(id)) { + _networkService.releaseIpAddress(getIpAddressId()); + } else { + _networkService.releaseIpAddress(getIpAddressId()); + } if (result) { SuccessResponse response = new SuccessResponse(getCommandName()); this.setResponseObject(response); @@ -139,4 +144,9 @@ public class DisassociateIPAddrCmd extends BaseAsyncCmd { public Long getInstanceId() { return getIpAddressId(); } + + private boolean isPortable(long id) { + IpAddress ip = getIpAddress(id); + return ip.isPortable(); + } } diff --git a/server/src/com/cloud/network/NetworkManager.java b/server/src/com/cloud/network/NetworkManager.java index 15bb450f7bd..2bb40c84321 100755 --- a/server/src/com/cloud/network/NetworkManager.java +++ b/server/src/com/cloud/network/NetworkManager.java @@ -239,6 +239,11 @@ public interface NetworkManager { IPAddressVO associateIPToGuestNetwork(long ipAddrId, long networkId, boolean releaseOnFailure) throws ResourceAllocationException, ResourceUnavailableException, InsufficientAddressCapacityException, ConcurrentOperationException; + IPAddressVO associatePortableIPToGuestNetwork(long ipAddrId, long networkId, boolean releaseOnFailure) throws ResourceAllocationException, ResourceUnavailableException, + InsufficientAddressCapacityException, ConcurrentOperationException; + + IPAddressVO disassociatePortableIPToGuestNetwork(long ipAddrId, long networkId) throws ResourceAllocationException, ResourceUnavailableException, + InsufficientAddressCapacityException, ConcurrentOperationException; /** * @param network diff --git a/server/src/com/cloud/network/NetworkManagerImpl.java b/server/src/com/cloud/network/NetworkManagerImpl.java index 03c606b5cea..cac6bf20421 100755 --- a/server/src/com/cloud/network/NetworkManagerImpl.java +++ b/server/src/com/cloud/network/NetworkManagerImpl.java @@ -797,12 +797,14 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L } DataCenter zone = _configMgr.getZone(network.getDataCenterId()); - if (network.getGuestType() == Network.GuestType.Shared && zone.getNetworkType() == NetworkType.Advanced) { - if (isSharedNetworkOfferingWithServices(network.getNetworkOfferingId())) { - _accountMgr.checkAccess(UserContext.current().getCaller(), AccessType.UseNetwork, false, network); - } else { - throw new InvalidParameterValueException("IP can be associated with guest network of 'shared' type only if " + - "network services Source Nat, Static Nat, Port Forwarding, Load balancing, firewall are enabled in the network"); + if (zone.getNetworkType() == NetworkType.Advanced) { + if (network.getGuestType() == Network.GuestType.Shared) { + if (isSharedNetworkOfferingWithServices(network.getNetworkOfferingId())) { + _accountMgr.checkAccess(UserContext.current().getCaller(), AccessType.UseNetwork, false, network); + } else { + throw new InvalidParameterValueException("IP can be associated with guest network of 'shared' type only if " + + "network services Source Nat, Static Nat, Port Forwarding, Load balancing, firewall are enabled in the network"); + } } } else { _accountMgr.checkAccess(caller, null, true, ipToAssoc); @@ -900,6 +902,92 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L } } + @Override + public IPAddressVO associatePortableIPToGuestNetwork(long ipAddrId, long networkId, boolean releaseOnFailure) throws ResourceAllocationException, ResourceUnavailableException, + InsufficientAddressCapacityException, ConcurrentOperationException { + return associateIPToGuestNetwork(ipAddrId, networkId, releaseOnFailure); + } + + @DB + @Override + public IPAddressVO disassociatePortableIPToGuestNetwork(long ipId, long networkId) + throws ResourceAllocationException, ResourceUnavailableException, + InsufficientAddressCapacityException, ConcurrentOperationException { + + Account caller = UserContext.current().getCaller(); + Account owner = null; + + Network network = _networksDao.findById(networkId); + if (network == null) { + throw new InvalidParameterValueException("Invalid network id is given"); + } + + IPAddressVO ipToAssoc = _ipAddressDao.findById(ipId); + if (ipToAssoc != null) { + + if (ipToAssoc.getAssociatedWithNetworkId() == null) { + throw new InvalidParameterValueException("IP " + ipToAssoc + " is not assocaited with any network"); + } + + if (ipToAssoc.getAssociatedWithNetworkId() != network.getId()) { + throw new InvalidParameterValueException("IP " + ipToAssoc + " is not assocaited with network id" + networkId); + } + + DataCenter zone = _configMgr.getZone(network.getDataCenterId()); + if (zone.getNetworkType() == NetworkType.Advanced) { + if (network.getGuestType() == Network.GuestType.Shared) { + assert (isSharedNetworkOfferingWithServices(network.getNetworkOfferingId())); + _accountMgr.checkAccess(UserContext.current().getCaller(), AccessType.UseNetwork, false, network); + } + } else { + _accountMgr.checkAccess(caller, null, true, ipToAssoc); + } + owner = _accountMgr.getAccount(ipToAssoc.getAllocatedToAccountId()); + } else { + s_logger.debug("Unable to find ip address by id: " + ipId); + return null; + } + + DataCenter zone = _configMgr.getZone(network.getDataCenterId()); + + // Check that network belongs to IP owner - skip this check + // - if zone is basic zone as there is just one guest network, + // - if shared network in Advanced zone + // - and it belongs to the system + if (network.getAccountId() != owner.getId()) { + if (zone.getNetworkType() != NetworkType.Basic && !(zone.getNetworkType() == NetworkType.Advanced && network.getGuestType() == Network.GuestType.Shared)) { + throw new InvalidParameterValueException("The owner of the network is not the same as owner of the IP"); + } + } + + // Check if IP has any services (rules) associated in the network + List ipList = new ArrayList(); + PublicIp publicIp = PublicIp.createFromAddrAndVlan(ipToAssoc, _vlanDao.findById(ipToAssoc.getVlanId())); + ipList.add(publicIp); + Map> ipToServices = _networkModel.getIpToServices(ipList, false, true); + if (ipToServices != null & !ipToServices.isEmpty()) { + Set services = ipToServices.get(publicIp); + if (services != null && !services.isEmpty()) { + throw new InvalidParameterValueException("IP " + ipToAssoc + " has services and rules associated in the network " + networkId); + } + } + + IPAddressVO ip = _ipAddressDao.findById(ipId); + ip.setAssociatedWithNetworkId(null); + _ipAddressDao.update(ipId, ip); + + try { + boolean success = applyIpAssociations(network, false); + if (success) { + s_logger.debug("Successfully associated ip address " + ip.getAddress().addr() + " to network " + network); + } else { + s_logger.warn("Failed to associate ip address " + ip.getAddress().addr() + " to network " + network); + } + return ip; + } finally { + + } + } @Override @DB diff --git a/server/src/com/cloud/network/NetworkServiceImpl.java b/server/src/com/cloud/network/NetworkServiceImpl.java index e67026c4342..876ea8f6fc8 100755 --- a/server/src/com/cloud/network/NetworkServiceImpl.java +++ b/server/src/com/cloud/network/NetworkServiceImpl.java @@ -570,6 +570,12 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { return _networkMgr.allocatePortableIp(ipOwner, caller, zoneId, null, null); } + @Override + @ActionEvent(eventType = EventTypes.EVENT_PORTABLE_IP_RELEASE, eventDescription = "disassociating portable Ip", async = true) + public boolean releasePortableIpAddress(long ipAddressId) throws InsufficientAddressCapacityException { + return releaseIpAddressInternal(ipAddressId); + } + @Override @DB public boolean configure(final String name, final Map params) throws ConfigurationException { @@ -805,9 +811,13 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { } @Override - @DB @ActionEvent(eventType = EventTypes.EVENT_NET_IP_RELEASE, eventDescription = "disassociating Ip", async = true) public boolean releaseIpAddress(long ipAddressId) throws InsufficientAddressCapacityException { + return releaseIpAddressInternal(ipAddressId); + } + + @DB + private boolean releaseIpAddressInternal(long ipAddressId) throws InsufficientAddressCapacityException { Long userId = UserContext.current().getCallerUserId(); Account caller = UserContext.current().getCaller(); diff --git a/server/test/com/cloud/network/MockNetworkManagerImpl.java b/server/test/com/cloud/network/MockNetworkManagerImpl.java index f2d1fd404d0..c5210580952 100755 --- a/server/test/com/cloud/network/MockNetworkManagerImpl.java +++ b/server/test/com/cloud/network/MockNetworkManagerImpl.java @@ -87,6 +87,16 @@ public class MockNetworkManagerImpl extends ManagerBase implements NetworkManage return null; } + @Override + public IPAddressVO associatePortableIPToGuestNetwork(long ipAddrId, long networkId, boolean releaseOnFailure) throws ResourceAllocationException, ResourceUnavailableException { + return null;// TODO Auto-generated method stub + } + + @Override + public IPAddressVO disassociatePortableIPToGuestNetwork(long ipAddrId, long networkId) throws ResourceAllocationException, ResourceUnavailableException, InsufficientAddressCapacityException, ConcurrentOperationException { + return null; // TODO Auto-generated method stub + } + @Override public boolean releaseIpAddress(long ipAddressId) { // TODO Auto-generated method stub @@ -856,6 +866,11 @@ public class MockNetworkManagerImpl extends ManagerBase implements NetworkManage return null; } + @Override + public boolean releasePortableIpAddress(long ipAddressId) throws InsufficientAddressCapacityException { + return false;// TODO Auto-generated method stub + } + @Override public boolean isSecondaryIpSetForNic(long nicId) { // TODO Auto-generated method stub diff --git a/server/test/com/cloud/vpc/MockNetworkManagerImpl.java b/server/test/com/cloud/vpc/MockNetworkManagerImpl.java index e6e92573918..c7700004490 100644 --- a/server/test/com/cloud/vpc/MockNetworkManagerImpl.java +++ b/server/test/com/cloud/vpc/MockNetworkManagerImpl.java @@ -208,6 +208,11 @@ public class MockNetworkManagerImpl extends ManagerBase implements NetworkManage return null; } + @Override + public boolean releasePortableIpAddress(long ipAddressId) throws InsufficientAddressCapacityException { + return false;// TODO Auto-generated method stub + } + /* (non-Javadoc) * @see com.cloud.network.NetworkService#releaseIpAddress(long) */ @@ -1117,13 +1122,20 @@ public class MockNetworkManagerImpl extends ManagerBase implements NetworkManage return null; } + @Override + public IPAddressVO associatePortableIPToGuestNetwork(long ipAddrId, long networkId, boolean releaseOnFailure) throws ResourceAllocationException, ResourceUnavailableException { + return null;// TODO Auto-generated method stub + } - + @Override + public IPAddressVO disassociatePortableIPToGuestNetwork(long ipAddrId, long networkId) throws ResourceAllocationException, ResourceUnavailableException, InsufficientAddressCapacityException, ConcurrentOperationException { + return null;// TODO Auto-generated method stub + } /* (non-Javadoc) - * @see com.cloud.network.NetworkManager#setupDns(com.cloud.network.Network, com.cloud.network.Network.Provider) - */ + * @see com.cloud.network.NetworkManager#setupDns(com.cloud.network.Network, com.cloud.network.Network.Provider) + */ @Override public boolean setupDns(Network network, Provider provider) { // TODO Auto-generated method stub