diff --git a/api/src/com/cloud/api/commands/AssociateIPAddrCmd.java b/api/src/com/cloud/api/commands/AssociateIPAddrCmd.java index 4832451a091..5817fb836af 100644 --- a/api/src/com/cloud/api/commands/AssociateIPAddrCmd.java +++ b/api/src/com/cloud/api/commands/AssociateIPAddrCmd.java @@ -42,6 +42,7 @@ import com.cloud.exception.ResourceAllocationException; import com.cloud.exception.ResourceUnavailableException; import com.cloud.network.IpAddress; import com.cloud.network.Network; +import com.cloud.network.IpAddress.AllocatedBy; import com.cloud.user.Account; import com.cloud.user.UserContext; @@ -173,7 +174,7 @@ public class AssociateIPAddrCmd extends BaseAsyncCreateCmd { @Override public void create() throws ResourceAllocationException{ try { - IpAddress ip = _networkService.allocateIP(getNetworkId(), _accountService.getAccount(getEntityOwnerId())); + IpAddress ip = _networkService.allocateIP(getNetworkId(), _accountService.getAccount(getEntityOwnerId()), AllocatedBy.ipassoc); if (ip != null) { this.setEntityId(ip.getId()); } else { diff --git a/api/src/com/cloud/api/commands/DisableStaticNatCmd.java b/api/src/com/cloud/api/commands/DisableStaticNatCmd.java index 3835001aa98..d408177dab9 100644 --- a/api/src/com/cloud/api/commands/DisableStaticNatCmd.java +++ b/api/src/com/cloud/api/commands/DisableStaticNatCmd.java @@ -31,6 +31,7 @@ import com.cloud.event.EventTypes; import com.cloud.exception.InvalidParameterValueException; import com.cloud.exception.ResourceUnavailableException; import com.cloud.network.IpAddress; +import com.cloud.network.IpAddress.AllocatedBy; @Implementation(description="Disables static rule for given ip address", responseObject=SuccessResponse.class) public class DisableStaticNatCmd extends BaseAsyncCmd { diff --git a/api/src/com/cloud/api/commands/EnableStaticNatCmd.java b/api/src/com/cloud/api/commands/EnableStaticNatCmd.java index 71113216557..2ce3ee4a45e 100644 --- a/api/src/com/cloud/api/commands/EnableStaticNatCmd.java +++ b/api/src/com/cloud/api/commands/EnableStaticNatCmd.java @@ -28,6 +28,7 @@ import com.cloud.api.Parameter; import com.cloud.api.ServerApiException; import com.cloud.api.response.SuccessResponse; import com.cloud.exception.NetworkRuleConflictException; +import com.cloud.exception.ResourceUnavailableException; import com.cloud.user.Account; import com.cloud.uservm.UserVm; @@ -81,7 +82,7 @@ public class EnableStaticNatCmd extends BaseCmd{ } @Override - public void execute(){ + public void execute() throws ResourceUnavailableException{ try { boolean result = _rulesService.enableStaticNat(ipAddressId, virtualMachineId); if (result) { diff --git a/api/src/com/cloud/network/IpAddress.java b/api/src/com/cloud/network/IpAddress.java index 9b3973de109..3a2d4578b15 100644 --- a/api/src/com/cloud/network/IpAddress.java +++ b/api/src/com/cloud/network/IpAddress.java @@ -45,6 +45,11 @@ public interface IpAddress extends ControlledEntity{ Free // The IP address is ready to be allocated. } + enum AllocatedBy { + ipassoc, + elasticip + } + long getDataCenterId(); Ip getAddress(); @@ -77,4 +82,7 @@ public interface IpAddress extends ControlledEntity{ Long getAllocatedToAccountId(); Long getAllocatedInDomainId(); + + AllocatedBy getAllocatedBy(); + } diff --git a/api/src/com/cloud/network/NetworkService.java b/api/src/com/cloud/network/NetworkService.java index 5ef61df5e34..c6a985df650 100755 --- a/api/src/com/cloud/network/NetworkService.java +++ b/api/src/com/cloud/network/NetworkService.java @@ -30,6 +30,7 @@ import com.cloud.exception.InsufficientAddressCapacityException; import com.cloud.exception.InsufficientCapacityException; import com.cloud.exception.ResourceAllocationException; import com.cloud.exception.ResourceUnavailableException; +import com.cloud.network.IpAddress.AllocatedBy; import com.cloud.network.Network.Capability; import com.cloud.network.Network.Provider; import com.cloud.network.Network.Service; @@ -42,7 +43,7 @@ public interface NetworkService { List getIsolatedNetworksOwnedByAccountInZone(long zoneId, Account owner); - IpAddress allocateIP(long networkId, Account ipOwner) throws ResourceAllocationException, InsufficientAddressCapacityException, ConcurrentOperationException; + IpAddress allocateIP(long networkId, Account ipOwner, AllocatedBy allocatedBy) throws ResourceAllocationException, InsufficientAddressCapacityException, ConcurrentOperationException; /** * Associates a public IP address for a router. diff --git a/api/src/com/cloud/network/rules/RulesService.java b/api/src/com/cloud/network/rules/RulesService.java index cbbd07024c2..859f9e8eff4 100644 --- a/api/src/com/cloud/network/rules/RulesService.java +++ b/api/src/com/cloud/network/rules/RulesService.java @@ -22,6 +22,7 @@ import java.util.List; import com.cloud.api.commands.ListPortForwardingRulesCmd; import com.cloud.exception.NetworkRuleConflictException; import com.cloud.exception.ResourceUnavailableException; +import com.cloud.network.IpAddress.AllocatedBy; import com.cloud.user.Account; public interface RulesService { @@ -54,10 +55,8 @@ public interface RulesService { boolean applyPortForwardingRules(long ipAdddressId, Account caller) throws ResourceUnavailableException; - boolean enableStaticNat(long ipAddressId, long vmId) throws NetworkRuleConflictException; - - boolean disableStaticNat(long ipAddressId) throws ResourceUnavailableException; - + boolean enableStaticNat(long ipAddressId, long vmId) throws NetworkRuleConflictException, ResourceUnavailableException; + PortForwardingRule getPortForwardigRule(long ruleId); FirewallRule getFirewallRule(long ruleId); @@ -70,5 +69,7 @@ public interface RulesService { StaticNatRule buildStaticNatRule(FirewallRule rule); List getSourceCidrs(long ruleId); + + boolean disableStaticNat(long ipId) throws ResourceUnavailableException; } diff --git a/server/src/com/cloud/network/ExternalLoadBalancerDeviceManagerImpl.java b/server/src/com/cloud/network/ExternalLoadBalancerDeviceManagerImpl.java index 2eed0a4da5d..615e8dc97ef 100644 --- a/server/src/com/cloud/network/ExternalLoadBalancerDeviceManagerImpl.java +++ b/server/src/com/cloud/network/ExternalLoadBalancerDeviceManagerImpl.java @@ -73,6 +73,7 @@ import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.network.ExternalLoadBalancerDeviceVO.LBDeviceAllocationState; import com.cloud.network.ExternalLoadBalancerDeviceVO.LBDeviceState; import com.cloud.network.ExternalNetworkDeviceManager.NetworkDevice; +import com.cloud.network.IpAddress.AllocatedBy; import com.cloud.network.Network.Service; import com.cloud.network.Networks.TrafficType; import com.cloud.network.addr.PublicIp; @@ -476,7 +477,7 @@ public abstract class ExternalLoadBalancerDeviceManagerImpl extends AdapterBase String dedicatedLb = offering.getDedicatedLB()?"true":"false"; //acquire a public IP to associate with lb appliance (used as subnet IP to make the appliance part of private network) - PublicIp publicIp = _networkMgr.assignPublicIpAddress(guestConfig.getDataCenterId(), null, _accountMgr.getSystemAccount(), VlanType.VirtualNetwork, null, null); + PublicIp publicIp = _networkMgr.assignPublicIpAddress(guestConfig.getDataCenterId(), null, _accountMgr.getSystemAccount(), VlanType.VirtualNetwork, null, null, AllocatedBy.ipassoc); String publicIPNetmask = publicIp.getVlanNetmask(); String publicIPgateway = publicIp.getVlanGateway(); String publicIPVlanTag = publicIp.getVlanTag(); diff --git a/server/src/com/cloud/network/IPAddressVO.java b/server/src/com/cloud/network/IPAddressVO.java index e884d740df1..4d2c64fc49c 100644 --- a/server/src/com/cloud/network/IPAddressVO.java +++ b/server/src/com/cloud/network/IPAddressVO.java @@ -96,6 +96,10 @@ public class IPAddressVO implements IpAddress, Identity { @Column(name="physical_network_id") private Long physicalNetworkId; + @Column(name="allocated_by") + @Enumerated(value=EnumType.STRING) + private AllocatedBy allocatedBy; + @Column(name="account_id") @Transient private Long accountId = null; @@ -265,4 +269,13 @@ public class IPAddressVO implements IpAddress, Identity { public void setPhysicalNetworkId(Long physicalNetworkId) { this.physicalNetworkId = physicalNetworkId; } + + @Override + public AllocatedBy getAllocatedBy() { + return allocatedBy; + } + + public void setAllocatedBy(AllocatedBy allocatedBy) { + this.allocatedBy = allocatedBy; + } } diff --git a/server/src/com/cloud/network/NetworkManager.java b/server/src/com/cloud/network/NetworkManager.java index 7449942dd87..be345f3a9f7 100755 --- a/server/src/com/cloud/network/NetworkManager.java +++ b/server/src/com/cloud/network/NetworkManager.java @@ -35,6 +35,7 @@ import com.cloud.exception.InsufficientAddressCapacityException; import com.cloud.exception.InsufficientCapacityException; import com.cloud.exception.ResourceUnavailableException; import com.cloud.hypervisor.Hypervisor.HypervisorType; +import com.cloud.network.IpAddress.AllocatedBy; import com.cloud.network.Network.Capability; import com.cloud.network.Network.Provider; import com.cloud.network.Network.Service; @@ -71,10 +72,11 @@ public interface NetworkManager extends NetworkService { * @param type * @param networkId * @param requestedIp TODO + * @param allocatedBy TODO * @return * @throws InsufficientAddressCapacityException */ - PublicIp assignPublicIpAddress(long dcId, Long podId, Account owner, VlanType type, Long networkId, String requestedIp) throws InsufficientAddressCapacityException; + PublicIp assignPublicIpAddress(long dcId, Long podId, Account owner, VlanType type, Long networkId, String requestedIp, AllocatedBy allocatedBy) throws InsufficientAddressCapacityException; /** * assigns a source nat ip address to an account within a network. diff --git a/server/src/com/cloud/network/NetworkManagerImpl.java b/server/src/com/cloud/network/NetworkManagerImpl.java index 972044dd9ad..68cfd3d4461 100755 --- a/server/src/com/cloud/network/NetworkManagerImpl.java +++ b/server/src/com/cloud/network/NetworkManagerImpl.java @@ -103,6 +103,7 @@ import com.cloud.host.HostVO; import com.cloud.host.Status; import com.cloud.host.dao.HostDao; import com.cloud.hypervisor.Hypervisor.HypervisorType; +import com.cloud.network.IpAddress.AllocatedBy; import com.cloud.network.IpAddress.State; import com.cloud.network.Network.Capability; import com.cloud.network.Network.GuestType; @@ -340,12 +341,12 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag } @Override - public PublicIp assignPublicIpAddress(long dcId, Long podId, Account owner, VlanType type, Long networkId, String requestedIp) throws InsufficientAddressCapacityException { - return fetchNewPublicIp(dcId, podId, null, owner, type, networkId, false, true, requestedIp); + public PublicIp assignPublicIpAddress(long dcId, Long podId, Account owner, VlanType type, Long networkId, String requestedIp, AllocatedBy allocatedBy) throws InsufficientAddressCapacityException { + return fetchNewPublicIp(dcId, podId, null, owner, type, networkId, false, true, requestedIp, allocatedBy); } @DB - public PublicIp fetchNewPublicIp(long dcId, Long podId, Long vlanDbId, Account owner, VlanType vlanUse, Long networkId, boolean sourceNat, boolean assign, String requestedIp) + public PublicIp fetchNewPublicIp(long dcId, Long podId, Long vlanDbId, Account owner, VlanType vlanUse, Long networkId, boolean sourceNat, boolean assign, String requestedIp, AllocatedBy allocatedBy) throws InsufficientAddressCapacityException { StringBuilder errorMessage = new StringBuilder("Unable to get ip adress in "); Transaction txn = Transaction.currentTxn(); @@ -401,6 +402,7 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag addr.setAllocatedTime(new Date()); addr.setAllocatedInDomainId(owner.getDomainId()); addr.setAllocatedToAccountId(owner.getId()); + addr.setAllocatedBy(allocatedBy); if (assign) { markPublicIpAsAllocated(addr); @@ -505,7 +507,7 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag vlanId = maps.get(0).getVlanDbId(); } - ip = fetchNewPublicIp(dcId, null, vlanId, owner, VlanType.VirtualNetwork, network.getId(), true, false, null); + ip = fetchNewPublicIp(dcId, null, vlanId, owner, VlanType.VirtualNetwork, network.getId(), true, false, null, AllocatedBy.ipassoc); sourceNat = ip.ip(); markPublicIpAsAllocated(sourceNat); @@ -920,7 +922,7 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag @Override @DB @ActionEvent(eventType = EventTypes.EVENT_NET_IP_ASSIGN, eventDescription = "allocating Ip", create = true) - public IpAddress allocateIP(long networkId, Account ipOwner) throws ResourceAllocationException, InsufficientAddressCapacityException, ConcurrentOperationException { + public IpAddress allocateIP(long networkId, Account ipOwner, AllocatedBy allocatedBy) throws ResourceAllocationException, InsufficientAddressCapacityException, ConcurrentOperationException { Account caller = UserContext.current().getCaller(); long userId = UserContext.current().getCallerUserId(); @@ -1007,7 +1009,7 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag } } - ip = fetchNewPublicIp(zone.getId(), null, null, ipOwner, vlanType, network.getId(), isSourceNat, assign, null); + ip = fetchNewPublicIp(zone.getId(), null, null, ipOwner, vlanType, network.getId(), isSourceNat, assign, null, allocatedBy); if (ip == null) { throw new InsufficientAddressCapacityException("Unable to find available public IP addresses", DataCenter.class, zone.getId()); @@ -3461,6 +3463,7 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag addr.setAllocatedTime(new Date()); addr.setAllocatedInDomainId(owner.getDomainId()); addr.setAllocatedToAccountId(owner.getId()); + addr.setAllocatedBy(AllocatedBy.ipassoc); addr.setState(IpAddress.State.Allocating); markPublicIpAsAllocated(addr); } @@ -5861,7 +5864,7 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag try { s_logger.debug("Allocating elastic IP address for load balancer rule..."); //allocate ip - ip = allocateIP(networkId, owner); + ip = allocateIP(networkId, owner, AllocatedBy.elasticip); //apply ip associations ip = associateIP(ip.getId()); } catch (ResourceAllocationException ex) { @@ -5887,7 +5890,7 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag if (networkId != null) { Network guestNetwork = getNetwork(networkId); NetworkOffering offering = _configMgr.getNetworkOffering(guestNetwork.getNetworkOfferingId()); - if (offering.getElasticIp()) { + if (offering.getElasticIp() && ip.getAllocatedBy() == AllocatedBy.elasticip) { UserContext ctx = UserContext.current(); if (!releasePublicIpAddress(ip.getId(), ctx.getCallerUserId(), ctx.getCaller())) { s_logger.warn("Unable to release elastic ip address id=" + ip.getId()); diff --git a/server/src/com/cloud/network/addr/PublicIp.java b/server/src/com/cloud/network/addr/PublicIp.java index a147aa96e3c..03c77af18c1 100644 --- a/server/src/com/cloud/network/addr/PublicIp.java +++ b/server/src/com/cloud/network/addr/PublicIp.java @@ -181,4 +181,9 @@ public class PublicIp implements PublicIpAddress { public Long getAllocatedInDomainId() { return _addr.getAllocatedInDomainId(); } + + @Override + public AllocatedBy getAllocatedBy() { + return _addr.getAllocatedBy(); + } } diff --git a/server/src/com/cloud/network/dao/IPAddressDaoImpl.java b/server/src/com/cloud/network/dao/IPAddressDaoImpl.java index 49607e09063..3e9134b620b 100755 --- a/server/src/com/cloud/network/dao/IPAddressDaoImpl.java +++ b/server/src/com/cloud/network/dao/IPAddressDaoImpl.java @@ -34,7 +34,6 @@ import com.cloud.network.IPAddressVO; import com.cloud.network.IpAddress.State; import com.cloud.utils.component.ComponentLocator; import com.cloud.utils.db.DB; -import com.cloud.utils.db.Filter; import com.cloud.utils.db.GenericDaoBase; import com.cloud.utils.db.GenericSearchBuilder; import com.cloud.utils.db.JoinBuilder; @@ -43,7 +42,6 @@ import com.cloud.utils.db.SearchCriteria; import com.cloud.utils.db.SearchCriteria.Func; import com.cloud.utils.db.SearchCriteria.Op; import com.cloud.utils.db.Transaction; -import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.net.Ip; @Local(value = { IPAddressDao.class }) @@ -137,42 +135,6 @@ public class IPAddressDaoImpl extends GenericDaoBase implemen return update(vo, sc) >= 1; } - /** - * @deprecated This method is now deprecated because vlan has been - * added. The actual method is now within NetworkManager. - */ - @Deprecated - public IPAddressVO assignIpAddress(long accountId, long domainId, long vlanDbId, boolean sourceNat) { - Transaction txn = Transaction.currentTxn(); - txn.start(); - - SearchCriteria sc = VlanDbIdSearchUnallocated.create(); - sc.setParameters("vlanDbId", vlanDbId); - - Filter filter = new Filter(IPAddressVO.class, "vlanId", true, 0l, 1l); - - List ips = this.lockRows(sc, filter, true); - if (ips.size() == 0) { - s_logger.info("Unable to get an ip address in " + vlanDbId); - return null; - } - - IPAddressVO ip = ips.get(0); - - ip.setAllocatedToAccountId(accountId); - ip.setAllocatedTime(new Date()); - ip.setAllocatedInDomainId(domainId); - ip.setSourceNat(sourceNat); - ip.setState(State.Allocated); - - if (!update(ip.getId(), ip)) { - throw new CloudRuntimeException("How can I lock the row but can't update it: " + ip.getAddress()); - } - - txn.commit(); - return ip; - } - @Override public void unassignIpAddress(long ipAddressId) { IPAddressVO address = createForUpdate(); @@ -184,6 +146,7 @@ public class IPAddressDaoImpl extends GenericDaoBase implemen address.setAssociatedWithVmId(null); address.setState(State.Free); address.setAssociatedWithNetworkId(null); + address.setAllocatedBy(null); update(ipAddressId, address); } diff --git a/server/src/com/cloud/network/guru/DirectNetworkGuru.java b/server/src/com/cloud/network/guru/DirectNetworkGuru.java index 6c337239267..8ce566c9bf1 100755 --- a/server/src/com/cloud/network/guru/DirectNetworkGuru.java +++ b/server/src/com/cloud/network/guru/DirectNetworkGuru.java @@ -34,6 +34,7 @@ import com.cloud.exception.InsufficientVirtualNetworkCapcityException; import com.cloud.exception.InvalidParameterValueException; import com.cloud.network.IPAddressVO; import com.cloud.network.Network; +import com.cloud.network.IpAddress.AllocatedBy; import com.cloud.network.Network.Service; import com.cloud.network.Network.State; import com.cloud.network.NetworkManager; @@ -154,7 +155,7 @@ public class DirectNetworkGuru extends AdapterBase implements NetworkGuru { protected void getIp(NicProfile nic, DataCenter dc, VirtualMachineProfile vm, Network network, String requestedIp) throws InsufficientVirtualNetworkCapcityException, InsufficientAddressCapacityException, ConcurrentOperationException { if (nic.getIp4Address() == null) { - PublicIp ip = _networkMgr.assignPublicIpAddress(dc.getId(), null, vm.getOwner(), VlanType.DirectAttached, network.getId(), requestedIp); + PublicIp ip = _networkMgr.assignPublicIpAddress(dc.getId(), null, vm.getOwner(), VlanType.DirectAttached, network.getId(), requestedIp, AllocatedBy.ipassoc); nic.setIp4Address(ip.getAddress().toString()); nic.setGateway(ip.getGateway()); nic.setNetmask(ip.getNetmask()); diff --git a/server/src/com/cloud/network/guru/DirectPodBasedNetworkGuru.java b/server/src/com/cloud/network/guru/DirectPodBasedNetworkGuru.java index 9b02126cd7f..d438d6351c4 100755 --- a/server/src/com/cloud/network/guru/DirectPodBasedNetworkGuru.java +++ b/server/src/com/cloud/network/guru/DirectPodBasedNetworkGuru.java @@ -42,6 +42,7 @@ import com.cloud.exception.InsufficientVirtualNetworkCapcityException; import com.cloud.network.IPAddressVO; import com.cloud.network.Network; import com.cloud.network.NetworkManager; +import com.cloud.network.IpAddress.AllocatedBy; import com.cloud.network.Networks.AddressFormat; import com.cloud.network.Networks.BroadcastDomainType; import com.cloud.network.Networks.TrafficType; @@ -162,7 +163,7 @@ public class DirectPodBasedNetworkGuru extends DirectNetworkGuru { InsufficientAddressCapacityException, ConcurrentOperationException { DataCenter dc = _dcDao.findById(pod.getDataCenterId()); if (nic.getIp4Address() == null) { - PublicIp ip = _networkMgr.assignPublicIpAddress(dc.getId(), pod.getId(), vm.getOwner(), VlanType.DirectAttached, network.getId(), null); + PublicIp ip = _networkMgr.assignPublicIpAddress(dc.getId(), pod.getId(), vm.getOwner(), VlanType.DirectAttached, network.getId(), null, AllocatedBy.ipassoc); nic.setIp4Address(ip.getAddress().toString()); nic.setFormat(AddressFormat.Ip4); nic.setGateway(ip.getGateway()); diff --git a/server/src/com/cloud/network/guru/PublicNetworkGuru.java b/server/src/com/cloud/network/guru/PublicNetworkGuru.java index 835127eb340..fc290e88ada 100755 --- a/server/src/com/cloud/network/guru/PublicNetworkGuru.java +++ b/server/src/com/cloud/network/guru/PublicNetworkGuru.java @@ -36,6 +36,7 @@ import com.cloud.exception.InsufficientAddressCapacityException; import com.cloud.exception.InsufficientVirtualNetworkCapcityException; import com.cloud.network.IPAddressVO; import com.cloud.network.Network; +import com.cloud.network.IpAddress.AllocatedBy; import com.cloud.network.Network.State; import com.cloud.network.NetworkManager; import com.cloud.network.NetworkProfile; @@ -116,7 +117,7 @@ public class PublicNetworkGuru extends AdapterBase implements NetworkGuru { protected void getIp(NicProfile nic, DataCenter dc, VirtualMachineProfile vm, Network network) throws InsufficientVirtualNetworkCapcityException, InsufficientAddressCapacityException, ConcurrentOperationException { if (nic.getIp4Address() == null) { - PublicIp ip = _networkMgr.assignPublicIpAddress(dc.getId(), null, vm.getOwner(), VlanType.VirtualNetwork, null, null); + PublicIp ip = _networkMgr.assignPublicIpAddress(dc.getId(), null, vm.getOwner(), VlanType.VirtualNetwork, null, null, AllocatedBy.ipassoc); nic.setIp4Address(ip.getAddress().toString()); nic.setGateway(ip.getGateway()); nic.setNetmask(ip.getNetmask()); diff --git a/server/src/com/cloud/network/lb/ElasticLoadBalancerManagerImpl.java b/server/src/com/cloud/network/lb/ElasticLoadBalancerManagerImpl.java index aea6ee2694e..05df6829c44 100644 --- a/server/src/com/cloud/network/lb/ElasticLoadBalancerManagerImpl.java +++ b/server/src/com/cloud/network/lb/ElasticLoadBalancerManagerImpl.java @@ -75,6 +75,7 @@ import com.cloud.network.ElasticLbVmMapVO; import com.cloud.network.IPAddressVO; import com.cloud.network.LoadBalancerVO; import com.cloud.network.Network; +import com.cloud.network.IpAddress.AllocatedBy; import com.cloud.network.Network.Provider; import com.cloud.network.Network.Service; import com.cloud.network.NetworkManager; @@ -595,7 +596,8 @@ public class ElasticLoadBalancerManagerImpl implements Network frontEndNetwork = _networkMgr.getNetwork(guestNetworkId); Transaction txn = Transaction.currentTxn(); txn.start(); - PublicIp ip = _networkMgr.assignPublicIpAddress(frontEndNetwork.getDataCenterId(), null, account, VlanType.DirectAttached, frontEndNetwork.getId(), null); + + PublicIp ip = _networkMgr.assignPublicIpAddress(frontEndNetwork.getDataCenterId(), null, account, VlanType.DirectAttached, frontEndNetwork.getId(), null, AllocatedBy.elasticip); IPAddressVO ipvo = _ipAddressDao.findById(ip.getId()); ipvo.setAssociatedWithNetworkId(frontEndNetwork.getId()); _ipAddressDao.update(ipvo.getId(), ipvo); diff --git a/server/src/com/cloud/network/rules/RulesManager.java b/server/src/com/cloud/network/rules/RulesManager.java index 3f36dc2fb30..1f0be0727d7 100644 --- a/server/src/com/cloud/network/rules/RulesManager.java +++ b/server/src/com/cloud/network/rules/RulesManager.java @@ -22,6 +22,7 @@ import java.util.List; import com.cloud.exception.NetworkRuleConflictException; import com.cloud.exception.ResourceUnavailableException; import com.cloud.network.IpAddress; +import com.cloud.network.IpAddress.AllocatedBy; import com.cloud.user.Account; import com.cloud.uservm.UserVm; @@ -72,5 +73,7 @@ public interface RulesManager extends RulesService { boolean applyStaticNatsForNetwork(long networkId, boolean continueOnError, Account caller); boolean enableElasticIpAndStaticNatForVm(UserVm vm, boolean stopOnError); + + boolean disableStaticNat(long ipAddressId, AllocatedBy allocatedBy) throws ResourceUnavailableException; } diff --git a/server/src/com/cloud/network/rules/RulesManagerImpl.java b/server/src/com/cloud/network/rules/RulesManagerImpl.java index 55ab95a6936..8b5f50c711d 100755 --- a/server/src/com/cloud/network/rules/RulesManagerImpl.java +++ b/server/src/com/cloud/network/rules/RulesManagerImpl.java @@ -41,6 +41,7 @@ import com.cloud.exception.NetworkRuleConflictException; import com.cloud.exception.ResourceUnavailableException; import com.cloud.network.IPAddressVO; import com.cloud.network.IpAddress; +import com.cloud.network.IpAddress.AllocatedBy; import com.cloud.network.Network; import com.cloud.network.Network.Service; import com.cloud.network.NetworkManager; @@ -320,7 +321,7 @@ public class RulesManagerImpl implements RulesManager, RulesService, Manager { } @Override - public boolean enableStaticNat(long ipId, long vmId) throws NetworkRuleConflictException { + public boolean enableStaticNat(long ipId, long vmId) throws NetworkRuleConflictException, ResourceUnavailableException { Account caller = UserContext.current().getCaller(); @@ -356,25 +357,7 @@ public class RulesManagerImpl implements RulesManager, RulesService, Manager { } // Verify ip address parameter - if (ipAddress.isSourceNat()) { - throw new InvalidParameterValueException("Can't enable static, ip address id=" + ipId + " is a sourceNat ip address"); - } - - if (!ipAddress.isOneToOneNat()) { // Dont allow to enable static nat if PF/LB rules exist for the IP - List portForwardingRules = _firewallDao.listByIpAndPurposeAndNotRevoked(ipId, Purpose.PortForwarding); - if (portForwardingRules != null && !portForwardingRules.isEmpty()) { - throw new NetworkRuleConflictException("Failed to enable static nat for the ip address id=" + ipId + " as it already has PortForwarding rules assigned"); - } - - List loadBalancingRules = _firewallDao.listByIpAndPurposeAndNotRevoked(ipId, Purpose.LoadBalancing); - if (loadBalancingRules != null && !loadBalancingRules.isEmpty()) { - throw new NetworkRuleConflictException("Failed to enable static nat for the ip address id=" + ipId + " as it already has LoadBalancing rules assigned"); - } - } else { - if (ipAddress.getAssociatedWithVmId() != null && ipAddress.getAssociatedWithVmId().longValue() != vmId) { - throw new NetworkRuleConflictException("Failed to enable static for the ip address id=" + ipId + " and vm id=" + vmId + " as it's already assigned to antoher vm"); - } - } + isIpReadyForStaticNat(vmId, ipAddress); // If there is public ip address already associated with the vm, throw an exception IPAddressVO ip = _ipAddressDao.findByAssociatedVmId(vmId); @@ -406,6 +389,45 @@ public class RulesManagerImpl implements RulesManager, RulesService, Manager { } } + protected void isIpReadyForStaticNat(long vmId, IPAddressVO ipAddress) throws NetworkRuleConflictException, ResourceUnavailableException { + if (ipAddress.isSourceNat()) { + throw new InvalidParameterValueException("Can't enable static, ip address " + ipAddress + " is a sourceNat ip address"); + } + + if (!ipAddress.isOneToOneNat()) { // Dont allow to enable static nat if PF/LB rules exist for the IP + List portForwardingRules = _firewallDao.listByIpAndPurposeAndNotRevoked(ipAddress.getId(), Purpose.PortForwarding); + if (portForwardingRules != null && !portForwardingRules.isEmpty()) { + throw new NetworkRuleConflictException("Failed to enable static nat for the ip address " + ipAddress + " as it already has PortForwarding rules assigned"); + } + + List loadBalancingRules = _firewallDao.listByIpAndPurposeAndNotRevoked(ipAddress.getId(), Purpose.LoadBalancing); + if (loadBalancingRules != null && !loadBalancingRules.isEmpty()) { + throw new NetworkRuleConflictException("Failed to enable static nat for the ip address " + ipAddress + " as it already has LoadBalancing rules assigned"); + } + } + + if (ipAddress.getAssociatedWithVmId() != null && ipAddress.getAssociatedWithVmId().longValue() != vmId) { + Long networkId = ipAddress.getAssociatedWithNetworkId(); + boolean reassignStaticNat = false; + if (networkId != null) { + Network guestNetwork = _networkMgr.getNetwork(networkId); + NetworkOffering offering = _configMgr.getNetworkOffering(guestNetwork.getNetworkOfferingId()); + if (offering.getElasticIp()) { + reassignStaticNat = true; + } + } + if (!reassignStaticNat) { + throw new NetworkRuleConflictException("Failed to enable static for the ip address " + ipAddress + " and vm id=" + vmId + " as it's already assigned to antoher vm"); + } + //unassign old static nat rule + s_logger.debug("Disassociating static nat for "); + if (!disableStaticNat(ipAddress.getId(), AllocatedBy.ipassoc)) { + throw new CloudRuntimeException("Failed to disable old static nat rule for vm id=" + vmId); + } + } + + } + @Override @ActionEvent(eventType = EventTypes.EVENT_NET_RULE_DELETE, eventDescription = "revoking forwarding rule", async = true) @@ -996,9 +1018,32 @@ public class RulesManagerImpl implements RulesManager, RulesService, Manager { public List listByNetworkId(long networkId) { return _portForwardingDao.listByNetwork(networkId); } + + @Override + public boolean disableStaticNat(long ipId) throws ResourceUnavailableException{ + Account caller = UserContext.current().getCaller(); + IPAddressVO ipAddress = _ipAddressDao.findById(ipId); + checkIpAndUserVm(ipAddress, null, caller); + + Long vmId = ipAddress.getAssociatedWithVmId(); + + boolean success = disableStaticNat(ipId, AllocatedBy.ipassoc); + if (success && vmId != null) { + s_logger.debug("Allocating ip and enabling static nat for vm id=" + vmId + " as a part of disassociateIp command"); + UserVm vm = _vmDao.findById(vmId); + success = enableElasticIpAndStaticNatForVm(vm, true); + if (!success) { + s_logger.warn("Failed to allocate ip and enable static nat for vm id=" + vmId + " as a part of disassociateIp command"); + } else { + s_logger.debug("Successfully allocated ip and enabled static nat for vm id=" + vmId + " as a part of disassociateIp command"); + } + } + + return success; + } @Override - public boolean disableStaticNat(long ipId) throws ResourceUnavailableException { + public boolean disableStaticNat(long ipId, AllocatedBy allocatedBy) throws ResourceUnavailableException { boolean success = true; UserContext ctx = UserContext.current(); @@ -1031,11 +1076,17 @@ public class RulesManagerImpl implements RulesManager, RulesService, Manager { if (success) { ipAddress.setOneToOneNat(false); ipAddress.setAssociatedWithVmId(null); + if (allocatedBy != null) { + ipAddress.setAllocatedBy(allocatedBy); + } _ipAddressDao.update(ipAddress.getId(), ipAddress); + + if (!_networkMgr.handleElasticIpRelease(ipAddress)) { s_logger.warn("Failed to release elastic ip address " + ipAddress); - return false; + success = false; } + return true; } else { s_logger.warn("Failed to disable one to one nat for the ip address id" + ipId); diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index 9dcb9e0df0c..416d52fc0b0 100755 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -1264,7 +1264,7 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager IPAddressVO ip = _ipAddressDao.findByAssociatedVmId(vmId); try { if (ip != null) { - if (_rulesMgr.disableStaticNat(ip.getId())) { + if (_rulesMgr.disableStaticNat(ip.getId(), null)) { s_logger.debug("Disabled 1-1 nat for ip address " + ip + " as a part of vm id=" + vmId + " expunge"); } else { s_logger.warn("Failed to disable static nat for ip address " + ip + " as a part of vm id=" + vmId + " expunge"); diff --git a/server/test/com/cloud/network/MockNetworkManagerImpl.java b/server/test/com/cloud/network/MockNetworkManagerImpl.java index 3c40230fb84..fb42122d8aa 100755 --- a/server/test/com/cloud/network/MockNetworkManagerImpl.java +++ b/server/test/com/cloud/network/MockNetworkManagerImpl.java @@ -24,6 +24,7 @@ import com.cloud.exception.InsufficientCapacityException; import com.cloud.exception.ResourceAllocationException; import com.cloud.exception.ResourceUnavailableException; import com.cloud.hypervisor.Hypervisor.HypervisorType; +import com.cloud.network.IpAddress.AllocatedBy; import com.cloud.network.Network.Capability; import com.cloud.network.Network.GuestType; import com.cloud.network.Network.Provider; @@ -58,7 +59,7 @@ public class MockNetworkManagerImpl implements NetworkManager, Manager, NetworkS } @Override - public IpAddress allocateIP(long networkId, Account ipOwner) throws ResourceAllocationException, InsufficientAddressCapacityException, ConcurrentOperationException { + public IpAddress allocateIP(long networkId, Account ipOwner, AllocatedBy allocatedBy) throws ResourceAllocationException, InsufficientAddressCapacityException, ConcurrentOperationException { // TODO Auto-generated method stub return null; } @@ -382,7 +383,7 @@ public class MockNetworkManagerImpl implements NetworkManager, Manager, NetworkS } @Override - public PublicIp assignPublicIpAddress(long dcId, Long podId, Account owner, VlanType type, Long networkId, String requestedIp) throws InsufficientAddressCapacityException { + public PublicIp assignPublicIpAddress(long dcId, Long podId, Account owner, VlanType type, Long networkId, String requestedIp, AllocatedBy allocatedBy) throws InsufficientAddressCapacityException { // TODO Auto-generated method stub return null; } diff --git a/setup/db/create-schema.sql b/setup/db/create-schema.sql index 7b22cd2e55f..9ed33c83c14 100755 --- a/setup/db/create-schema.sql +++ b/setup/db/create-schema.sql @@ -918,6 +918,7 @@ CREATE TABLE `cloud`.`user_ip_address` ( `source_network_id` bigint unsigned NOT NULL COMMENT 'network id ip belongs to', `network_id` bigint unsigned COMMENT 'network this public ip address is associated with', `physical_network_id` bigint unsigned NOT NULL COMMENT 'physical network id that this configuration is based on', + `allocated_by` char (32) COMMENT 'the way ip address was allocated; can be by ipassoc or vmdeploy' PRIMARY KEY (`id`), UNIQUE (`public_ip_address`, `source_network_id`), CONSTRAINT `fk_user_ip_address__source_network_id` FOREIGN KEY (`source_network_id`) REFERENCES `networks`(`id`),