From 2c42ebbf718721a175a9ab87898fc4898e8c076e Mon Sep 17 00:00:00 2001 From: Alex Huang Date: Wed, 8 Dec 2010 09:03:17 -0800 Subject: [PATCH] ip assoc working --- api/src/com/cloud/api/BaseCmd.java | 3 +- .../api/commands/AssociateIPAddrCmd.java | 4 +- .../ResourceUnavailableException.java | 3 +- api/src/com/cloud/network/NetworkService.java | 2 +- .../cloud/network/element/NetworkElement.java | 4 +- .../cloud/agent/manager/AgentManagerImpl.java | 56 +++--- .../consoleproxy/ConsoleProxyManagerImpl.java | 21 +- server/src/com/cloud/network/IPAddressVO.java | 11 ++ .../src/com/cloud/network/NetworkManager.java | 6 +- .../com/cloud/network/NetworkManagerImpl.java | 180 +++++++++++------- .../com/cloud/network/dao/IPAddressDao.java | 8 +- .../cloud/network/dao/IPAddressDaoImpl.java | 35 ++-- .../network/element/DomainRouterElement.java | 4 +- .../router/DomainRouterManagerImpl.java | 4 +- .../SecondaryStorageManagerImpl.java | 11 +- setup/db/create-index-fk.sql | 9 - setup/db/create-schema.sql | 7 +- 17 files changed, 222 insertions(+), 146 deletions(-) diff --git a/api/src/com/cloud/api/BaseCmd.java b/api/src/com/cloud/api/BaseCmd.java index 15c9bd62ed8..dbeacde19bb 100755 --- a/api/src/com/cloud/api/BaseCmd.java +++ b/api/src/com/cloud/api/BaseCmd.java @@ -32,6 +32,7 @@ import com.cloud.consoleproxy.ConsoleProxyService; import com.cloud.dao.EntityManager; import com.cloud.exception.ConcurrentOperationException; import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.ResourceAllocationException; import com.cloud.exception.ResourceUnavailableException; import com.cloud.network.DomainRouterService; import com.cloud.network.NetworkService; @@ -125,7 +126,7 @@ public abstract class BaseCmd { _responseGenerator = generator; } - public abstract void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException; + public abstract void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException; public String getResponseType() { if (responseType == null) { diff --git a/api/src/com/cloud/api/commands/AssociateIPAddrCmd.java b/api/src/com/cloud/api/commands/AssociateIPAddrCmd.java index dd25bbf7188..7d6cd191f54 100644 --- a/api/src/com/cloud/api/commands/AssociateIPAddrCmd.java +++ b/api/src/com/cloud/api/commands/AssociateIPAddrCmd.java @@ -29,7 +29,9 @@ import com.cloud.api.ServerApiException; import com.cloud.api.response.IPAddressResponse; import com.cloud.exception.ConcurrentOperationException; 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; import com.cloud.network.Network; import com.cloud.user.UserContext; @@ -107,7 +109,7 @@ public class AssociateIPAddrCmd extends BaseCmd { } @Override - public void execute(){ + public void execute() throws ResourceUnavailableException, ResourceAllocationException, ConcurrentOperationException, InsufficientCapacityException { try { IpAddress result = _networkService.associateIP(this); if (result != null) { diff --git a/api/src/com/cloud/exception/ResourceUnavailableException.java b/api/src/com/cloud/exception/ResourceUnavailableException.java index 00c71daec1e..4568caa8256 100644 --- a/api/src/com/cloud/exception/ResourceUnavailableException.java +++ b/api/src/com/cloud/exception/ResourceUnavailableException.java @@ -18,8 +18,9 @@ package com.cloud.exception; import com.cloud.utils.SerialVersionUID; +import com.cloud.utils.exception.CloudRuntimeException; -public class ResourceUnavailableException extends Exception { +public class ResourceUnavailableException extends CloudRuntimeException { private static final long serialVersionUID = SerialVersionUID.ResourceUnavailableException; public ResourceUnavailableException(String msg) { diff --git a/api/src/com/cloud/network/NetworkService.java b/api/src/com/cloud/network/NetworkService.java index 9ac4222f681..c89686499fa 100644 --- a/api/src/com/cloud/network/NetworkService.java +++ b/api/src/com/cloud/network/NetworkService.java @@ -49,7 +49,7 @@ public interface NetworkService { * @return ip address object * @throws ResourceAllocationException, InsufficientCapacityException */ - IpAddress associateIP(AssociateIPAddrCmd cmd) throws ResourceAllocationException, InsufficientAddressCapacityException, ConcurrentOperationException; + IpAddress associateIP(AssociateIPAddrCmd cmd) throws ResourceAllocationException, InsufficientAddressCapacityException, ConcurrentOperationException, ResourceUnavailableException; boolean disassociateIpAddress(DisassociateIPAddrCmd cmd); /** diff --git a/api/src/com/cloud/network/element/NetworkElement.java b/api/src/com/cloud/network/element/NetworkElement.java index 45e9b91ccd9..0e8a439e039 100644 --- a/api/src/com/cloud/network/element/NetworkElement.java +++ b/api/src/com/cloud/network/element/NetworkElement.java @@ -75,7 +75,7 @@ public interface NetworkElement extends Adapter { * @return * @throws ResourceUnavailableException */ - boolean associate(Network network, IpAddress ipAddress) throws ResourceUnavailableException; + boolean associate(Network network, List ipAddress) throws ResourceUnavailableException; /** * Disassociate the ip address from this network @@ -84,7 +84,7 @@ public interface NetworkElement extends Adapter { * @return * @throws ResourceUnavailableException */ - boolean disassociate(Network network, IpAddress ipAddress) throws ResourceUnavailableException; + boolean disassociate(Network network, List ipAddress) throws ResourceUnavailableException; /** * Apply rules diff --git a/server/src/com/cloud/agent/manager/AgentManagerImpl.java b/server/src/com/cloud/agent/manager/AgentManagerImpl.java index a657e786bd8..60ce6b03d0f 100755 --- a/server/src/com/cloud/agent/manager/AgentManagerImpl.java +++ b/server/src/com/cloud/agent/manager/AgentManagerImpl.java @@ -21,7 +21,6 @@ import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.net.URI; import java.net.URISyntaxException; -import java.net.URLEncoder; import java.nio.channels.ClosedChannelException; import java.util.ArrayList; import java.util.Enumeration; @@ -408,8 +407,9 @@ public class AgentManagerImpl implements AgentManager, HandlerFactory, ResourceS for (Pair listener : _cmdMonitors) { answer = listener.second().processControlCommand(attache.getId(), cmd); - if(answer != null) - return answer; + if(answer != null) { + return answer; + } } s_logger.warn("No handling of agent control command: " + cmd.toString() + " sent from " + attache.getId()); @@ -437,8 +437,9 @@ public class AgentManagerImpl implements AgentManager, HandlerFactory, ResourceS synchronized (_agents) { final Set s = _agents.keySet(); - for (final Long id : s) + for (final Long id : s) { result.add(id); + } } return result; } @@ -620,9 +621,9 @@ public class AgentManagerImpl implements AgentManager, HandlerFactory, ResourceS try { uri = new URI(UriUtils.encodeURIComponent(url)); - if (uri.getScheme() == null) - throw new InvalidParameterValueException("uri.scheme is null " + url + ", add nfs:// as a prefix"); - else if (uri.getScheme().equalsIgnoreCase("nfs")) { + if (uri.getScheme() == null) { + throw new InvalidParameterValueException("uri.scheme is null " + url + ", add nfs:// as a prefix"); + } else if (uri.getScheme().equalsIgnoreCase("nfs")) { if (uri.getHost() == null || uri.getHost().equalsIgnoreCase("") || uri.getPath() == null || uri.getPath().equalsIgnoreCase("")) { throw new InvalidParameterValueException("Your host and/or path is wrong. Make sure it's of the format nfs://hostname/path"); } @@ -700,7 +701,9 @@ public class AgentManagerImpl implements AgentManager, HandlerFactory, ResourceS boolean success = true; for( HostVO thost: hosts ) { long thostId = thost.getId(); - if( thostId == hostId ) continue; + if( thostId == hostId ) { + continue; + } PoolEjectCommand eject = new PoolEjectCommand(host.getGuid()); Answer answer = easySend(thostId, eject); @@ -1007,8 +1010,9 @@ public class AgentManagerImpl implements AgentManager, HandlerFactory, ResourceS } protected boolean handleDisconnect(AgentAttache attache, Status.Event event, boolean investigate) { - if( attache == null ) + if( attache == null ) { return true; + } long hostId = attache.getId(); @@ -1254,8 +1258,9 @@ public class AgentManagerImpl implements AgentManager, HandlerFactory, ResourceS protected AgentAttache simulateStart(ServerResource resource, Map details, boolean old) throws IllegalArgumentException{ StartupCommand[] cmds = resource.initialize(); - if (cmds == null ) + if (cmds == null ) { return null; + } AgentAttache attache = null; if (s_logger.isDebugEnabled()) { @@ -1643,10 +1648,11 @@ public class AgentManagerImpl implements AgentManager, HandlerFactory, ResourceS } try{ - if (maintain(hostId)) - return _hostDao.findById(hostId); - else - throw new CloudRuntimeException("Unable to prepare for maintenance host " + hostId); + if (maintain(hostId)) { + return _hostDao.findById(hostId); + } else { + throw new CloudRuntimeException("Unable to prepare for maintenance host " + hostId); + } }catch (AgentUnavailableException e) { throw new CloudRuntimeException("Unable to prepare for maintenance host " + hostId); } @@ -1680,8 +1686,9 @@ public class AgentManagerImpl implements AgentManager, HandlerFactory, ResourceS } protected void checkCIDR(Host.Type type, HostPodVO pod, DataCenterVO dc, String serverPrivateIP, String serverPrivateNetmask) throws IllegalArgumentException { // Skip this check for Storage Agents and Console Proxies - if (type == Host.Type.Storage || type == Host.Type.ConsoleProxy) + if (type == Host.Type.Storage || type == Host.Type.ConsoleProxy) { return; + } if (serverPrivateIP == null) { return; @@ -2066,18 +2073,21 @@ public class AgentManagerImpl implements AgentManager, HandlerFactory, ResourceS // If this command is from the agent simulator, don't do the CIDR // check - if (scc.getAgentTag() != null && startup.getAgentTag().equalsIgnoreCase("vmops-simulator")) + if (scc.getAgentTag() != null && startup.getAgentTag().equalsIgnoreCase("vmops-simulator")) { doCidrCheck = false; + } // If this command is from a KVM agent, or from an agent that has a // null hypervisor type, don't do the CIDR check - if (hypervisorType == null || hypervisorType == HypervisorType.KVM || hypervisorType == HypervisorType.VmWare) + if (hypervisorType == null || hypervisorType == HypervisorType.KVM || hypervisorType == HypervisorType.VmWare) { doCidrCheck = false; + } - if (doCidrCheck) + if (doCidrCheck) { s_logger.info("Host: " + host.getName() + " connected with hypervisor type: " + hypervisorType + ". Checking CIDR..."); - else + } else { s_logger.info("Host: " + host.getName() + " connected with hypervisor type: " + hypervisorType + ". Skipping CIDR check..."); + } if (doCidrCheck) { checkCIDR(type, p, dc, scc.getPrivateIpAddress(), scc.getPrivateNetmask()); @@ -2276,8 +2286,9 @@ public class AgentManagerImpl implements AgentManager, HandlerFactory, ResourceS } catch (Exception e) { s_logger.warn("Unable to simulate start on resource " + id + " name " + resource.getName(), e); } finally { - if(actionDelegate != null) - actionDelegate.action(new Long(id)); + if(actionDelegate != null) { + actionDelegate.action(new Long(id)); + } StackMaid.current().exitCleanup(); } @@ -2316,8 +2327,9 @@ public class AgentManagerImpl implements AgentManager, HandlerFactory, ResourceS // } try { StartupCommand[] startups = new StartupCommand[cmds.length]; - for (int i = 0; i < cmds.length; i++) + for (int i = 0; i < cmds.length; i++) { startups[i] = (StartupCommand) cmds[i]; + } attache = handleConnect(link, startups); } catch (final IllegalArgumentException e) { _alertMgr.sendAlert(AlertManager.ALERT_TYPE_HOST, 0, new Long(0), "Agent from " + startup.getPrivateIpAddress() diff --git a/server/src/com/cloud/consoleproxy/ConsoleProxyManagerImpl.java b/server/src/com/cloud/consoleproxy/ConsoleProxyManagerImpl.java index 4efca8b1bb9..209401ddd27 100644 --- a/server/src/com/cloud/consoleproxy/ConsoleProxyManagerImpl.java +++ b/server/src/com/cloud/consoleproxy/ConsoleProxyManagerImpl.java @@ -88,6 +88,7 @@ import com.cloud.event.EventUtils; import com.cloud.event.EventVO; import com.cloud.event.dao.EventDao; import com.cloud.exception.AgentUnavailableException; +import com.cloud.exception.ConcurrentOperationException; import com.cloud.exception.InsufficientCapacityException; import com.cloud.exception.OperationTimedoutException; import com.cloud.exception.ResourceUnavailableException; @@ -478,7 +479,12 @@ public class ConsoleProxyManagerImpl implements ConsoleProxyManager, ConsoleProx s_logger.info("No stopped console proxy is available, need to allocate a new console proxy for data center : " + dataCenterId); } - proxy = startNew(dataCenterId); + try { + proxy = startNew(dataCenterId); + } catch (ConcurrentOperationException e) { + s_logger.info("Concurrent operation caught " + e); + return null; + } } else { if (s_logger.isInfoEnabled()) { s_logger.info("Found a stopped console proxy, bring it up to running pool. proxy vm id : " + proxy.getId() + ", data center : " @@ -905,7 +911,7 @@ public class ConsoleProxyManagerImpl implements ConsoleProxyManager, ConsoleProx return null; } - public ConsoleProxyVO startNewConsoleProxy(long dataCenterId) { + public ConsoleProxyVO startNewConsoleProxy(long dataCenterId) throws ConcurrentOperationException { if (s_logger.isDebugEnabled()) { s_logger.debug("Assign console proxy from a newly started instance for request from data center : " + dataCenterId); } @@ -948,7 +954,7 @@ public class ConsoleProxyManagerImpl implements ConsoleProxyManager, ConsoleProx return null; } - public ConsoleProxyVO startNew(long dataCenterId) { + public ConsoleProxyVO startNew(long dataCenterId) throws ConcurrentOperationException { if (s_logger.isDebugEnabled()) { s_logger.debug("Assign console proxy from a newly started instance for request from data center : " + dataCenterId); @@ -1087,7 +1093,7 @@ public class ConsoleProxyManagerImpl implements ConsoleProxyManager, ConsoleProx } } - protected Map createProxyInstance2(long dataCenterId) { + protected Map createProxyInstance2(long dataCenterId) throws ConcurrentOperationException { long id = _consoleProxyDao.getNextInSequence(Long.class, "id"); String name = VirtualMachineName.getConsoleProxyName(id, _instance); @@ -1102,9 +1108,9 @@ public class ConsoleProxyManagerImpl implements ConsoleProxyManager, ConsoleProx NicProfile defaultNic = new NicProfile(); defaultNic.setDefaultNic(true); defaultNic.setDeviceId(2); - networks.add(new Pair(_networkMgr.setupNetworkConfiguration(systemAcct, defaultOffering.get(0), plan, null, null, false).get(0), defaultNic)); + networks.add(new Pair(_networkMgr.setupNetwork(systemAcct, defaultOffering.get(0), plan, null, null, false).get(0), defaultNic)); for (NetworkOfferingVO offering : offerings) { - networks.add(new Pair(_networkMgr.setupNetworkConfiguration(systemAcct, offering, plan, null, null, false).get(0), null)); + networks.add(new Pair(_networkMgr.setupNetwork(systemAcct, offering, plan, null, null, false).get(0), null)); } ConsoleProxyVO proxy = new ConsoleProxyVO(id, _serviceOffering.getId(), name, _template.getId(), _template.getGuestOSId(), dataCenterId, systemAcct.getDomainId(), systemAcct.getId(), 0); try { @@ -1698,6 +1704,9 @@ public class ConsoleProxyManagerImpl implements ConsoleProxyManager, ConsoleProx if (_allocProxyLock.lock(ACQUIRE_GLOBAL_LOCK_TIMEOUT_FOR_SYNC)) { try { proxy = startNew(dataCenterId); + } catch (ConcurrentOperationException e) { + s_logger.info("Concurrent Operation caught " + e) + ; } finally { _allocProxyLock.unlock(); } diff --git a/server/src/com/cloud/network/IPAddressVO.java b/server/src/com/cloud/network/IPAddressVO.java index 3b7be26d536..95ff75598d8 100644 --- a/server/src/com/cloud/network/IPAddressVO.java +++ b/server/src/com/cloud/network/IPAddressVO.java @@ -65,6 +65,9 @@ public class IPAddressVO implements IpAddress { @Column(name="mac_address") private long macAddress; + + @Column(name="network_id") + private Long associatedNetworkId; protected IPAddressVO() { } @@ -104,6 +107,14 @@ public class IPAddressVO implements IpAddress { public Long getAllocatedToAccountId() { return allocatedToAccountId; } + + public Long getAssociatedNetworkId() { + return associatedNetworkId; + } + + public void setAssociatedNetworkId(Long networkId) { + this.associatedNetworkId = networkId; + } @Override public Long getAllocatedInDomainId() { diff --git a/server/src/com/cloud/network/NetworkManager.java b/server/src/com/cloud/network/NetworkManager.java index 06ca4996f37..d86f097123f 100644 --- a/server/src/com/cloud/network/NetworkManager.java +++ b/server/src/com/cloud/network/NetworkManager.java @@ -89,8 +89,8 @@ public interface NetworkManager extends NetworkService { */ List listPublicIpAddressesInVirtualNetwork(long accountId, long dcId, Boolean sourceNat); - List setupNetworkConfiguration(Account owner, NetworkOfferingVO offering, DeploymentPlan plan, String name, String displayText, boolean isShared); - List setupNetwork(Account owner, NetworkOfferingVO offering, Network predefined, DeploymentPlan plan, String name, String displayText, boolean isShared); + List setupNetwork(Account owner, NetworkOfferingVO offering, DeploymentPlan plan, String name, String displayText, boolean isShared) throws ConcurrentOperationException; + List setupNetwork(Account owner, NetworkOfferingVO offering, Network predefined, DeploymentPlan plan, String name, String displayText, boolean isShared) throws ConcurrentOperationException; List getSystemAccountNetworkOfferings(String... offeringNames); @@ -106,7 +106,7 @@ public interface NetworkManager extends NetworkService { List getNetworksforOffering(long offeringId, long dataCenterId, long accountId); - List setupNetwork(Account owner, ServiceOfferingVO offering, DeploymentPlan plan); + List setupNetwork(Account owner, ServiceOfferingVO offering, DeploymentPlan plan) throws ConcurrentOperationException; Network getNetwork(long id); String getNextAvailableMacAddressInNetwork(long networkConfigurationId) throws InsufficientAddressCapacityException; diff --git a/server/src/com/cloud/network/NetworkManagerImpl.java b/server/src/com/cloud/network/NetworkManagerImpl.java index 639bb4effb8..5b50bcc5835 100755 --- a/server/src/com/cloud/network/NetworkManagerImpl.java +++ b/server/src/com/cloud/network/NetworkManagerImpl.java @@ -193,7 +193,7 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag private Map _configs; @DB - protected PublicIp fetchNewPublicIp(long dcId, VlanType vlanUse, Account owner, boolean sourceNat) throws InsufficientAddressCapacityException { + protected PublicIp fetchNewPublicIp(long dcId, VlanType vlanUse, Account owner, Long networkId, boolean sourceNat) throws InsufficientAddressCapacityException { Transaction txn = Transaction.currentTxn(); txn.start(); SearchCriteria sc = AssignIpAddressSearch.create(); @@ -214,6 +214,7 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag addr.setAllocatedTime(new Date()); addr.setAllocatedInDomainId(owner.getDomainId()); addr.setAllocatedToAccountId(owner.getId()); + addr.setAssociatedNetworkId(networkId); if (!_ipAddressDao.update(addr.getAddress(), addr)) { throw new CloudRuntimeException("Found address to allocate but unable to update: " + addr); @@ -261,7 +262,7 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag s_logger.debug("assigning a new ip address in " + dcId + " to " + owner); } - ip = fetchNewPublicIp(dcId, VlanType.VirtualNetwork, owner, true); + ip = fetchNewPublicIp(dcId, VlanType.VirtualNetwork, owner, network.getId(), true); sourceNat = ip.ip(); sourceNat.setState(IpAddress.State.Allocated); _ipAddressDao.update(sourceNat.getAddress(), sourceNat); @@ -423,6 +424,37 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag return account; } + public boolean applyIpAssociations(Network network, boolean continueOnError) throws ResourceUnavailableException { + List userIps = _ipAddressDao.listByNetwork(network.getId()); + + boolean success = true; + for (NetworkElement element : _networkElements) { + try { + element.associate(network, userIps); + } catch (ResourceUnavailableException e) { + success = false; + if (!continueOnError) { + throw e; + } else { + s_logger.debug("Resource is not available: " + element.getName(), e); + } + } + } + + if (success) { + for (IPAddressVO addr : userIps) { + if (addr.getState() == IpAddress.State.Allocating) { + addr.setState(IpAddress.State.Allocated); + _ipAddressDao.update(addr.getAddress(), addr); + } else if (addr.getState() == IpAddress.State.Releasing) { + _ipAddressDao.unassignIpAddress(addr.getAddress()); + } + } + } + + return success; + } + @Override public List getVirtualNetworksOwnedByAccountInZone(String accountName, long domainId, long zoneId) { Account owner = _accountDao.findActiveAccount(accountName, domainId); @@ -434,13 +466,12 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag } @Override @DB - public IpAddress associateIP(AssociateIPAddrCmd cmd) throws ResourceAllocationException, InsufficientAddressCapacityException, ConcurrentOperationException { + public IpAddress associateIP(AssociateIPAddrCmd cmd) throws ResourceAllocationException, ResourceUnavailableException, InsufficientAddressCapacityException, ConcurrentOperationException { String accountName = cmd.getAccountName(); long domainId = cmd.getDomainId(); Long zoneId = cmd.getZoneId(); Account caller = UserContext.current().getAccount(); long userId = UserContext.current().getUserId(); - Long accountId = null; Account owner = _accountDao.findActiveAccount(accountName, domainId); if (owner == null) { @@ -449,6 +480,7 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag _accountMgr.checkAccess(caller, owner); + long ownerId = owner.getId(); Long networkId = cmd.getNetworkId(); Network network = null; if (networkId != null) { @@ -460,7 +492,7 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag EventVO event = new EventVO(); event.setUserId(userId); - event.setAccountId(accountId); + event.setAccountId(ownerId); event.setType(EventTypes.EVENT_NET_IP_ASSIGN); PublicIp ip = null; @@ -470,11 +502,11 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag Account accountToLock = null; try { if (s_logger.isDebugEnabled()) { - s_logger.debug("Associate IP address called for user " + userId + " account " + accountId); + s_logger.debug("Associate IP address called for user " + userId + " account " + ownerId); } - accountToLock = _accountDao.acquireInLockTable(accountId); + accountToLock = _accountDao.acquireInLockTable(ownerId); if (accountToLock == null) { - s_logger.warn("Unable to lock account: " + accountId); + s_logger.warn("Unable to lock account: " + ownerId); throw new ConcurrentOperationException("Unable to acquire account lock"); } @@ -492,11 +524,11 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag txn.start(); - ip = fetchNewPublicIp(zoneId, VlanType.VirtualNetwork, owner, false); + ip = fetchNewPublicIp(zoneId, VlanType.VirtualNetwork, owner, network.getId(), false); if (ip == null) { throw new InsufficientAddressCapacityException("Unable to find available public IP addresses", DataCenter.class, zoneId); } - _accountMgr.incrementResourceCount(accountId, ResourceType.public_ip); + _accountMgr.incrementResourceCount(ownerId, ResourceType.public_ip); String ipAddress = ip.getAddress(); @@ -505,13 +537,8 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag _eventDao.persist(event); txn.commit(); - if (network != null) { - for (NetworkElement element : _networkElements) { - element.associate(network, ip); - } - } - - success = true; + + success = applyIpAssociations(network, false); return ip; } catch (ResourceUnavailableException e) { @@ -519,16 +546,21 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag return null; } finally { if (caller != null) { - _accountDao.releaseFromLockTable(accountId); + _accountDao.releaseFromLockTable(ownerId); s_logger.debug("Associate IP address lock released"); } if (!success) { if (ip != null) { - Transaction.currentTxn(); + try { + _ipAddressDao.markAsUnavailable(ip.getAddress(), ip.getAccountId()); + applyIpAssociations(network, true); + } catch (Exception e) { + s_logger.warn("Unable to disassociate ip address for recovery", e); + } txn.start(); _ipAddressDao.unassignIpAddress(ip.getAddress()); - _accountMgr.decrementResourceCount(accountId, ResourceType.public_ip); + _accountMgr.decrementResourceCount(ownerId, ResourceType.public_ip); event.setLevel(EventVO.LEVEL_ERROR); event.setDescription(""); @@ -569,12 +601,15 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag success = false; } - for (NetworkElement ne : _networkElements) { + if (ip.getAssociatedNetworkId() != null) { + Network network = _networksDao.findById(ip.getAssociatedNetworkId()); try { - ne.disassociate(null, ip); + if (!applyIpAssociations(network, true)) { + s_logger.warn("Unable to apply ip address associations for " + network); + success = false; + } } catch (ResourceUnavailableException e) { - s_logger.warn("Unable to release the ip address " + ip, e); - success = false; + throw new CloudRuntimeException("We should nver get to here because we used true when applyIpAssociations", e); } } @@ -726,56 +761,65 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag } @Override - public List setupNetworkConfiguration(Account owner, NetworkOfferingVO offering, DeploymentPlan plan, String name, String displayText, boolean isShared) { + public List setupNetwork(Account owner, NetworkOfferingVO offering, DeploymentPlan plan, String name, String displayText, boolean isShared) throws ConcurrentOperationException { return setupNetwork(owner, offering, null, plan, name, displayText, isShared); } - @Override - public List setupNetwork(Account owner, NetworkOfferingVO offering, Network predefined, DeploymentPlan plan, String name, String displayText, boolean isShared) { - - List configs = _networksDao.listBy(owner.getId(), offering.getId(), plan.getDataCenterId()); - if (predefined == null || (predefined.getBroadcastUri() == null && predefined.getBroadcastDomainType() != BroadcastDomainType.Vlan)) { - if (configs.size() > 0) { - if (s_logger.isDebugEnabled()) { - s_logger.debug("Found existing network configuration for offering " + offering + ": " + configs.get(0)); + @Override @DB + public List setupNetwork(Account owner, NetworkOfferingVO offering, Network predefined, DeploymentPlan plan, String name, String displayText, boolean isShared) throws ConcurrentOperationException { + Transaction.currentTxn(); + Account locked = _accountDao.acquireInLockTable(owner.getId()); + if (locked == null) { + throw new ConcurrentOperationException("Unable to acquire lock on " + owner); + } + try { + List configs = _networksDao.listBy(owner.getId(), offering.getId(), plan.getDataCenterId()); + if (predefined == null || (predefined.getBroadcastUri() == null && predefined.getBroadcastDomainType() != BroadcastDomainType.Vlan)) { + if (configs.size() > 0) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Found existing network configuration for offering " + offering + ": " + configs.get(0)); + } + return configs; } - return configs; } - } - - configs = new ArrayList(); - - long related = -1; - - for (NetworkGuru guru : _networkGurus) { - Network config = guru.design(offering, plan, predefined, owner); - if (config == null) { - continue; - } - - if (config.getId() != -1) { - if (config instanceof NetworkVO) { - configs.add((NetworkVO)config); - } else { - configs.add(_networksDao.findById(config.getId())); + + configs = new ArrayList(); + + long related = -1; + + for (NetworkGuru guru : _networkGurus) { + Network config = guru.design(offering, plan, predefined, owner); + if (config == null) { + continue; } - continue; + + if (config.getId() != -1) { + if (config instanceof NetworkVO) { + configs.add((NetworkVO)config); + } else { + configs.add(_networksDao.findById(config.getId())); + } + continue; + } + + long id = _networksDao.getNextInSequence(Long.class, "id"); + if (related == -1) { + related = id; + } + + NetworkVO vo = new NetworkVO(id, config, offering.getId(), plan.getDataCenterId(), guru.getName(), owner.getDomainId(), owner.getId(), related, name, displayText, isShared); + configs.add(_networksDao.persist(vo)); } - - long id = _networksDao.getNextInSequence(Long.class, "id"); - if (related == -1) { - related = id; - } - - NetworkVO vo = new NetworkVO(id, config, offering.getId(), plan.getDataCenterId(), guru.getName(), owner.getDomainId(), owner.getId(), related, name, displayText, isShared); - configs.add(_networksDao.persist(vo)); + + if (configs.size() < 1) { + throw new CloudRuntimeException("Unable to convert network offering to network profile: " + offering.getId()); + } + + return configs; + } finally { + s_logger.debug("Releasing lock for " + locked); + _accountDao.releaseFromLockTable(locked.getId()); } - - if (configs.size() < 1) { - throw new CloudRuntimeException("Unable to convert network offering to network profile: " + offering.getId()); - } - - return configs; } @Override @@ -1179,9 +1223,9 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag } @Override - public List setupNetwork(Account owner, ServiceOfferingVO offering, DeploymentPlan plan) { + public List setupNetwork(Account owner, ServiceOfferingVO offering, DeploymentPlan plan) throws ConcurrentOperationException { NetworkOfferingVO networkOffering = _networkOfferingDao.findByServiceOffering(offering); - return setupNetworkConfiguration(owner, networkOffering, plan, null, null, false); + return setupNetwork(owner, networkOffering, plan, null, null, false); } private String [] getGuestIpRange() { diff --git a/server/src/com/cloud/network/dao/IPAddressDao.java b/server/src/com/cloud/network/dao/IPAddressDao.java index 4b9d57f7ecf..1d96fe0190e 100644 --- a/server/src/com/cloud/network/dao/IPAddressDao.java +++ b/server/src/com/cloud/network/dao/IPAddressDao.java @@ -32,6 +32,8 @@ public interface IPAddressDao extends GenericDao { List listByAccount(long accountId); List listByDcIdIpAddress(long dcId, String ipAddress); + + List listByNetwork(long networkId); int countIPs(long dcId, long vlanDbId, boolean onlyCountAllocated); @@ -40,10 +42,4 @@ public interface IPAddressDao extends GenericDao { boolean mark(long dcId, String ip); List assignAcccountSpecificIps(long accountId, long longValue, Long vlanDbId, boolean sourceNat); - - void setIpAsSourceNat(String ipAddr); - - void unassignIpAsSourceNat(String ipAddress); - - } diff --git a/server/src/com/cloud/network/dao/IPAddressDaoImpl.java b/server/src/com/cloud/network/dao/IPAddressDaoImpl.java index 0f9c277581c..9efdeb86c6b 100644 --- a/server/src/com/cloud/network/dao/IPAddressDaoImpl.java +++ b/server/src/com/cloud/network/dao/IPAddressDaoImpl.java @@ -59,6 +59,7 @@ public class IPAddressDaoImpl extends GenericDaoBase implem AllFieldsSearch.and("vlan", AllFieldsSearch.entity().getVlanId(), Op.EQ); AllFieldsSearch.and("accountId", AllFieldsSearch.entity().getAllocatedToAccountId(), Op.EQ); AllFieldsSearch.and("sourceNat", AllFieldsSearch.entity().isSourceNat(), Op.EQ); + AllFieldsSearch.and("network", AllFieldsSearch.entity().getAssociatedNetworkId(), Op.EQ); AllFieldsSearch.done(); VlanDbIdSearchUnallocated = createSearchBuilder(); @@ -122,15 +123,11 @@ public class IPAddressDaoImpl extends GenericDaoBase implem return ipStringList; } - @Override - public void setIpAsSourceNat(String ipAddr) { - - IPAddressVO ip = createForUpdate(ipAddr); - ip.setSourceNat(true); - s_logger.debug("Setting " + ipAddr + " as source Nat "); - update(ipAddr, ip); - } - + /** + * @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(); @@ -171,13 +168,7 @@ public class IPAddressDaoImpl extends GenericDaoBase implem address.setSourceNat(false); address.setOneToOneNat(false); address.setState(State.Free); - update(ipAddress, address); - } - - @Override - public void unassignIpAsSourceNat(String ipAddress) { - IPAddressVO address = createForUpdate(); - address.setSourceNat(false); + address.setAssociatedNetworkId(null); update(ipAddress, address); } @@ -185,7 +176,7 @@ public class IPAddressDaoImpl extends GenericDaoBase implem public List listByAccount(long accountId) { SearchCriteria sc = AllFieldsSearch.create(); sc.setParameters("accountId", accountId); - return listIncludingRemovedBy(sc); + return listBy(sc); } @Override @@ -193,7 +184,15 @@ public class IPAddressDaoImpl extends GenericDaoBase implem SearchCriteria sc = AllFieldsSearch.create(); sc.setParameters("dataCenterId", dcId); sc.setParameters("ipAddress", ipAddress); - return listIncludingRemovedBy(sc); + return listBy(sc); + } + + @Override + public List listByNetwork(long networkId) { + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("network", networkId); + + return listBy(sc); } @Override diff --git a/server/src/com/cloud/network/element/DomainRouterElement.java b/server/src/com/cloud/network/element/DomainRouterElement.java index 9f7fdc713c9..c8e2ff2f416 100644 --- a/server/src/com/cloud/network/element/DomainRouterElement.java +++ b/server/src/com/cloud/network/element/DomainRouterElement.java @@ -142,13 +142,13 @@ public class DomainRouterElement extends AdapterBase implements NetworkElement { } @Override - public boolean associate(Network network, IpAddress ipAddress) throws ResourceUnavailableException { + public boolean associate(Network network, List ipAddress) throws ResourceUnavailableException { // TODO Auto-generated method stub return false; } @Override - public boolean disassociate(Network network, IpAddress ipAddress) throws ResourceUnavailableException { + public boolean disassociate(Network network, List ipAddress) throws ResourceUnavailableException { // TODO Auto-generated method stub return false; } diff --git a/server/src/com/cloud/network/router/DomainRouterManagerImpl.java b/server/src/com/cloud/network/router/DomainRouterManagerImpl.java index d60261c2dd1..92dce248ea3 100644 --- a/server/src/com/cloud/network/router/DomainRouterManagerImpl.java +++ b/server/src/com/cloud/network/router/DomainRouterManagerImpl.java @@ -2096,11 +2096,11 @@ public class DomainRouterManagerImpl implements DomainRouterManager, DomainRoute List offerings = _networkMgr.getSystemAccountNetworkOfferings(NetworkOfferingVO.SystemVmControlNetwork); NetworkOfferingVO controlOffering = offerings.get(0); - NetworkVO controlConfig = _networkMgr.setupNetworkConfiguration(_systemAcct, controlOffering, plan, null, null, false).get(0); + NetworkVO controlConfig = _networkMgr.setupNetwork(_systemAcct, controlOffering, plan, null, null, false).get(0); List> networks = new ArrayList>(3); NetworkOfferingVO publicOffering = _networkMgr.getSystemAccountNetworkOfferings(NetworkOfferingVO.SystemVmPublicNetwork).get(0); - List publicConfigs = _networkMgr.setupNetworkConfiguration(_systemAcct, publicOffering, plan, null, null, false); + List publicConfigs = _networkMgr.setupNetwork(_systemAcct, publicOffering, plan, null, null, false); NicProfile defaultNic = new NicProfile(); defaultNic.setDefaultNic(true); //defaultNic.setIp4Address(sourceNatIp); diff --git a/server/src/com/cloud/storage/secondary/SecondaryStorageManagerImpl.java b/server/src/com/cloud/storage/secondary/SecondaryStorageManagerImpl.java index 910d34a383f..e28bd23d6af 100644 --- a/server/src/com/cloud/storage/secondary/SecondaryStorageManagerImpl.java +++ b/server/src/com/cloud/storage/secondary/SecondaryStorageManagerImpl.java @@ -761,9 +761,14 @@ public class SecondaryStorageManagerImpl implements SecondaryStorageVmManager, V NicProfile defaultNic = new NicProfile(); defaultNic.setDefaultNic(true); defaultNic.setDeviceId(2); - networks.add(new Pair(_networkMgr.setupNetworkConfiguration(systemAcct, defaultOffering.get(0), plan, null, null, false).get(0), defaultNic)); - for (NetworkOfferingVO offering : offerings) { - networks.add(new Pair(_networkMgr.setupNetworkConfiguration(systemAcct, offering, plan, null, null, false).get(0), null)); + try { + networks.add(new Pair(_networkMgr.setupNetwork(systemAcct, defaultOffering.get(0), plan, null, null, false).get(0), defaultNic)); + for (NetworkOfferingVO offering : offerings) { + networks.add(new Pair(_networkMgr.setupNetwork(systemAcct, offering, plan, null, null, false).get(0), null)); + } + } catch (ConcurrentOperationException e) { + s_logger.info("Unable to setup due to concurrent operation. " + e); + return new HashMap(); } SecondaryStorageVmVO secStorageVm = new SecondaryStorageVmVO(id, _serviceOffering.getId(), name, _template.getId(), _template.getGuestOSId(), dataCenterId, systemAcct.getDomainId(), systemAcct.getId()); diff --git a/setup/db/create-index-fk.sql b/setup/db/create-index-fk.sql index 259b2956a4c..b7a582c59c1 100755 --- a/setup/db/create-index-fk.sql +++ b/setup/db/create-index-fk.sql @@ -89,15 +89,6 @@ ALTER TABLE `cloud`.`cluster` ADD CONSTRAINT `fk_cluster__data_center_id` FOREIG ALTER TABLE `cloud`.`cluster` ADD CONSTRAINT `fk_cluster__pod_id` FOREIGN KEY `fd_cluster__pod_id`(`pod_id`) REFERENCES `cloud`.`host_pod_ref`(`id`); ALTER TABLE `cloud`.`cluster` ADD UNIQUE `i_cluster__pod_id__name`(`pod_id`, `name`); -ALTER TABLE `cloud`.`user_ip_address` ADD CONSTRAINT `fk_user_ip_address__account_id` FOREIGN KEY `fk_user_ip_address__account_id` (`account_id`) REFERENCES `account` (`id`); -ALTER TABLE `cloud`.`user_ip_address` ADD INDEX `i_user_ip_address__account_id`(`account_id`); -ALTER TABLE `cloud`.`user_ip_address` ADD CONSTRAINT `fk_user_ip_address__vlan_db_id` FOREIGN KEY `fk_user_ip_address__vlan_db_id` (`vlan_db_id`) REFERENCES `vlan` (`id`) ON DELETE CASCADE; -ALTER TABLE `cloud`.`user_ip_address` ADD INDEX `i_user_ip_address__vlan_db_id`(`vlan_db_id`); - -ALTER TABLE `cloud`.`user_ip_address` ADD INDEX `i_user_ip_address__data_center_id`(`data_center_id`); -ALTER TABLE `cloud`.`user_ip_address` ADD INDEX `i_user_ip_address__source_nat`(`source_nat`); -ALTER TABLE `cloud`.`user_ip_address` ADD INDEX `i_user_ip_address__allocated`(`allocated`); -ALTER TABLE `cloud`.`user_ip_address` ADD INDEX `i_user_ip_address__public_ip_address`(`public_ip_address`); ALTER TABLE `cloud`.`vm_template` ADD INDEX `i_vm_template__removed`(`removed`); ALTER TABLE `cloud`.`vm_template` ADD INDEX `i_vm_template__public`(`public`); diff --git a/setup/db/create-schema.sql b/setup/db/create-schema.sql index 0c7aee1ab09..d6fd69a39a7 100755 --- a/setup/db/create-schema.sql +++ b/setup/db/create-schema.sql @@ -628,7 +628,12 @@ CREATE TABLE `cloud`.`user_ip_address` ( `mac_address` bigint unsigned NOT NULL COMMENT 'mac address of this ip', `network_id` bigint unsigned COMMENT 'network this public ip address is associated with', PRIMARY KEY (`public_ip_address`), - CONSTRAINT `fk_user_ip_address__network_id` FOREIGN KEY (`network_id`) REFERENCES `networks`(`id`) + CONSTRAINT `fk_user_ip_address__network_id` FOREIGN KEY (`network_id`) REFERENCES `networks`(`id`), + CONSTRAINT `fk_user_ip_address__account_id` FOREIGN KEY (`account_id`) REFERENCES `account`(`id`), + CONSTRAINT `fk_user_ip_address__vlan_db_id` FOREIGN KEY (`vlan_db_id`) REFERENCES `vlan`(`id`) ON DELETE CASCADE, + CONSTRAINT `fk_user_ip_address__data_center_id` FOREIGN KEY (`data_center_id`) REFERENCES `data_center`(`id`) ON DELETE CASCADE, + INDEX `i_user_ip_address__allocated`(`allocated`), + INDEX `i_user_ip_address__source_nat`(`source_nat`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE `cloud`.`user_statistics` (