ip assoc working

This commit is contained in:
Alex Huang 2010-12-08 09:03:17 -08:00
parent 49c77cf0cf
commit 2c42ebbf71
17 changed files with 222 additions and 146 deletions

View File

@ -32,6 +32,7 @@ import com.cloud.consoleproxy.ConsoleProxyService;
import com.cloud.dao.EntityManager; import com.cloud.dao.EntityManager;
import com.cloud.exception.ConcurrentOperationException; import com.cloud.exception.ConcurrentOperationException;
import com.cloud.exception.InsufficientCapacityException; import com.cloud.exception.InsufficientCapacityException;
import com.cloud.exception.ResourceAllocationException;
import com.cloud.exception.ResourceUnavailableException; import com.cloud.exception.ResourceUnavailableException;
import com.cloud.network.DomainRouterService; import com.cloud.network.DomainRouterService;
import com.cloud.network.NetworkService; import com.cloud.network.NetworkService;
@ -125,7 +126,7 @@ public abstract class BaseCmd {
_responseGenerator = generator; _responseGenerator = generator;
} }
public abstract void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException; public abstract void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException;
public String getResponseType() { public String getResponseType() {
if (responseType == null) { if (responseType == null) {

View File

@ -29,7 +29,9 @@ import com.cloud.api.ServerApiException;
import com.cloud.api.response.IPAddressResponse; import com.cloud.api.response.IPAddressResponse;
import com.cloud.exception.ConcurrentOperationException; import com.cloud.exception.ConcurrentOperationException;
import com.cloud.exception.InsufficientAddressCapacityException; import com.cloud.exception.InsufficientAddressCapacityException;
import com.cloud.exception.InsufficientCapacityException;
import com.cloud.exception.ResourceAllocationException; import com.cloud.exception.ResourceAllocationException;
import com.cloud.exception.ResourceUnavailableException;
import com.cloud.network.IpAddress; import com.cloud.network.IpAddress;
import com.cloud.network.Network; import com.cloud.network.Network;
import com.cloud.user.UserContext; import com.cloud.user.UserContext;
@ -107,7 +109,7 @@ public class AssociateIPAddrCmd extends BaseCmd {
} }
@Override @Override
public void execute(){ public void execute() throws ResourceUnavailableException, ResourceAllocationException, ConcurrentOperationException, InsufficientCapacityException {
try { try {
IpAddress result = _networkService.associateIP(this); IpAddress result = _networkService.associateIP(this);
if (result != null) { if (result != null) {

View File

@ -18,8 +18,9 @@
package com.cloud.exception; package com.cloud.exception;
import com.cloud.utils.SerialVersionUID; 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; private static final long serialVersionUID = SerialVersionUID.ResourceUnavailableException;
public ResourceUnavailableException(String msg) { public ResourceUnavailableException(String msg) {

View File

@ -49,7 +49,7 @@ public interface NetworkService {
* @return ip address object * @return ip address object
* @throws ResourceAllocationException, InsufficientCapacityException * @throws ResourceAllocationException, InsufficientCapacityException
*/ */
IpAddress associateIP(AssociateIPAddrCmd cmd) throws ResourceAllocationException, InsufficientAddressCapacityException, ConcurrentOperationException; IpAddress associateIP(AssociateIPAddrCmd cmd) throws ResourceAllocationException, InsufficientAddressCapacityException, ConcurrentOperationException, ResourceUnavailableException;
boolean disassociateIpAddress(DisassociateIPAddrCmd cmd); boolean disassociateIpAddress(DisassociateIPAddrCmd cmd);
/** /**

View File

@ -75,7 +75,7 @@ public interface NetworkElement extends Adapter {
* @return * @return
* @throws ResourceUnavailableException * @throws ResourceUnavailableException
*/ */
boolean associate(Network network, IpAddress ipAddress) throws ResourceUnavailableException; boolean associate(Network network, List<? extends IpAddress> ipAddress) throws ResourceUnavailableException;
/** /**
* Disassociate the ip address from this network * Disassociate the ip address from this network
@ -84,7 +84,7 @@ public interface NetworkElement extends Adapter {
* @return * @return
* @throws ResourceUnavailableException * @throws ResourceUnavailableException
*/ */
boolean disassociate(Network network, IpAddress ipAddress) throws ResourceUnavailableException; boolean disassociate(Network network, List<? extends IpAddress> ipAddress) throws ResourceUnavailableException;
/** /**
* Apply rules * Apply rules

View File

@ -21,7 +21,6 @@ import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.net.URI; import java.net.URI;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.net.URLEncoder;
import java.nio.channels.ClosedChannelException; import java.nio.channels.ClosedChannelException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Enumeration; import java.util.Enumeration;
@ -408,8 +407,9 @@ public class AgentManagerImpl implements AgentManager, HandlerFactory, ResourceS
for (Pair<Integer, Listener> listener : _cmdMonitors) { for (Pair<Integer, Listener> listener : _cmdMonitors) {
answer = listener.second().processControlCommand(attache.getId(), cmd); answer = listener.second().processControlCommand(attache.getId(), cmd);
if(answer != null) if(answer != null) {
return answer; return answer;
}
} }
s_logger.warn("No handling of agent control command: " + cmd.toString() + " sent from " + attache.getId()); 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) { synchronized (_agents) {
final Set<Long> s = _agents.keySet(); final Set<Long> s = _agents.keySet();
for (final Long id : s) for (final Long id : s) {
result.add(id); result.add(id);
}
} }
return result; return result;
} }
@ -620,9 +621,9 @@ public class AgentManagerImpl implements AgentManager, HandlerFactory, ResourceS
try { try {
uri = new URI(UriUtils.encodeURIComponent(url)); uri = new URI(UriUtils.encodeURIComponent(url));
if (uri.getScheme() == null) if (uri.getScheme() == null) {
throw new InvalidParameterValueException("uri.scheme is null " + url + ", add nfs:// as a prefix"); throw new InvalidParameterValueException("uri.scheme is null " + url + ", add nfs:// as a prefix");
else if (uri.getScheme().equalsIgnoreCase("nfs")) { } else if (uri.getScheme().equalsIgnoreCase("nfs")) {
if (uri.getHost() == null || uri.getHost().equalsIgnoreCase("") || uri.getPath() == null || uri.getPath().equalsIgnoreCase("")) { 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"); 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; boolean success = true;
for( HostVO thost: hosts ) { for( HostVO thost: hosts ) {
long thostId = thost.getId(); long thostId = thost.getId();
if( thostId == hostId ) continue; if( thostId == hostId ) {
continue;
}
PoolEjectCommand eject = new PoolEjectCommand(host.getGuid()); PoolEjectCommand eject = new PoolEjectCommand(host.getGuid());
Answer answer = easySend(thostId, eject); 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) { protected boolean handleDisconnect(AgentAttache attache, Status.Event event, boolean investigate) {
if( attache == null ) if( attache == null ) {
return true; return true;
}
long hostId = attache.getId(); long hostId = attache.getId();
@ -1254,8 +1258,9 @@ public class AgentManagerImpl implements AgentManager, HandlerFactory, ResourceS
protected AgentAttache simulateStart(ServerResource resource, Map<String, String> details, boolean old) throws IllegalArgumentException{ protected AgentAttache simulateStart(ServerResource resource, Map<String, String> details, boolean old) throws IllegalArgumentException{
StartupCommand[] cmds = resource.initialize(); StartupCommand[] cmds = resource.initialize();
if (cmds == null ) if (cmds == null ) {
return null; return null;
}
AgentAttache attache = null; AgentAttache attache = null;
if (s_logger.isDebugEnabled()) { if (s_logger.isDebugEnabled()) {
@ -1643,10 +1648,11 @@ public class AgentManagerImpl implements AgentManager, HandlerFactory, ResourceS
} }
try{ try{
if (maintain(hostId)) if (maintain(hostId)) {
return _hostDao.findById(hostId); return _hostDao.findById(hostId);
else } else {
throw new CloudRuntimeException("Unable to prepare for maintenance host " + hostId); throw new CloudRuntimeException("Unable to prepare for maintenance host " + hostId);
}
}catch (AgentUnavailableException e) { }catch (AgentUnavailableException e) {
throw new CloudRuntimeException("Unable to prepare for maintenance host " + hostId); 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 { 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 // 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; return;
}
if (serverPrivateIP == null) { if (serverPrivateIP == null) {
return; 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 // If this command is from the agent simulator, don't do the CIDR
// check // check
if (scc.getAgentTag() != null && startup.getAgentTag().equalsIgnoreCase("vmops-simulator")) if (scc.getAgentTag() != null && startup.getAgentTag().equalsIgnoreCase("vmops-simulator")) {
doCidrCheck = false; doCidrCheck = false;
}
// If this command is from a KVM agent, or from an agent that has a // If this command is from a KVM agent, or from an agent that has a
// null hypervisor type, don't do the CIDR check // 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; doCidrCheck = false;
}
if (doCidrCheck) if (doCidrCheck) {
s_logger.info("Host: " + host.getName() + " connected with hypervisor type: " + hypervisorType + ". Checking CIDR..."); 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..."); s_logger.info("Host: " + host.getName() + " connected with hypervisor type: " + hypervisorType + ". Skipping CIDR check...");
}
if (doCidrCheck) { if (doCidrCheck) {
checkCIDR(type, p, dc, scc.getPrivateIpAddress(), scc.getPrivateNetmask()); checkCIDR(type, p, dc, scc.getPrivateIpAddress(), scc.getPrivateNetmask());
@ -2276,8 +2286,9 @@ public class AgentManagerImpl implements AgentManager, HandlerFactory, ResourceS
} catch (Exception e) { } catch (Exception e) {
s_logger.warn("Unable to simulate start on resource " + id + " name " + resource.getName(), e); s_logger.warn("Unable to simulate start on resource " + id + " name " + resource.getName(), e);
} finally { } finally {
if(actionDelegate != null) if(actionDelegate != null) {
actionDelegate.action(new Long(id)); actionDelegate.action(new Long(id));
}
StackMaid.current().exitCleanup(); StackMaid.current().exitCleanup();
} }
@ -2316,8 +2327,9 @@ public class AgentManagerImpl implements AgentManager, HandlerFactory, ResourceS
// } // }
try { try {
StartupCommand[] startups = new StartupCommand[cmds.length]; 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]; startups[i] = (StartupCommand) cmds[i];
}
attache = handleConnect(link, startups); attache = handleConnect(link, startups);
} catch (final IllegalArgumentException e) { } catch (final IllegalArgumentException e) {
_alertMgr.sendAlert(AlertManager.ALERT_TYPE_HOST, 0, new Long(0), "Agent from " + startup.getPrivateIpAddress() _alertMgr.sendAlert(AlertManager.ALERT_TYPE_HOST, 0, new Long(0), "Agent from " + startup.getPrivateIpAddress()

View File

@ -88,6 +88,7 @@ import com.cloud.event.EventUtils;
import com.cloud.event.EventVO; import com.cloud.event.EventVO;
import com.cloud.event.dao.EventDao; import com.cloud.event.dao.EventDao;
import com.cloud.exception.AgentUnavailableException; import com.cloud.exception.AgentUnavailableException;
import com.cloud.exception.ConcurrentOperationException;
import com.cloud.exception.InsufficientCapacityException; import com.cloud.exception.InsufficientCapacityException;
import com.cloud.exception.OperationTimedoutException; import com.cloud.exception.OperationTimedoutException;
import com.cloud.exception.ResourceUnavailableException; 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); 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 { } else {
if (s_logger.isInfoEnabled()) { 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 : " 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; return null;
} }
public ConsoleProxyVO startNewConsoleProxy(long dataCenterId) { public ConsoleProxyVO startNewConsoleProxy(long dataCenterId) throws ConcurrentOperationException {
if (s_logger.isDebugEnabled()) { if (s_logger.isDebugEnabled()) {
s_logger.debug("Assign console proxy from a newly started instance for request from data center : " + dataCenterId); 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; return null;
} }
public ConsoleProxyVO startNew(long dataCenterId) { public ConsoleProxyVO startNew(long dataCenterId) throws ConcurrentOperationException {
if (s_logger.isDebugEnabled()) { if (s_logger.isDebugEnabled()) {
s_logger.debug("Assign console proxy from a newly started instance for request from data center : " + dataCenterId); 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<String, Object> createProxyInstance2(long dataCenterId) { protected Map<String, Object> createProxyInstance2(long dataCenterId) throws ConcurrentOperationException {
long id = _consoleProxyDao.getNextInSequence(Long.class, "id"); long id = _consoleProxyDao.getNextInSequence(Long.class, "id");
String name = VirtualMachineName.getConsoleProxyName(id, _instance); String name = VirtualMachineName.getConsoleProxyName(id, _instance);
@ -1102,9 +1108,9 @@ public class ConsoleProxyManagerImpl implements ConsoleProxyManager, ConsoleProx
NicProfile defaultNic = new NicProfile(); NicProfile defaultNic = new NicProfile();
defaultNic.setDefaultNic(true); defaultNic.setDefaultNic(true);
defaultNic.setDeviceId(2); defaultNic.setDeviceId(2);
networks.add(new Pair<NetworkVO, NicProfile>(_networkMgr.setupNetworkConfiguration(systemAcct, defaultOffering.get(0), plan, null, null, false).get(0), defaultNic)); networks.add(new Pair<NetworkVO, NicProfile>(_networkMgr.setupNetwork(systemAcct, defaultOffering.get(0), plan, null, null, false).get(0), defaultNic));
for (NetworkOfferingVO offering : offerings) { for (NetworkOfferingVO offering : offerings) {
networks.add(new Pair<NetworkVO, NicProfile>(_networkMgr.setupNetworkConfiguration(systemAcct, offering, plan, null, null, false).get(0), null)); networks.add(new Pair<NetworkVO, NicProfile>(_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); ConsoleProxyVO proxy = new ConsoleProxyVO(id, _serviceOffering.getId(), name, _template.getId(), _template.getGuestOSId(), dataCenterId, systemAcct.getDomainId(), systemAcct.getId(), 0);
try { try {
@ -1698,6 +1704,9 @@ public class ConsoleProxyManagerImpl implements ConsoleProxyManager, ConsoleProx
if (_allocProxyLock.lock(ACQUIRE_GLOBAL_LOCK_TIMEOUT_FOR_SYNC)) { if (_allocProxyLock.lock(ACQUIRE_GLOBAL_LOCK_TIMEOUT_FOR_SYNC)) {
try { try {
proxy = startNew(dataCenterId); proxy = startNew(dataCenterId);
} catch (ConcurrentOperationException e) {
s_logger.info("Concurrent Operation caught " + e)
;
} finally { } finally {
_allocProxyLock.unlock(); _allocProxyLock.unlock();
} }

View File

@ -66,6 +66,9 @@ public class IPAddressVO implements IpAddress {
@Column(name="mac_address") @Column(name="mac_address")
private long macAddress; private long macAddress;
@Column(name="network_id")
private Long associatedNetworkId;
protected IPAddressVO() { protected IPAddressVO() {
} }
@ -105,6 +108,14 @@ public class IPAddressVO implements IpAddress {
return allocatedToAccountId; return allocatedToAccountId;
} }
public Long getAssociatedNetworkId() {
return associatedNetworkId;
}
public void setAssociatedNetworkId(Long networkId) {
this.associatedNetworkId = networkId;
}
@Override @Override
public Long getAllocatedInDomainId() { public Long getAllocatedInDomainId() {
return allocatedInDomainId; return allocatedInDomainId;

View File

@ -89,8 +89,8 @@ public interface NetworkManager extends NetworkService {
*/ */
List<IPAddressVO> listPublicIpAddressesInVirtualNetwork(long accountId, long dcId, Boolean sourceNat); List<IPAddressVO> listPublicIpAddressesInVirtualNetwork(long accountId, long dcId, Boolean sourceNat);
List<NetworkVO> setupNetworkConfiguration(Account owner, NetworkOfferingVO offering, DeploymentPlan plan, String name, String displayText, boolean isShared); List<NetworkVO> setupNetwork(Account owner, NetworkOfferingVO offering, DeploymentPlan plan, String name, String displayText, boolean isShared) throws ConcurrentOperationException;
List<NetworkVO> setupNetwork(Account owner, NetworkOfferingVO offering, Network predefined, DeploymentPlan plan, String name, String displayText, boolean isShared); List<NetworkVO> setupNetwork(Account owner, NetworkOfferingVO offering, Network predefined, DeploymentPlan plan, String name, String displayText, boolean isShared) throws ConcurrentOperationException;
List<NetworkOfferingVO> getSystemAccountNetworkOfferings(String... offeringNames); List<NetworkOfferingVO> getSystemAccountNetworkOfferings(String... offeringNames);
@ -106,7 +106,7 @@ public interface NetworkManager extends NetworkService {
List<NetworkVO> getNetworksforOffering(long offeringId, long dataCenterId, long accountId); List<NetworkVO> getNetworksforOffering(long offeringId, long dataCenterId, long accountId);
List<NetworkVO> setupNetwork(Account owner, ServiceOfferingVO offering, DeploymentPlan plan); List<NetworkVO> setupNetwork(Account owner, ServiceOfferingVO offering, DeploymentPlan plan) throws ConcurrentOperationException;
Network getNetwork(long id); Network getNetwork(long id);
String getNextAvailableMacAddressInNetwork(long networkConfigurationId) throws InsufficientAddressCapacityException; String getNextAvailableMacAddressInNetwork(long networkConfigurationId) throws InsufficientAddressCapacityException;

View File

@ -193,7 +193,7 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag
private Map<String, String> _configs; private Map<String, String> _configs;
@DB @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(); Transaction txn = Transaction.currentTxn();
txn.start(); txn.start();
SearchCriteria<IPAddressVO> sc = AssignIpAddressSearch.create(); SearchCriteria<IPAddressVO> sc = AssignIpAddressSearch.create();
@ -214,6 +214,7 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag
addr.setAllocatedTime(new Date()); addr.setAllocatedTime(new Date());
addr.setAllocatedInDomainId(owner.getDomainId()); addr.setAllocatedInDomainId(owner.getDomainId());
addr.setAllocatedToAccountId(owner.getId()); addr.setAllocatedToAccountId(owner.getId());
addr.setAssociatedNetworkId(networkId);
if (!_ipAddressDao.update(addr.getAddress(), addr)) { if (!_ipAddressDao.update(addr.getAddress(), addr)) {
throw new CloudRuntimeException("Found address to allocate but unable to update: " + 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); 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 = ip.ip();
sourceNat.setState(IpAddress.State.Allocated); sourceNat.setState(IpAddress.State.Allocated);
_ipAddressDao.update(sourceNat.getAddress(), sourceNat); _ipAddressDao.update(sourceNat.getAddress(), sourceNat);
@ -423,6 +424,37 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag
return account; return account;
} }
public boolean applyIpAssociations(Network network, boolean continueOnError) throws ResourceUnavailableException {
List<IPAddressVO> 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 @Override
public List<? extends Network> getVirtualNetworksOwnedByAccountInZone(String accountName, long domainId, long zoneId) { public List<? extends Network> getVirtualNetworksOwnedByAccountInZone(String accountName, long domainId, long zoneId) {
Account owner = _accountDao.findActiveAccount(accountName, domainId); Account owner = _accountDao.findActiveAccount(accountName, domainId);
@ -434,13 +466,12 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag
} }
@Override @DB @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(); String accountName = cmd.getAccountName();
long domainId = cmd.getDomainId(); long domainId = cmd.getDomainId();
Long zoneId = cmd.getZoneId(); Long zoneId = cmd.getZoneId();
Account caller = UserContext.current().getAccount(); Account caller = UserContext.current().getAccount();
long userId = UserContext.current().getUserId(); long userId = UserContext.current().getUserId();
Long accountId = null;
Account owner = _accountDao.findActiveAccount(accountName, domainId); Account owner = _accountDao.findActiveAccount(accountName, domainId);
if (owner == null) { if (owner == null) {
@ -449,6 +480,7 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag
_accountMgr.checkAccess(caller, owner); _accountMgr.checkAccess(caller, owner);
long ownerId = owner.getId();
Long networkId = cmd.getNetworkId(); Long networkId = cmd.getNetworkId();
Network network = null; Network network = null;
if (networkId != null) { if (networkId != null) {
@ -460,7 +492,7 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag
EventVO event = new EventVO(); EventVO event = new EventVO();
event.setUserId(userId); event.setUserId(userId);
event.setAccountId(accountId); event.setAccountId(ownerId);
event.setType(EventTypes.EVENT_NET_IP_ASSIGN); event.setType(EventTypes.EVENT_NET_IP_ASSIGN);
PublicIp ip = null; PublicIp ip = null;
@ -470,11 +502,11 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag
Account accountToLock = null; Account accountToLock = null;
try { try {
if (s_logger.isDebugEnabled()) { 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) { 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"); throw new ConcurrentOperationException("Unable to acquire account lock");
} }
@ -492,11 +524,11 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag
txn.start(); txn.start();
ip = fetchNewPublicIp(zoneId, VlanType.VirtualNetwork, owner, false); ip = fetchNewPublicIp(zoneId, VlanType.VirtualNetwork, owner, network.getId(), false);
if (ip == null) { if (ip == null) {
throw new InsufficientAddressCapacityException("Unable to find available public IP addresses", DataCenter.class, zoneId); 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(); String ipAddress = ip.getAddress();
@ -505,13 +537,8 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag
_eventDao.persist(event); _eventDao.persist(event);
txn.commit(); txn.commit();
if (network != null) {
for (NetworkElement element : _networkElements) {
element.associate(network, ip);
}
}
success = true; success = applyIpAssociations(network, false);
return ip; return ip;
} catch (ResourceUnavailableException e) { } catch (ResourceUnavailableException e) {
@ -519,16 +546,21 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag
return null; return null;
} finally { } finally {
if (caller != null) { if (caller != null) {
_accountDao.releaseFromLockTable(accountId); _accountDao.releaseFromLockTable(ownerId);
s_logger.debug("Associate IP address lock released"); s_logger.debug("Associate IP address lock released");
} }
if (!success) { if (!success) {
if (ip != null) { 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(); txn.start();
_ipAddressDao.unassignIpAddress(ip.getAddress()); _ipAddressDao.unassignIpAddress(ip.getAddress());
_accountMgr.decrementResourceCount(accountId, ResourceType.public_ip); _accountMgr.decrementResourceCount(ownerId, ResourceType.public_ip);
event.setLevel(EventVO.LEVEL_ERROR); event.setLevel(EventVO.LEVEL_ERROR);
event.setDescription(""); event.setDescription("");
@ -569,12 +601,15 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag
success = false; success = false;
} }
for (NetworkElement ne : _networkElements) { if (ip.getAssociatedNetworkId() != null) {
Network network = _networksDao.findById(ip.getAssociatedNetworkId());
try { 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) { } catch (ResourceUnavailableException e) {
s_logger.warn("Unable to release the ip address " + ip, e); throw new CloudRuntimeException("We should nver get to here because we used true when applyIpAssociations", e);
success = false;
} }
} }
@ -726,56 +761,65 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag
} }
@Override @Override
public List<NetworkVO> setupNetworkConfiguration(Account owner, NetworkOfferingVO offering, DeploymentPlan plan, String name, String displayText, boolean isShared) { public List<NetworkVO> setupNetwork(Account owner, NetworkOfferingVO offering, DeploymentPlan plan, String name, String displayText, boolean isShared) throws ConcurrentOperationException {
return setupNetwork(owner, offering, null, plan, name, displayText, isShared); return setupNetwork(owner, offering, null, plan, name, displayText, isShared);
} }
@Override @Override @DB
public List<NetworkVO> setupNetwork(Account owner, NetworkOfferingVO offering, Network predefined, DeploymentPlan plan, String name, String displayText, boolean isShared) { public List<NetworkVO> setupNetwork(Account owner, NetworkOfferingVO offering, Network predefined, DeploymentPlan plan, String name, String displayText, boolean isShared) throws ConcurrentOperationException {
Transaction.currentTxn();
List<NetworkVO> configs = _networksDao.listBy(owner.getId(), offering.getId(), plan.getDataCenterId()); Account locked = _accountDao.acquireInLockTable(owner.getId());
if (predefined == null || (predefined.getBroadcastUri() == null && predefined.getBroadcastDomainType() != BroadcastDomainType.Vlan)) { if (locked == null) {
if (configs.size() > 0) { throw new ConcurrentOperationException("Unable to acquire lock on " + owner);
if (s_logger.isDebugEnabled()) { }
s_logger.debug("Found existing network configuration for offering " + offering + ": " + configs.get(0)); try {
List<NetworkVO> 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<NetworkVO>();
long related = -1;
for (NetworkGuru guru : _networkGurus) {
Network config = guru.design(offering, plan, predefined, owner);
if (config == null) {
continue;
} }
if (config.getId() != -1) { configs = new ArrayList<NetworkVO>();
if (config instanceof NetworkVO) {
configs.add((NetworkVO)config); long related = -1;
} else {
configs.add(_networksDao.findById(config.getId())); 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 (configs.size() < 1) {
if (related == -1) { throw new CloudRuntimeException("Unable to convert network offering to network profile: " + offering.getId());
related = id;
} }
NetworkVO vo = new NetworkVO(id, config, offering.getId(), plan.getDataCenterId(), guru.getName(), owner.getDomainId(), owner.getId(), related, name, displayText, isShared); return configs;
configs.add(_networksDao.persist(vo)); } 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 @Override
@ -1179,9 +1223,9 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag
} }
@Override @Override
public List<NetworkVO> setupNetwork(Account owner, ServiceOfferingVO offering, DeploymentPlan plan) { public List<NetworkVO> setupNetwork(Account owner, ServiceOfferingVO offering, DeploymentPlan plan) throws ConcurrentOperationException {
NetworkOfferingVO networkOffering = _networkOfferingDao.findByServiceOffering(offering); NetworkOfferingVO networkOffering = _networkOfferingDao.findByServiceOffering(offering);
return setupNetworkConfiguration(owner, networkOffering, plan, null, null, false); return setupNetwork(owner, networkOffering, plan, null, null, false);
} }
private String [] getGuestIpRange() { private String [] getGuestIpRange() {

View File

@ -33,6 +33,8 @@ public interface IPAddressDao extends GenericDao<IPAddressVO, String> {
List<IPAddressVO> listByDcIdIpAddress(long dcId, String ipAddress); List<IPAddressVO> listByDcIdIpAddress(long dcId, String ipAddress);
List<IPAddressVO> listByNetwork(long networkId);
int countIPs(long dcId, long vlanDbId, boolean onlyCountAllocated); int countIPs(long dcId, long vlanDbId, boolean onlyCountAllocated);
int countIPs(long dcId, Long accountId, String vlanId, String vlanGateway, String vlanNetmask); int countIPs(long dcId, Long accountId, String vlanId, String vlanGateway, String vlanNetmask);
@ -40,10 +42,4 @@ public interface IPAddressDao extends GenericDao<IPAddressVO, String> {
boolean mark(long dcId, String ip); boolean mark(long dcId, String ip);
List<String> assignAcccountSpecificIps(long accountId, long longValue, Long vlanDbId, boolean sourceNat); List<String> assignAcccountSpecificIps(long accountId, long longValue, Long vlanDbId, boolean sourceNat);
void setIpAsSourceNat(String ipAddr);
void unassignIpAsSourceNat(String ipAddress);
} }

View File

@ -59,6 +59,7 @@ public class IPAddressDaoImpl extends GenericDaoBase<IPAddressVO, String> implem
AllFieldsSearch.and("vlan", AllFieldsSearch.entity().getVlanId(), Op.EQ); AllFieldsSearch.and("vlan", AllFieldsSearch.entity().getVlanId(), Op.EQ);
AllFieldsSearch.and("accountId", AllFieldsSearch.entity().getAllocatedToAccountId(), Op.EQ); AllFieldsSearch.and("accountId", AllFieldsSearch.entity().getAllocatedToAccountId(), Op.EQ);
AllFieldsSearch.and("sourceNat", AllFieldsSearch.entity().isSourceNat(), Op.EQ); AllFieldsSearch.and("sourceNat", AllFieldsSearch.entity().isSourceNat(), Op.EQ);
AllFieldsSearch.and("network", AllFieldsSearch.entity().getAssociatedNetworkId(), Op.EQ);
AllFieldsSearch.done(); AllFieldsSearch.done();
VlanDbIdSearchUnallocated = createSearchBuilder(); VlanDbIdSearchUnallocated = createSearchBuilder();
@ -122,15 +123,11 @@ public class IPAddressDaoImpl extends GenericDaoBase<IPAddressVO, String> implem
return ipStringList; return ipStringList;
} }
@Override /**
public void setIpAsSourceNat(String ipAddr) { * @deprecated This method is now deprecated because vlan has been
* added. The actual method is now within NetworkManager.
IPAddressVO ip = createForUpdate(ipAddr); */
ip.setSourceNat(true); @Deprecated
s_logger.debug("Setting " + ipAddr + " as source Nat ");
update(ipAddr, ip);
}
public IPAddressVO assignIpAddress(long accountId, long domainId, long vlanDbId, boolean sourceNat) { public IPAddressVO assignIpAddress(long accountId, long domainId, long vlanDbId, boolean sourceNat) {
Transaction txn = Transaction.currentTxn(); Transaction txn = Transaction.currentTxn();
txn.start(); txn.start();
@ -171,13 +168,7 @@ public class IPAddressDaoImpl extends GenericDaoBase<IPAddressVO, String> implem
address.setSourceNat(false); address.setSourceNat(false);
address.setOneToOneNat(false); address.setOneToOneNat(false);
address.setState(State.Free); address.setState(State.Free);
update(ipAddress, address); address.setAssociatedNetworkId(null);
}
@Override
public void unassignIpAsSourceNat(String ipAddress) {
IPAddressVO address = createForUpdate();
address.setSourceNat(false);
update(ipAddress, address); update(ipAddress, address);
} }
@ -185,7 +176,7 @@ public class IPAddressDaoImpl extends GenericDaoBase<IPAddressVO, String> implem
public List<IPAddressVO> listByAccount(long accountId) { public List<IPAddressVO> listByAccount(long accountId) {
SearchCriteria<IPAddressVO> sc = AllFieldsSearch.create(); SearchCriteria<IPAddressVO> sc = AllFieldsSearch.create();
sc.setParameters("accountId", accountId); sc.setParameters("accountId", accountId);
return listIncludingRemovedBy(sc); return listBy(sc);
} }
@Override @Override
@ -193,7 +184,15 @@ public class IPAddressDaoImpl extends GenericDaoBase<IPAddressVO, String> implem
SearchCriteria<IPAddressVO> sc = AllFieldsSearch.create(); SearchCriteria<IPAddressVO> sc = AllFieldsSearch.create();
sc.setParameters("dataCenterId", dcId); sc.setParameters("dataCenterId", dcId);
sc.setParameters("ipAddress", ipAddress); sc.setParameters("ipAddress", ipAddress);
return listIncludingRemovedBy(sc); return listBy(sc);
}
@Override
public List<IPAddressVO> listByNetwork(long networkId) {
SearchCriteria<IPAddressVO> sc = AllFieldsSearch.create();
sc.setParameters("network", networkId);
return listBy(sc);
} }
@Override @Override

View File

@ -142,13 +142,13 @@ public class DomainRouterElement extends AdapterBase implements NetworkElement {
} }
@Override @Override
public boolean associate(Network network, IpAddress ipAddress) throws ResourceUnavailableException { public boolean associate(Network network, List<? extends IpAddress> ipAddress) throws ResourceUnavailableException {
// TODO Auto-generated method stub // TODO Auto-generated method stub
return false; return false;
} }
@Override @Override
public boolean disassociate(Network network, IpAddress ipAddress) throws ResourceUnavailableException { public boolean disassociate(Network network, List<? extends IpAddress> ipAddress) throws ResourceUnavailableException {
// TODO Auto-generated method stub // TODO Auto-generated method stub
return false; return false;
} }

View File

@ -2096,11 +2096,11 @@ public class DomainRouterManagerImpl implements DomainRouterManager, DomainRoute
List<NetworkOfferingVO> offerings = _networkMgr.getSystemAccountNetworkOfferings(NetworkOfferingVO.SystemVmControlNetwork); List<NetworkOfferingVO> offerings = _networkMgr.getSystemAccountNetworkOfferings(NetworkOfferingVO.SystemVmControlNetwork);
NetworkOfferingVO controlOffering = offerings.get(0); 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<Pair<NetworkVO, NicProfile>> networks = new ArrayList<Pair<NetworkVO, NicProfile>>(3); List<Pair<NetworkVO, NicProfile>> networks = new ArrayList<Pair<NetworkVO, NicProfile>>(3);
NetworkOfferingVO publicOffering = _networkMgr.getSystemAccountNetworkOfferings(NetworkOfferingVO.SystemVmPublicNetwork).get(0); NetworkOfferingVO publicOffering = _networkMgr.getSystemAccountNetworkOfferings(NetworkOfferingVO.SystemVmPublicNetwork).get(0);
List<NetworkVO> publicConfigs = _networkMgr.setupNetworkConfiguration(_systemAcct, publicOffering, plan, null, null, false); List<NetworkVO> publicConfigs = _networkMgr.setupNetwork(_systemAcct, publicOffering, plan, null, null, false);
NicProfile defaultNic = new NicProfile(); NicProfile defaultNic = new NicProfile();
defaultNic.setDefaultNic(true); defaultNic.setDefaultNic(true);
//defaultNic.setIp4Address(sourceNatIp); //defaultNic.setIp4Address(sourceNatIp);

View File

@ -761,9 +761,14 @@ public class SecondaryStorageManagerImpl implements SecondaryStorageVmManager, V
NicProfile defaultNic = new NicProfile(); NicProfile defaultNic = new NicProfile();
defaultNic.setDefaultNic(true); defaultNic.setDefaultNic(true);
defaultNic.setDeviceId(2); defaultNic.setDeviceId(2);
networks.add(new Pair<NetworkVO, NicProfile>(_networkMgr.setupNetworkConfiguration(systemAcct, defaultOffering.get(0), plan, null, null, false).get(0), defaultNic)); try {
for (NetworkOfferingVO offering : offerings) { networks.add(new Pair<NetworkVO, NicProfile>(_networkMgr.setupNetwork(systemAcct, defaultOffering.get(0), plan, null, null, false).get(0), defaultNic));
networks.add(new Pair<NetworkVO, NicProfile>(_networkMgr.setupNetworkConfiguration(systemAcct, offering, plan, null, null, false).get(0), null)); for (NetworkOfferingVO offering : offerings) {
networks.add(new Pair<NetworkVO, NicProfile>(_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<String, Object>();
} }
SecondaryStorageVmVO secStorageVm = new SecondaryStorageVmVO(id, _serviceOffering.getId(), name, _template.getId(), SecondaryStorageVmVO secStorageVm = new SecondaryStorageVmVO(id, _serviceOffering.getId(), name, _template.getId(),
_template.getGuestOSId(), dataCenterId, systemAcct.getDomainId(), systemAcct.getId()); _template.getGuestOSId(), dataCenterId, systemAcct.getDomainId(), systemAcct.getId());

View File

@ -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 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`.`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__removed`(`removed`);
ALTER TABLE `cloud`.`vm_template` ADD INDEX `i_vm_template__public`(`public`); ALTER TABLE `cloud`.`vm_template` ADD INDEX `i_vm_template__public`(`public`);

View File

@ -628,7 +628,12 @@ CREATE TABLE `cloud`.`user_ip_address` (
`mac_address` bigint unsigned NOT NULL COMMENT 'mac address of this ip', `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', `network_id` bigint unsigned COMMENT 'network this public ip address is associated with',
PRIMARY KEY (`public_ip_address`), 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; ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `cloud`.`user_statistics` ( CREATE TABLE `cloud`.`user_statistics` (