From 0f6f231ee62d4ecafa8e12b1bbda14d5547e8232 Mon Sep 17 00:00:00 2001 From: Alena Prokharchyk Date: Thu, 12 Jan 2012 16:56:54 -0800 Subject: [PATCH] Elastic IP - when deployVm, get ip address and enable static nat on it. On vm destroy release the Ip --- .../src/com/cloud/network/NetworkManager.java | 4 ++ .../com/cloud/network/NetworkManagerImpl.java | 29 +++++++++ .../lb/LoadBalancingRulesManagerImpl.java | 35 +++-------- .../cloud/server/ConfigurationServerImpl.java | 2 +- .../src/com/cloud/vm/UserVmManagerImpl.java | 61 ++++++++++++++++++- 5 files changed, 100 insertions(+), 31 deletions(-) diff --git a/server/src/com/cloud/network/NetworkManager.java b/server/src/com/cloud/network/NetworkManager.java index ded421d67f0..4c6d9b9c7b4 100755 --- a/server/src/com/cloud/network/NetworkManager.java +++ b/server/src/com/cloud/network/NetworkManager.java @@ -278,4 +278,8 @@ public interface NetworkManager extends NetworkService { Capability cap, String capValue); Provider getDefaultUniqueProviderForService(String serviceName); + + IpAddress assignElasticIp(long networkId, Account owner, + boolean forElasticLb, boolean forElasticIp) + throws InsufficientAddressCapacityException; } diff --git a/server/src/com/cloud/network/NetworkManagerImpl.java b/server/src/com/cloud/network/NetworkManagerImpl.java index 0eecc0dbe1a..e732f0b44c7 100755 --- a/server/src/com/cloud/network/NetworkManagerImpl.java +++ b/server/src/com/cloud/network/NetworkManagerImpl.java @@ -5838,4 +5838,33 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag } } } + + public IpAddress assignElasticIp(long networkId, Account owner, boolean forElasticLb, boolean forElasticIp) throws InsufficientAddressCapacityException{ + Network guestNetwork = getNetwork(networkId); + NetworkOffering off = _configMgr.getNetworkOffering(guestNetwork.getNetworkOfferingId()); + IpAddress ip = null; + if ((off.getElasticLb() && forElasticLb) || (off.getElasticIp() && forElasticIp)) { + + try { + s_logger.debug("Allocating elastic IP address for load balancer rule..."); + //allocate ip + ip = allocateIP(networkId, owner); + //apply ip associations + ip = associateIP(ip.getId()); + } catch (ResourceAllocationException ex) { + throw new CloudRuntimeException("Failed to allocate elastic ip due to ", ex); + } catch (ConcurrentOperationException ex) { + throw new CloudRuntimeException("Failed to allocate elastic lb ip due to ", ex); + } catch (ResourceUnavailableException ex) { + throw new CloudRuntimeException("Failed to allocate elastic lb ip due to ", ex); + } + + if (ip == null) { + throw new CloudRuntimeException("Failed to allocate elastic ip"); + } + } + + return ip; + } + } diff --git a/server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java b/server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java index 97b3b5cf7ba..948bafb78f5 100755 --- a/server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java +++ b/server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java @@ -47,12 +47,10 @@ import com.cloud.event.EventTypes; import com.cloud.event.UsageEventVO; import com.cloud.event.dao.EventDao; import com.cloud.event.dao.UsageEventDao; -import com.cloud.exception.ConcurrentOperationException; import com.cloud.exception.InsufficientAddressCapacityException; 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; import com.cloud.network.IPAddressVO; import com.cloud.network.IpAddress; @@ -627,37 +625,18 @@ public class LoadBalancingRulesManagerImpl implements LoadBalancingRulesMa _networkMgr.checkIpForService(ipAddressVo, Service.Lb); } + Network guestNetwork = _networkMgr.getNetwork(lb.getNetworkId()); + NetworkOffering off = _configMgr.getNetworkOffering(guestNetwork.getNetworkOfferingId()); + if (ipAddressVo != null) { + throw new InvalidParameterValueException("Can't specify ipAddressId when create LB in the network with LB capability " + Capability.ElasticLb.getName()); + } + LoadBalancer result = _elbMgr.handleCreateLoadBalancerRule(lb, lbOwner, lb.getNetworkId()); if (result == null){ - Network guestNetwork = _networkMgr.getNetwork(lb.getNetworkId()); - NetworkOffering off = _configMgr.getNetworkOffering(guestNetwork.getNetworkOfferingId()); if (off.getElasticLb()) { - if (ipAddressVo != null) { - throw new InvalidParameterValueException("Can't specify ipAddressId when create LB in the network with LB capability " + Capability.ElasticLb.getName()); - } - - IpAddress ip = null; - try { - s_logger.debug("Allocating elastic IP address for load balancer rule..."); - //allocate ip - ip = _networkMgr.allocateIP(lb.getNetworkId(), lbOwner); - //apply ip associations - ip = _networkMgr.associateIP(ip.getId()); - } catch (ResourceAllocationException ex) { - throw new CloudRuntimeException("Failed to allocate elastic lb ip due to ", ex); - } catch (ConcurrentOperationException ex) { - throw new CloudRuntimeException("Failed to allocate elastic lb ip due to ", ex); - } catch (ResourceUnavailableException ex) { - throw new CloudRuntimeException("Failed to allocate elastic lb ip due to ", ex); - } - - if (ip == null) { - throw new CloudRuntimeException("Failed to allocate elastic lb ip"); - } - + IpAddress ip = _networkMgr.assignElasticIp(lb.getNetworkId(), lbOwner, true, false); lb.setSourceIpAddressId(ip.getId()); } - result = createLoadBalancer(lb, openFirewall); } diff --git a/server/src/com/cloud/server/ConfigurationServerImpl.java b/server/src/com/cloud/server/ConfigurationServerImpl.java index 659bcc8dc90..de48a9619a5 100755 --- a/server/src/com/cloud/server/ConfigurationServerImpl.java +++ b/server/src/com/cloud/server/ConfigurationServerImpl.java @@ -953,7 +953,7 @@ public class ConfigurationServerImpl implements ConfigurationServer { NetworkOffering.DefaultSharedEIPandELBNetworkOffering, "Offering for Shared networks with Elastic IP and Elastic LB capabilities", TrafficType.Guest, - true, true, null, null, true, Availability.Optional, + false, true, null, null, true, Availability.Optional, null, Network.GuestType.Shared, true, false, false, false, true, true); defaultNetscalerNetworkOffering.setState(NetworkOffering.State.Enabled); diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index 6e44261cbeb..84cfaea33f3 100755 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -119,6 +119,7 @@ import com.cloud.host.dao.HostDao; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.hypervisor.dao.HypervisorCapabilitiesDao; import com.cloud.network.IPAddressVO; +import com.cloud.network.IpAddress; import com.cloud.network.Network; import com.cloud.network.Network.Provider; import com.cloud.network.Network.Service; @@ -1260,7 +1261,7 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager s_logger.warn("Fail to remove vm id=" + vmId + " from load balancers as a part of expunge process"); } - // If vm is assigned to static nat, disable static nat for the ip address + // If vm is assigned to static nat, disable static nat for the ip address and disassociate ip if elasticIP is enabled IPAddressVO ip = _ipAddressDao.findByAssociatedVmId(vmId); try { if (ip != null) { @@ -1270,6 +1271,21 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager s_logger.warn("Failed to disable static nat for ip address " + ip + " as a part of vm id=" + vmId + " expunge"); success = false; } + + Long networkId = ip.getAssociatedWithNetworkId(); + if (networkId != null) { + Network guestNetwork = _networkMgr.getNetwork(networkId); + NetworkOffering offering = _configMgr.getNetworkOffering(guestNetwork.getNetworkOfferingId()); + if (offering.getElasticIp()) { + UserContext ctx = UserContext.current(); + if (!_networkMgr.releasePublicIpAddress(ip.getId(), ctx.getCallerUserId(), ctx.getCaller())) { + s_logger.warn("Unable to release elastic ip address id=" + ip.getId() + " as a part of vm id=" + vmId + " cleanup"); + success = false; + } else { + s_logger.warn("Successfully released elastic ip address id=" + ip.getId() + " as a part of vm id=" + vmId + " cleanup"); + } + } + } } } catch (ResourceUnavailableException e) { success = false; @@ -2591,9 +2607,13 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager } finally { updateVmStateForFailedVmCreation(vm.getId()); } + + if (!finalizeDeploy(vm, true)) { + //FIXME alena - if fails, expunge the vm + } if (template.getEnablePassword()) { - // this value is not being sent to the backend; need only for api dispaly purposes + // this value is not being sent to the backend; need only for api display purposes vm.setPassword(password); } @@ -3586,4 +3606,41 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager s_logger.debug("Restore VM " + vmId + " with template " + root.getTemplateId() + " successfully"); return vm; } + + protected boolean finalizeDeploy(UserVm vm, boolean stopOnError) { + boolean success = true; + Account vmOwner = _accountMgr.getAccount(vm.getAccountId()); + + //enable static nat if eIp capability is supported + List nics = _nicDao.listByVmId(vm.getId()); + for (Nic nic : nics) { + Network guestNetwork = _networkMgr.getNetwork(nic.getNetworkId()); + NetworkOffering offering = _configMgr.getNetworkOffering(guestNetwork.getNetworkOfferingId()); + if (offering.getElasticIp()) { + try { + s_logger.debug("Allocating elastic ip and enabling static nat for it for the vm " + vm + " in guest network " + guestNetwork); + IpAddress ip = _networkMgr.assignElasticIp(guestNetwork.getId(), vmOwner, false, true); + if (ip == null) { + s_logger.warn("Failed to allocate elastic ip as a part of vm deployment for vm " + vm); + return false; + } + s_logger.debug("Allocated elastic ip " + ip + ", now enabling static nat on it for vm " + vm); + success = success && _rulesMgr.enableStaticNat(ip.getId(), vm.getId()); + if (!success) { + s_logger.warn("Failed to enable static nat on elastic ip " + ip + " for the vm " + vm); + } else { + s_logger.warn("Succesfully enabled static nat on elastic ip " + ip + " for the vm " + vm); + } + } catch (Exception ex) { + s_logger.warn("Failed to finalize vm deployment for vm " + vm + " on the network " + guestNetwork + " due to exception ", ex); + } finally { + if (!success && stopOnError) { + return false; + } + } + } + } + + return success; + } }