mirror of https://github.com/apache/cloudstack.git
2056 lines
88 KiB
Java
Executable File
2056 lines
88 KiB
Java
Executable File
/**
|
|
* Copyright (C) 2010 Cloud.com, Inc. All rights reserved.
|
|
*
|
|
* This software is licensed under the GNU General Public License v3 or later.
|
|
*
|
|
* It is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or any later version.
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
package com.cloud.network;
|
|
|
|
import java.net.URI;
|
|
import java.util.ArrayList;
|
|
import java.util.Arrays;
|
|
import java.util.Date;
|
|
import java.util.HashMap;
|
|
import java.util.Iterator;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.concurrent.Executors;
|
|
import java.util.concurrent.ScheduledExecutorService;
|
|
import java.util.concurrent.TimeUnit;
|
|
|
|
import javax.ejb.Local;
|
|
import javax.naming.ConfigurationException;
|
|
|
|
import org.apache.log4j.Logger;
|
|
|
|
import com.cloud.agent.api.to.NicTO;
|
|
import com.cloud.alert.AlertManager;
|
|
import com.cloud.api.BaseCmd;
|
|
import com.cloud.api.commands.AssociateIPAddrCmd;
|
|
import com.cloud.api.commands.CreateNetworkCmd;
|
|
import com.cloud.api.commands.DisassociateIPAddrCmd;
|
|
import com.cloud.api.commands.ListNetworksCmd;
|
|
import com.cloud.api.commands.RestartNetworkCmd;
|
|
import com.cloud.capacity.dao.CapacityDao;
|
|
import com.cloud.configuration.Config;
|
|
import com.cloud.configuration.ConfigurationManager;
|
|
import com.cloud.configuration.ResourceCount.ResourceType;
|
|
import com.cloud.configuration.dao.ConfigurationDao;
|
|
import com.cloud.configuration.dao.ResourceLimitDao;
|
|
import com.cloud.dc.AccountVlanMapVO;
|
|
import com.cloud.dc.DataCenter;
|
|
import com.cloud.dc.DataCenter.NetworkType;
|
|
import com.cloud.dc.DataCenterVO;
|
|
import com.cloud.dc.PodVlanMapVO;
|
|
import com.cloud.dc.Vlan;
|
|
import com.cloud.dc.Vlan.VlanType;
|
|
import com.cloud.dc.VlanVO;
|
|
import com.cloud.dc.dao.AccountVlanMapDao;
|
|
import com.cloud.dc.dao.DataCenterDao;
|
|
import com.cloud.dc.dao.PodVlanMapDao;
|
|
import com.cloud.dc.dao.VlanDao;
|
|
import com.cloud.deploy.DataCenterDeployment;
|
|
import com.cloud.deploy.DeployDestination;
|
|
import com.cloud.deploy.DeploymentPlan;
|
|
import com.cloud.domain.Domain;
|
|
import com.cloud.domain.dao.DomainDao;
|
|
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.AccountLimitException;
|
|
import com.cloud.exception.ConcurrentOperationException;
|
|
import com.cloud.exception.InsufficientAddressCapacityException;
|
|
import com.cloud.exception.InsufficientCapacityException;
|
|
import com.cloud.exception.InvalidParameterValueException;
|
|
import com.cloud.exception.PermissionDeniedException;
|
|
import com.cloud.exception.ResourceAllocationException;
|
|
import com.cloud.exception.ResourceUnavailableException;
|
|
import com.cloud.network.Network.Capability;
|
|
import com.cloud.network.Network.GuestIpType;
|
|
import com.cloud.network.Network.Service;
|
|
import com.cloud.network.Networks.AddressFormat;
|
|
import com.cloud.network.Networks.BroadcastDomainType;
|
|
import com.cloud.network.Networks.TrafficType;
|
|
import com.cloud.network.addr.PublicIp;
|
|
import com.cloud.network.dao.IPAddressDao;
|
|
import com.cloud.network.dao.NetworkDao;
|
|
import com.cloud.network.element.NetworkElement;
|
|
import com.cloud.network.guru.NetworkGuru;
|
|
import com.cloud.network.lb.LoadBalancingRulesManager;
|
|
import com.cloud.network.rules.FirewallRule;
|
|
import com.cloud.network.rules.RulesManager;
|
|
import com.cloud.network.vpn.PasswordResetElement;
|
|
import com.cloud.network.vpn.RemoteAccessVpnElement;
|
|
import com.cloud.offering.NetworkOffering;
|
|
import com.cloud.offering.NetworkOffering.Availability;
|
|
import com.cloud.offerings.NetworkOfferingVO;
|
|
import com.cloud.offerings.dao.NetworkOfferingDao;
|
|
import com.cloud.user.Account;
|
|
import com.cloud.user.AccountManager;
|
|
import com.cloud.user.AccountVO;
|
|
import com.cloud.user.User;
|
|
import com.cloud.user.UserContext;
|
|
import com.cloud.user.UserStatisticsVO;
|
|
import com.cloud.user.dao.AccountDao;
|
|
import com.cloud.user.dao.UserStatisticsDao;
|
|
import com.cloud.utils.NumbersUtil;
|
|
import com.cloud.utils.Pair;
|
|
import com.cloud.utils.component.Adapters;
|
|
import com.cloud.utils.component.Inject;
|
|
import com.cloud.utils.component.Manager;
|
|
import com.cloud.utils.concurrency.NamedThreadFactory;
|
|
import com.cloud.utils.db.DB;
|
|
import com.cloud.utils.db.Filter;
|
|
import com.cloud.utils.db.JoinBuilder;
|
|
import com.cloud.utils.db.JoinBuilder.JoinType;
|
|
import com.cloud.utils.db.SearchBuilder;
|
|
import com.cloud.utils.db.SearchCriteria;
|
|
import com.cloud.utils.db.SearchCriteria.Op;
|
|
import com.cloud.utils.db.Transaction;
|
|
import com.cloud.utils.exception.CloudRuntimeException;
|
|
import com.cloud.utils.net.Ip;
|
|
import com.cloud.utils.net.NetUtils;
|
|
import com.cloud.vm.Nic;
|
|
import com.cloud.vm.NicProfile;
|
|
import com.cloud.vm.NicVO;
|
|
import com.cloud.vm.ReservationContext;
|
|
import com.cloud.vm.ReservationContextImpl;
|
|
import com.cloud.vm.VMInstanceVO;
|
|
import com.cloud.vm.VirtualMachine;
|
|
import com.cloud.vm.VirtualMachine.Type;
|
|
import com.cloud.vm.VirtualMachineProfile;
|
|
import com.cloud.vm.dao.NicDao;
|
|
import com.cloud.vm.dao.UserVmDao;
|
|
|
|
/**
|
|
* NetworkManagerImpl implements NetworkManager.
|
|
*/
|
|
@Local(value = { NetworkManager.class, NetworkService.class })
|
|
public class NetworkManagerImpl implements NetworkManager, NetworkService, Manager {
|
|
private static final Logger s_logger = Logger.getLogger(NetworkManagerImpl.class);
|
|
|
|
String _name;
|
|
@Inject
|
|
DataCenterDao _dcDao = null;
|
|
@Inject
|
|
VlanDao _vlanDao = null;
|
|
@Inject
|
|
IPAddressDao _ipAddressDao = null;
|
|
@Inject
|
|
AccountDao _accountDao = null;
|
|
@Inject
|
|
DomainDao _domainDao = null;
|
|
@Inject
|
|
UserStatisticsDao _userStatsDao = null;
|
|
@Inject
|
|
EventDao _eventDao = null;
|
|
@Inject
|
|
ConfigurationDao _configDao;
|
|
@Inject
|
|
UserVmDao _vmDao = null;
|
|
@Inject
|
|
ResourceLimitDao _limitDao = null;
|
|
@Inject
|
|
CapacityDao _capacityDao = null;
|
|
@Inject
|
|
AlertManager _alertMgr;
|
|
@Inject
|
|
AccountManager _accountMgr;
|
|
@Inject
|
|
ConfigurationManager _configMgr;
|
|
@Inject
|
|
AccountVlanMapDao _accountVlanMapDao;
|
|
@Inject
|
|
NetworkOfferingDao _networkOfferingDao = null;
|
|
@Inject
|
|
NetworkDao _networksDao = null;
|
|
@Inject
|
|
NicDao _nicDao = null;
|
|
@Inject
|
|
RulesManager _rulesMgr;
|
|
@Inject
|
|
LoadBalancingRulesManager _lbMgr;
|
|
@Inject
|
|
UsageEventDao _usageEventDao;
|
|
@Inject
|
|
PodVlanMapDao _podVlanMapDao;
|
|
@Inject(adapter = NetworkGuru.class)
|
|
Adapters<NetworkGuru> _networkGurus;
|
|
@Inject(adapter = NetworkElement.class)
|
|
Adapters<NetworkElement> _networkElements;
|
|
|
|
private HashMap<String, NetworkOfferingVO> _systemNetworks = new HashMap<String, NetworkOfferingVO>(5);
|
|
|
|
ScheduledExecutorService _executor;
|
|
|
|
SearchBuilder<AccountVO> AccountsUsingNetworkSearch;
|
|
SearchBuilder<IPAddressVO> AssignIpAddressSearch;
|
|
SearchBuilder<IPAddressVO> AssignIpAddressFromPodVlanSearch;
|
|
SearchBuilder<IPAddressVO> IpAddressSearch;
|
|
SearchBuilder<NicVO> NicForTrafficTypeSearch;
|
|
|
|
int _networkGcWait;
|
|
int _networkGcInterval;
|
|
String _networkDomain;
|
|
|
|
private Map<String, String> _configs;
|
|
|
|
HashMap<Long, Long> _lastNetworkIdsToFree = new HashMap<Long, Long>();
|
|
|
|
@Override
|
|
public PublicIp assignPublicIpAddress(long dcId, Long podId, Account owner, VlanType type, Long networkId) throws InsufficientAddressCapacityException {
|
|
return fetchNewPublicIp(dcId, podId, null, owner, type, networkId, false, true);
|
|
}
|
|
|
|
@DB
|
|
public PublicIp fetchNewPublicIp(long dcId, Long podId, Long vlanDbId, Account owner, VlanType vlanUse, Long networkId, boolean sourceNat, boolean assign) throws InsufficientAddressCapacityException {
|
|
Transaction txn = Transaction.currentTxn();
|
|
txn.start();
|
|
SearchCriteria<IPAddressVO> sc = null;
|
|
if (podId != null) {
|
|
sc = AssignIpAddressFromPodVlanSearch.create();
|
|
sc.setJoinParameters("podVlanMapSB", "podId", podId);
|
|
} else {
|
|
sc = AssignIpAddressSearch.create();
|
|
}
|
|
|
|
if (vlanDbId != null) {
|
|
sc.addAnd("vlanId", SearchCriteria.Op.EQ, vlanDbId);
|
|
}
|
|
|
|
sc.setParameters("dc", dcId);
|
|
|
|
// for direct network take ip addresses only from the vlans belonging to the network
|
|
if (vlanUse == VlanType.DirectAttached) {
|
|
sc.setJoinParameters("vlan", "networkId", networkId);
|
|
}
|
|
sc.setJoinParameters("vlan", "type", vlanUse);
|
|
|
|
Filter filter = new Filter(IPAddressVO.class, "vlanId", true, 0l, 1l);
|
|
|
|
List<IPAddressVO> addrs = _ipAddressDao.lockRows(sc, filter, true);
|
|
|
|
if (addrs.size() == 0) {
|
|
throw new InsufficientAddressCapacityException("Insufficient address capacity", DataCenter.class, dcId);
|
|
}
|
|
|
|
assert (addrs.size() == 1) : "Return size is incorrect: " + addrs.size();
|
|
|
|
IPAddressVO addr = addrs.get(0);
|
|
addr.setSourceNat(sourceNat);
|
|
addr.setAllocatedTime(new Date());
|
|
addr.setAllocatedInDomainId(owner.getDomainId());
|
|
addr.setAllocatedToAccountId(owner.getId());
|
|
|
|
addr.setState(assign ? IpAddress.State.Allocated : IpAddress.State.Allocating);
|
|
|
|
if (vlanUse == VlanType.DirectAttached) {
|
|
addr.setState(IpAddress.State.Allocated);
|
|
} else {
|
|
addr.setAssociatedWithNetworkId(networkId);
|
|
}
|
|
|
|
if (!_ipAddressDao.update(addr.getAddress(), addr)) {
|
|
throw new CloudRuntimeException("Found address to allocate but unable to update: " + addr);
|
|
}
|
|
if(owner.getAccountId() != Account.ACCOUNT_ID_SYSTEM){
|
|
long isSourceNat = (sourceNat) ? 1 : 0 ;
|
|
UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_NET_IP_ASSIGN, owner.getAccountId(), dcId, isSourceNat, addr.getAddress().toString());
|
|
_usageEventDao.persist(usageEvent);
|
|
}
|
|
|
|
txn.commit();
|
|
long macAddress = NetUtils.createSequenceBasedMacAddress(addr.getMacAddress());
|
|
|
|
return new PublicIp(addr, _vlanDao.findById(addr.getVlanId()), macAddress);
|
|
}
|
|
|
|
@Override
|
|
@DB
|
|
public PublicIp assignSourceNatIpAddress(Account owner, Network network, long callerId) throws ConcurrentOperationException, InsufficientAddressCapacityException {
|
|
assert (network.getTrafficType() != null) : "You're asking for a source nat but your network can't participate in source nat. What do you have to say for yourself?";
|
|
|
|
long dcId = network.getDataCenterId();
|
|
long ownerId = owner.getId();
|
|
|
|
PublicIp ip = null;
|
|
|
|
Transaction txn = Transaction.currentTxn();
|
|
try {
|
|
txn.start();
|
|
|
|
owner = _accountDao.acquireInLockTable(ownerId);
|
|
if (owner == null) {
|
|
throw new ConcurrentOperationException("Unable to lock account " + ownerId);
|
|
}
|
|
if (s_logger.isDebugEnabled()) {
|
|
s_logger.debug("lock account " + ownerId + " is acquired");
|
|
}
|
|
|
|
IPAddressVO sourceNat = null;
|
|
List<IPAddressVO> addrs = listPublicIpAddressesInVirtualNetwork(ownerId, dcId, null);
|
|
if (addrs.size() == 0) {
|
|
// Check that the maximum number of public IPs for the given accountId will not be exceeded
|
|
if (_accountMgr.resourceLimitExceeded(owner, ResourceType.public_ip)) {
|
|
throw new AccountLimitException("Maximum number of public IP addresses for account: " + owner.getAccountName() + " has been exceeded.");
|
|
}
|
|
|
|
if (s_logger.isDebugEnabled()) {
|
|
s_logger.debug("assigning a new ip address in " + dcId + " to " + owner);
|
|
}
|
|
|
|
//If account has Account specific ip ranges, try to allocate ip from there
|
|
Long vlanId = null;
|
|
List<AccountVlanMapVO> maps = _accountVlanMapDao.listAccountVlanMapsByAccount(ownerId);
|
|
if (maps != null && !maps.isEmpty()) {
|
|
vlanId = maps.get(0).getVlanDbId();
|
|
}
|
|
|
|
ip = fetchNewPublicIp(dcId, null, vlanId, owner, VlanType.VirtualNetwork, network.getId(), true, false);
|
|
sourceNat = ip.ip();
|
|
sourceNat.setState(IpAddress.State.Allocated);
|
|
_ipAddressDao.update(sourceNat.getAddress(), sourceNat);
|
|
|
|
// Increment the number of public IPs for this accountId in the database
|
|
_accountMgr.incrementResourceCount(ownerId, ResourceType.public_ip);
|
|
} else {
|
|
// Account already has ip addresses
|
|
for (IPAddressVO addr : addrs) {
|
|
if (addr.isSourceNat()) {
|
|
sourceNat = addr;
|
|
break;
|
|
}
|
|
}
|
|
|
|
assert (sourceNat != null) : "How do we get a bunch of ip addresses but none of them are source nat? account=" + ownerId + "; dc=" + dcId;
|
|
ip = new PublicIp(sourceNat, _vlanDao.findById(sourceNat.getVlanId()), NetUtils.createSequenceBasedMacAddress(sourceNat.getMacAddress()));
|
|
}
|
|
|
|
UserStatisticsVO stats = _userStatsDao.findBy(ownerId, dcId, null, null);
|
|
if (stats == null) {
|
|
if (s_logger.isDebugEnabled()) {
|
|
s_logger.debug("Creating statistics for the owner: " + ownerId);
|
|
}
|
|
stats = new UserStatisticsVO(ownerId, dcId, null, null);
|
|
_userStatsDao.persist(stats);
|
|
}
|
|
txn.commit();
|
|
return ip;
|
|
} finally {
|
|
if (owner != null) {
|
|
if (s_logger.isDebugEnabled()) {
|
|
s_logger.debug("Releasing lock account " + ownerId);
|
|
}
|
|
|
|
_accountDao.releaseFromLockTable(ownerId);
|
|
}
|
|
if (ip == null) {
|
|
txn.rollback();
|
|
s_logger.error("Unable to get source nat ip address for account " + ownerId);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns the target account for an api command
|
|
*
|
|
* @param accountName
|
|
* - non-null if the account name was passed in in the command
|
|
* @param domainId
|
|
* - non-null if the domainId was passed in in the command.
|
|
* @return
|
|
*/
|
|
protected Account getAccountForApiCommand(String accountName, Long domainId) throws InvalidParameterValueException, PermissionDeniedException {
|
|
Account account = UserContext.current().getCaller();
|
|
|
|
if (_accountMgr.isAdmin(account.getType())) {
|
|
// The admin is making the call, determine if it is for someone else or for himself
|
|
if (domainId != null) {
|
|
if ((account != null) && !_domainDao.isChildDomain(account.getDomainId(), domainId)) {
|
|
throw new PermissionDeniedException("Invalid domain id (" + domainId + ") given, , permission denied");
|
|
}
|
|
if (accountName != null) {
|
|
Account userAccount = _accountMgr.getActiveAccount(accountName, domainId);
|
|
if (userAccount != null) {
|
|
account = userAccount;
|
|
} else {
|
|
throw new PermissionDeniedException("Unable to find account " + accountName + " in domain " + domainId + ", permission denied");
|
|
}
|
|
}
|
|
} else {
|
|
// the admin is calling the api on his own behalf
|
|
return account;
|
|
}
|
|
}
|
|
return account;
|
|
}
|
|
|
|
public boolean applyIpAssociations(Network network, boolean continueOnError) throws ResourceUnavailableException {
|
|
List<IPAddressVO> userIps = _ipAddressDao.listByAssociatedNetwork(network.getId());
|
|
List<PublicIp> publicIps = new ArrayList<PublicIp>();
|
|
if (userIps != null && !userIps.isEmpty()) {
|
|
for (IPAddressVO userIp : userIps) {
|
|
PublicIp publicIp = new PublicIp(userIp, _vlanDao.findById(userIp.getVlanId()), userIp.getMacAddress());
|
|
publicIps.add(publicIp);
|
|
}
|
|
}
|
|
|
|
boolean success = true;
|
|
for (NetworkElement element : _networkElements) {
|
|
try {
|
|
element.applyIps(network, publicIps);
|
|
} 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);
|
|
addr.setAssociatedWithNetworkId(network.getId());
|
|
_ipAddressDao.update(addr.getAddress(), addr);
|
|
} else if (addr.getState() == IpAddress.State.Releasing) {
|
|
_ipAddressDao.unassignIpAddress(addr.getAddress());
|
|
}
|
|
}
|
|
}
|
|
|
|
return success;
|
|
}
|
|
|
|
@Override
|
|
public List<? extends Network> getVirtualNetworksOwnedByAccountInZone(String accountName, long domainId, long zoneId) {
|
|
Account owner = _accountMgr.getActiveAccount(accountName, domainId);
|
|
if (owner == null) {
|
|
throw new InvalidParameterValueException("Unable to find account " + accountName + " in domain " + domainId + ", permission denied");
|
|
}
|
|
|
|
return _networksDao.listBy(owner.getId(), zoneId, GuestIpType.Virtual);
|
|
}
|
|
|
|
@Override
|
|
@DB
|
|
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().getCaller();
|
|
long userId = UserContext.current().getCallerUserId();
|
|
|
|
Account owner = _accountMgr.getActiveAccount(accountName, domainId);
|
|
if (owner == null) {
|
|
throw new InvalidParameterValueException("Unable to find account " + accountName + " in domain " + domainId + ", permission denied");
|
|
}
|
|
|
|
_accountMgr.checkAccess(caller, owner);
|
|
|
|
long ownerId = owner.getId();
|
|
Long networkId = cmd.getNetworkId();
|
|
Network network = null;
|
|
if (networkId != null) {
|
|
network = _networksDao.findById(networkId);
|
|
if (network == null) {
|
|
throw new InvalidParameterValueException("Network id is invalid: " + networkId);
|
|
}
|
|
}
|
|
|
|
PublicIp ip = null;
|
|
boolean success = false;
|
|
|
|
Transaction txn = Transaction.currentTxn();
|
|
Account accountToLock = null;
|
|
try {
|
|
if (s_logger.isDebugEnabled()) {
|
|
s_logger.debug("Associate IP address called for user " + userId + " account " + ownerId);
|
|
}
|
|
accountToLock = _accountDao.acquireInLockTable(ownerId);
|
|
if (accountToLock == null) {
|
|
s_logger.warn("Unable to lock account: " + ownerId);
|
|
throw new ConcurrentOperationException("Unable to acquire account lock");
|
|
}
|
|
|
|
if (s_logger.isDebugEnabled()) {
|
|
s_logger.debug("Associate IP address lock acquired");
|
|
}
|
|
|
|
// Check that the maximum number of public IPs for the given
|
|
// accountId will not be exceeded
|
|
if (_accountMgr.resourceLimitExceeded(accountToLock, ResourceType.public_ip)) {
|
|
ResourceAllocationException rae = new ResourceAllocationException("Maximum number of public IP addresses for account: " + accountToLock.getAccountName() + " has been exceeded.");
|
|
rae.setResourceType("ip");
|
|
throw rae;
|
|
}
|
|
|
|
txn.start();
|
|
ip = fetchNewPublicIp(zoneId, null, null, owner, VlanType.VirtualNetwork, network.getId(), false, false);
|
|
|
|
if (ip == null) {
|
|
throw new InsufficientAddressCapacityException("Unable to find available public IP addresses", DataCenter.class, zoneId);
|
|
}
|
|
|
|
_accountMgr.incrementResourceCount(ownerId, ResourceType.public_ip);
|
|
|
|
Ip ipAddress = ip.getAddress();
|
|
|
|
s_logger.debug("Got " + ipAddress + " to assign for account " + owner.getId() + " in zone " + network.getDataCenterId());
|
|
|
|
txn.commit();
|
|
|
|
success = applyIpAssociations(network, false);
|
|
if (success) {
|
|
s_logger.debug("Successfully associated ip address " + ip + " for account " + owner.getId() + " in zone " + network.getDataCenterId());
|
|
} else {
|
|
s_logger.warn("Failed to associate ip address " + ip + " for account " + owner.getId() + " in zone " + network.getDataCenterId());
|
|
}
|
|
|
|
return ip;
|
|
} catch (ResourceUnavailableException e) {
|
|
s_logger.error("Unable to associate ip address due to resource unavailable exception", e);
|
|
return null;
|
|
} finally {
|
|
if (accountToLock != null) {
|
|
_accountDao.releaseFromLockTable(ownerId);
|
|
s_logger.debug("Associate IP address lock released");
|
|
}
|
|
|
|
if (!success) {
|
|
if (ip != null) {
|
|
try {
|
|
s_logger.warn("Failed to associate ip address " + ip);
|
|
_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(ownerId, ResourceType.public_ip);
|
|
|
|
txn.commit();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public boolean releasePublicIpAddress(Ip addr, long ownerId, long userId) {
|
|
IPAddressVO ip = _ipAddressDao.markAsUnavailable(addr, ownerId);
|
|
assert (ip != null) : "Unable to mark the ip address " + addr + " owned by " + ownerId + " as unavailable.";
|
|
if (ip == null) {
|
|
return true;
|
|
}
|
|
|
|
if (s_logger.isDebugEnabled()) {
|
|
s_logger.debug("Releasing ip " + addr + "; sourceNat = " + ip.isSourceNat());
|
|
}
|
|
|
|
boolean success = true;
|
|
try {
|
|
if (!_rulesMgr.revokeAllRules(addr, userId)) {
|
|
s_logger.warn("Unable to revoke all the port forwarding rules for ip " + ip);
|
|
success = false;
|
|
}
|
|
} catch (ResourceUnavailableException e) {
|
|
s_logger.warn("Unable to revoke all the port forwarding rules for ip " + ip, e);
|
|
success = false;
|
|
}
|
|
|
|
if (!_lbMgr.removeAllLoadBalanacers(addr)) {
|
|
s_logger.warn("Unable to revoke all the load balancer rules for ip " + ip);
|
|
success = false;
|
|
}
|
|
|
|
if (ip.getAssociatedWithNetworkId() != null) {
|
|
Network network = _networksDao.findById(ip.getAssociatedWithNetworkId());
|
|
try {
|
|
if (!applyIpAssociations(network, true)) {
|
|
s_logger.warn("Unable to apply ip address associations for " + network);
|
|
success = false;
|
|
}
|
|
} catch (ResourceUnavailableException e) {
|
|
throw new CloudRuntimeException("We should nver get to here because we used true when applyIpAssociations", e);
|
|
}
|
|
}
|
|
|
|
if (success) {
|
|
_ipAddressDao.unassignIpAddress(addr);
|
|
s_logger.debug("released a public ip: " + addr);
|
|
if(ownerId != Account.ACCOUNT_ID_SYSTEM){
|
|
UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_NET_IP_RELEASE, ownerId, ip.getDataCenterId(), 0, addr.toString());
|
|
_usageEventDao.persist(usageEvent);
|
|
}
|
|
|
|
_accountMgr.decrementResourceCount(ownerId, ResourceType.public_ip);
|
|
}
|
|
|
|
return success;
|
|
}
|
|
|
|
@Override
|
|
public boolean configure(final String name, final Map<String, Object> params) throws ConfigurationException {
|
|
_name = name;
|
|
|
|
_configs = _configDao.getConfiguration("AgentManager", params);
|
|
_networkGcWait = NumbersUtil.parseInt(_configs.get(Config.NetworkGcWait.key()), 600);
|
|
_networkGcInterval = NumbersUtil.parseInt(_configs.get(Config.NetworkGcInterval.key()), 600);
|
|
|
|
_configs = _configDao.getConfiguration("Network", params);
|
|
_networkDomain = _configs.get(Config.GuestDomainSuffix.key());
|
|
|
|
NetworkOfferingVO publicNetworkOffering = new NetworkOfferingVO(NetworkOfferingVO.SystemPublicNetwork, TrafficType.Public);
|
|
publicNetworkOffering = _networkOfferingDao.persistDefaultNetworkOffering(publicNetworkOffering);
|
|
_systemNetworks.put(NetworkOfferingVO.SystemPublicNetwork, publicNetworkOffering);
|
|
NetworkOfferingVO managementNetworkOffering = new NetworkOfferingVO(NetworkOfferingVO.SystemManagementNetwork, TrafficType.Management);
|
|
managementNetworkOffering = _networkOfferingDao.persistDefaultNetworkOffering(managementNetworkOffering);
|
|
_systemNetworks.put(NetworkOfferingVO.SystemManagementNetwork, managementNetworkOffering);
|
|
NetworkOfferingVO controlNetworkOffering = new NetworkOfferingVO(NetworkOfferingVO.SystemControlNetwork, TrafficType.Control);
|
|
controlNetworkOffering = _networkOfferingDao.persistDefaultNetworkOffering(controlNetworkOffering);
|
|
_systemNetworks.put(NetworkOfferingVO.SystemControlNetwork, controlNetworkOffering);
|
|
NetworkOfferingVO storageNetworkOffering = new NetworkOfferingVO(NetworkOfferingVO.SystemStorageNetwork, TrafficType.Storage);
|
|
storageNetworkOffering = _networkOfferingDao.persistDefaultNetworkOffering(storageNetworkOffering);
|
|
_systemNetworks.put(NetworkOfferingVO.SystemStorageNetwork, storageNetworkOffering);
|
|
NetworkOfferingVO guestNetworkOffering = new NetworkOfferingVO(NetworkOfferingVO.SystemGuestNetwork, TrafficType.Guest);
|
|
guestNetworkOffering = _networkOfferingDao.persistDefaultNetworkOffering(guestNetworkOffering);
|
|
_systemNetworks.put(NetworkOfferingVO.SystemGuestNetwork, guestNetworkOffering);
|
|
|
|
NetworkOfferingVO defaultGuestNetworkOffering = new NetworkOfferingVO(NetworkOffering.DefaultVirtualizedNetworkOffering, "Virtual Vlan", TrafficType.Guest, false, false, null, null, null, true, Availability.Required, false, false, false, false,
|
|
false, false, false);
|
|
defaultGuestNetworkOffering = _networkOfferingDao.persistDefaultNetworkOffering(defaultGuestNetworkOffering);
|
|
NetworkOfferingVO defaultGuestDirectNetworkOffering = new NetworkOfferingVO(NetworkOffering.DefaultDirectNetworkOffering, "Direct", TrafficType.Public, false, false, null, null, null, true, Availability.Required, false, false, false, false, false,
|
|
false, false);
|
|
defaultGuestDirectNetworkOffering = _networkOfferingDao.persistDefaultNetworkOffering(defaultGuestDirectNetworkOffering);
|
|
|
|
AccountsUsingNetworkSearch = _accountDao.createSearchBuilder();
|
|
SearchBuilder<NetworkAccountVO> networkAccountSearch = _networksDao.createSearchBuilderForAccount();
|
|
AccountsUsingNetworkSearch.join("nc", networkAccountSearch, AccountsUsingNetworkSearch.entity().getId(), networkAccountSearch.entity().getAccountId(), JoinType.INNER);
|
|
networkAccountSearch.and("config", networkAccountSearch.entity().getNetworkId(), SearchCriteria.Op.EQ);
|
|
networkAccountSearch.and("owner", networkAccountSearch.entity().isOwner(), SearchCriteria.Op.EQ);
|
|
AccountsUsingNetworkSearch.done();
|
|
|
|
AssignIpAddressSearch = _ipAddressDao.createSearchBuilder();
|
|
AssignIpAddressSearch.and("dc", AssignIpAddressSearch.entity().getDataCenterId(), Op.EQ);
|
|
AssignIpAddressSearch.and("allocated", AssignIpAddressSearch.entity().getAllocatedTime(), Op.NULL);
|
|
AssignIpAddressSearch.and("vlanId", AssignIpAddressSearch.entity().getVlanId(), Op.EQ);
|
|
SearchBuilder<VlanVO> vlanSearch = _vlanDao.createSearchBuilder();
|
|
vlanSearch.and("type", vlanSearch.entity().getVlanType(), Op.EQ);
|
|
vlanSearch.and("networkId", vlanSearch.entity().getNetworkId(), Op.EQ);
|
|
AssignIpAddressSearch.join("vlan", vlanSearch, vlanSearch.entity().getId(), AssignIpAddressSearch.entity().getVlanId(), JoinType.INNER);
|
|
AssignIpAddressSearch.done();
|
|
|
|
AssignIpAddressFromPodVlanSearch = _ipAddressDao.createSearchBuilder();
|
|
AssignIpAddressFromPodVlanSearch.and("dc", AssignIpAddressFromPodVlanSearch.entity().getDataCenterId(), Op.EQ);
|
|
AssignIpAddressFromPodVlanSearch.and("allocated", AssignIpAddressFromPodVlanSearch.entity().getAllocatedTime(), Op.NULL);
|
|
SearchBuilder<VlanVO> podVlanSearch = _vlanDao.createSearchBuilder();
|
|
podVlanSearch.and("type", podVlanSearch.entity().getVlanType(), Op.EQ);
|
|
podVlanSearch.and("networkId", podVlanSearch.entity().getNetworkId(), Op.EQ);
|
|
SearchBuilder<PodVlanMapVO> podVlanMapSB = _podVlanMapDao.createSearchBuilder();
|
|
podVlanMapSB.and("podId", podVlanMapSB.entity().getPodId(), Op.EQ);
|
|
AssignIpAddressFromPodVlanSearch.join("podVlanMapSB", podVlanMapSB, podVlanMapSB.entity().getVlanDbId(), AssignIpAddressFromPodVlanSearch.entity().getVlanId(), JoinType.INNER);
|
|
AssignIpAddressFromPodVlanSearch.join("vlan", podVlanSearch, podVlanSearch.entity().getId(), AssignIpAddressFromPodVlanSearch.entity().getVlanId(), JoinType.INNER);
|
|
AssignIpAddressFromPodVlanSearch.done();
|
|
|
|
IpAddressSearch = _ipAddressDao.createSearchBuilder();
|
|
IpAddressSearch.and("accountId", IpAddressSearch.entity().getAllocatedToAccountId(), Op.EQ);
|
|
IpAddressSearch.and("dataCenterId", IpAddressSearch.entity().getDataCenterId(), Op.EQ);
|
|
SearchBuilder<VlanVO> virtualNetworkVlanSB = _vlanDao.createSearchBuilder();
|
|
virtualNetworkVlanSB.and("vlanType", virtualNetworkVlanSB.entity().getVlanType(), Op.EQ);
|
|
IpAddressSearch.join("virtualNetworkVlanSB", virtualNetworkVlanSB, IpAddressSearch.entity().getVlanId(), virtualNetworkVlanSB.entity().getId(), JoinBuilder.JoinType.INNER);
|
|
IpAddressSearch.done();
|
|
|
|
NicForTrafficTypeSearch = _nicDao.createSearchBuilder();
|
|
SearchBuilder<NetworkVO> networkSearch = _networksDao.createSearchBuilder();
|
|
NicForTrafficTypeSearch.join("network", networkSearch, networkSearch.entity().getId(), NicForTrafficTypeSearch.entity().getNetworkId(), JoinType.INNER);
|
|
NicForTrafficTypeSearch.and("instance", NicForTrafficTypeSearch.entity().getInstanceId(), Op.EQ);
|
|
networkSearch.and("traffictype", networkSearch.entity().getTrafficType(), Op.EQ);
|
|
NicForTrafficTypeSearch.done();
|
|
|
|
_executor = Executors.newScheduledThreadPool(1, new NamedThreadFactory("Network-Scavenger"));
|
|
|
|
s_logger.info("Network Manager is configured.");
|
|
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public String getName() {
|
|
return _name;
|
|
}
|
|
|
|
@Override
|
|
public boolean start() {
|
|
_executor.scheduleWithFixedDelay(new NetworkGarbageCollector(), _networkGcInterval, _networkGcInterval, TimeUnit.SECONDS);
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public boolean stop() {
|
|
return true;
|
|
}
|
|
|
|
protected NetworkManagerImpl() {
|
|
}
|
|
|
|
@Override
|
|
public List<IPAddressVO> listPublicIpAddressesInVirtualNetwork(long accountId, long dcId, Boolean sourceNat) {
|
|
SearchCriteria<IPAddressVO> sc = IpAddressSearch.create();
|
|
sc.setParameters("accountId", accountId);
|
|
sc.setParameters("dataCenterId", dcId);
|
|
if (sourceNat != null) {
|
|
sc.addAnd("sourceNat", SearchCriteria.Op.EQ, sourceNat);
|
|
}
|
|
sc.setJoinParameters("virtualNetworkVlanSB", "vlanType", VlanType.VirtualNetwork);
|
|
|
|
return _ipAddressDao.search(sc, null);
|
|
}
|
|
|
|
@Override
|
|
public List<NetworkVO> setupNetwork(Account owner, NetworkOfferingVO offering, DeploymentPlan plan, String name, String displayText, boolean isShared, boolean isDefault) throws ConcurrentOperationException {
|
|
return setupNetwork(owner, offering, null, plan, name, displayText, isShared, isDefault);
|
|
}
|
|
|
|
@Override
|
|
@DB
|
|
public List<NetworkVO> setupNetwork(Account owner, NetworkOfferingVO offering, Network predefined, DeploymentPlan plan, String name, String displayText, boolean isShared, boolean isDefault) throws ConcurrentOperationException {
|
|
Transaction.currentTxn();
|
|
Account locked = _accountDao.acquireInLockTable(owner.getId());
|
|
if (locked == null) {
|
|
throw new ConcurrentOperationException("Unable to acquire lock on " + owner);
|
|
}
|
|
try {
|
|
|
|
if (predefined == null || (predefined.getBroadcastUri() == null && predefined.getBroadcastDomainType() != BroadcastDomainType.Vlan)) {
|
|
List<NetworkVO> configs = _networksDao.listBy(owner.getId(), offering.getId(), plan.getDataCenterId());
|
|
if (configs.size() > 0) {
|
|
if (s_logger.isDebugEnabled()) {
|
|
s_logger.debug("Found existing network configuration for offering " + offering + ": " + configs.get(0));
|
|
}
|
|
return configs;
|
|
}
|
|
}
|
|
|
|
List<NetworkVO> 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) {
|
|
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, isDefault);
|
|
configs.add(_networksDao.persist(vo, vo.getGuestType() != null));
|
|
}
|
|
|
|
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());
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public List<NetworkOfferingVO> getSystemAccountNetworkOfferings(String... offeringNames) {
|
|
List<NetworkOfferingVO> offerings = new ArrayList<NetworkOfferingVO>(offeringNames.length);
|
|
for (String offeringName : offeringNames) {
|
|
NetworkOfferingVO network = _systemNetworks.get(offeringName);
|
|
if (network == null) {
|
|
throw new CloudRuntimeException("Unable to find system network profile for " + offeringName);
|
|
}
|
|
offerings.add(network);
|
|
}
|
|
return offerings;
|
|
}
|
|
|
|
@Override
|
|
@DB
|
|
public void allocate(VirtualMachineProfile<? extends VMInstanceVO> vm, List<Pair<NetworkVO, NicProfile>> networks) throws InsufficientCapacityException, ConcurrentOperationException {
|
|
Transaction txn = Transaction.currentTxn();
|
|
txn.start();
|
|
|
|
int deviceId = 0;
|
|
|
|
boolean[] deviceIds = new boolean[networks.size()];
|
|
Arrays.fill(deviceIds, false);
|
|
|
|
List<NicVO> nics = new ArrayList<NicVO>(networks.size());
|
|
NicVO defaultNic = null;
|
|
|
|
for (Pair<NetworkVO, NicProfile> network : networks) {
|
|
NetworkVO config = network.first();
|
|
NetworkGuru concierge = _networkGurus.get(config.getGuruName());
|
|
NicProfile requested = network.second();
|
|
if (requested != null && requested.getMode() == null) {
|
|
requested.setMode(config.getMode());
|
|
}
|
|
NicProfile profile = concierge.allocate(config, requested, vm);
|
|
|
|
if (vm != null && vm.getVirtualMachine().getType() == Type.User && config.isDefault()) {
|
|
profile.setDefaultNic(true);
|
|
}
|
|
|
|
if (profile == null) {
|
|
continue;
|
|
}
|
|
NicVO vo = new NicVO(concierge.getName(), vm.getId(), config.getId());
|
|
|
|
while (deviceIds[deviceId] && deviceId < deviceIds.length) {
|
|
deviceId++;
|
|
}
|
|
|
|
deviceId = applyProfileToNic(vo, profile, deviceId);
|
|
|
|
vo = _nicDao.persist(vo);
|
|
|
|
if (vo.isDefaultNic()) {
|
|
if (defaultNic != null) {
|
|
throw new IllegalArgumentException("You cannot specify two nics as default nics: nic 1 = " + defaultNic + "; nic 2 = " + vo);
|
|
}
|
|
defaultNic = vo;
|
|
}
|
|
|
|
int devId = vo.getDeviceId();
|
|
if (devId > deviceIds.length) {
|
|
throw new IllegalArgumentException("Device id for nic is too large: " + vo);
|
|
}
|
|
if (deviceIds[devId]) {
|
|
throw new IllegalArgumentException("Conflicting device id for two different nics: " + devId);
|
|
}
|
|
|
|
deviceIds[devId] = true;
|
|
nics.add(vo);
|
|
|
|
NetworkOffering no = _configMgr.getNetworkOffering(config.getNetworkOfferingId());
|
|
Integer networkRate = _configMgr.getNetworkRate(no.getId());
|
|
vm.addNic(new NicProfile(vo, network.first(), vo.getBroadcastUri(), vo.getIsolationUri(), networkRate));
|
|
}
|
|
|
|
if (nics.size() == 1) {
|
|
nics.get(0).setDefaultNic(true);
|
|
}
|
|
|
|
txn.commit();
|
|
}
|
|
|
|
protected Integer applyProfileToNic(NicVO vo, NicProfile profile, Integer deviceId) {
|
|
if (profile.getDeviceId() != null) {
|
|
vo.setDeviceId(profile.getDeviceId());
|
|
} else if (deviceId != null) {
|
|
vo.setDeviceId(deviceId++);
|
|
}
|
|
|
|
vo.setReservationStrategy(profile.getReservationStrategy());
|
|
|
|
vo.setDefaultNic(profile.isDefaultNic());
|
|
|
|
if (profile.getIp4Address() != null) {
|
|
vo.setIp4Address(profile.getIp4Address());
|
|
vo.setAddressFormat(AddressFormat.Ip4);
|
|
}
|
|
|
|
if (profile.getMacAddress() != null) {
|
|
vo.setMacAddress(profile.getMacAddress());
|
|
}
|
|
|
|
vo.setMode(profile.getMode());
|
|
vo.setNetmask(profile.getNetmask());
|
|
vo.setGateway(profile.getGateway());
|
|
|
|
if (profile.getBroadCastUri() != null) {
|
|
vo.setBroadcastUri(profile.getBroadCastUri());
|
|
}
|
|
|
|
if (profile.getIsolationUri() != null) {
|
|
vo.setIsolationUri(profile.getIsolationUri());
|
|
}
|
|
|
|
vo.setState(Nic.State.Allocated);
|
|
return deviceId;
|
|
}
|
|
|
|
protected NicTO toNicTO(NicVO nic, NicProfile profile, NetworkVO config) {
|
|
NicTO to = new NicTO();
|
|
to.setDeviceId(nic.getDeviceId());
|
|
to.setBroadcastType(config.getBroadcastDomainType());
|
|
to.setType(config.getTrafficType());
|
|
to.setIp(nic.getIp4Address());
|
|
to.setNetmask(nic.getNetmask());
|
|
to.setMac(nic.getMacAddress());
|
|
to.setDns1(profile.getDns1());
|
|
to.setDns2(profile.getDns2());
|
|
if (nic.getGateway() != null) {
|
|
to.setGateway(nic.getGateway());
|
|
} else {
|
|
to.setGateway(config.getGateway());
|
|
}
|
|
to.setDefaultNic(nic.isDefaultNic());
|
|
to.setBroadcastUri(nic.getBroadcastUri());
|
|
to.setIsolationuri(nic.getIsolationUri());
|
|
if (profile != null) {
|
|
to.setDns1(profile.getDns1());
|
|
to.setDns2(profile.getDns2());
|
|
}
|
|
|
|
Integer networkRate = _configMgr.getNetworkRate(config.getNetworkOfferingId());
|
|
to.setNetworkRateMbps(networkRate);
|
|
|
|
return to;
|
|
}
|
|
|
|
@Override
|
|
@DB
|
|
public Pair<NetworkGuru, NetworkVO> implementNetwork(long networkId, DeployDestination dest, ReservationContext context) throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException {
|
|
Transaction.currentTxn();
|
|
Pair<NetworkGuru, NetworkVO> implemented = new Pair<NetworkGuru, NetworkVO>(null, null);
|
|
|
|
NetworkVO network = _networksDao.acquireInLockTable(networkId);
|
|
if (network == null) {
|
|
throw new ConcurrentOperationException("Unable to acquire network configuration: " + networkId);
|
|
}
|
|
|
|
try {
|
|
NetworkGuru guru = _networkGurus.get(network.getGuruName());
|
|
Network.State state = network.getState();
|
|
if (state == Network.State.Implemented || state == Network.State.Setup || state == Network.State.Implementing) {
|
|
implemented.set(guru, network);
|
|
return implemented;
|
|
}
|
|
|
|
if (s_logger.isDebugEnabled()) {
|
|
s_logger.debug("Asking " + guru + " to implement " + network);
|
|
}
|
|
|
|
NetworkOfferingVO offering = _networkOfferingDao.findById(network.getNetworkOfferingId());
|
|
network.setReservationId(context.getReservationId());
|
|
network.setState(Network.State.Implementing);
|
|
|
|
_networksDao.update(networkId, network);
|
|
|
|
Network result = guru.implement(network, offering, dest, context);
|
|
network.setCidr(result.getCidr());
|
|
network.setBroadcastUri(result.getBroadcastUri());
|
|
network.setGateway(result.getGateway());
|
|
network.setMode(result.getMode());
|
|
_networksDao.update(networkId, network);
|
|
|
|
for (NetworkElement element : _networkElements) {
|
|
if (s_logger.isDebugEnabled()) {
|
|
s_logger.debug("Asking " + element.getName() + " to implmenet " + network);
|
|
}
|
|
element.implement(network, offering, dest, context);
|
|
}
|
|
|
|
network.setState(Network.State.Implemented);
|
|
_networksDao.update(network.getId(), network);
|
|
implemented.set(guru, network);
|
|
return implemented;
|
|
} finally {
|
|
if (implemented.first() == null) {
|
|
s_logger.debug("Cleaning up because we're unable to implement network " + network);
|
|
network.setState(Network.State.Shutdown);
|
|
_networksDao.update(networkId, network);
|
|
shutdownNetwork(networkId);
|
|
}
|
|
_networksDao.releaseFromLockTable(networkId);
|
|
}
|
|
}
|
|
|
|
@DB
|
|
protected void updateNic(NicVO nic, long networkId, int count) {
|
|
Transaction txn = Transaction.currentTxn();
|
|
txn.start();
|
|
_nicDao.update(nic.getId(), nic);
|
|
_networksDao.changeActiveNicsBy(networkId, count);
|
|
txn.commit();
|
|
}
|
|
|
|
@Override
|
|
public void prepare(VirtualMachineProfile<? extends VMInstanceVO> vmProfile, DeployDestination dest, ReservationContext context) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException {
|
|
List<NicVO> nics = _nicDao.listBy(vmProfile.getId());
|
|
for (NicVO nic : nics) {
|
|
Pair<NetworkGuru, NetworkVO> implemented = implementNetwork(nic.getNetworkId(), dest, context);
|
|
NetworkGuru concierge = implemented.first();
|
|
NetworkVO network = implemented.second();
|
|
NetworkOffering no = _configMgr.getNetworkOffering(network.getNetworkOfferingId());
|
|
Integer networkRate = _configMgr.getNetworkRate(no.getId());
|
|
NicProfile profile = null;
|
|
if (nic.getReservationStrategy() == Nic.ReservationStrategy.Start) {
|
|
nic.setState(Nic.State.Reserving);
|
|
nic.setReservationId(context.getReservationId());
|
|
_nicDao.update(nic.getId(), nic);
|
|
URI broadcastUri = nic.getBroadcastUri();
|
|
if (broadcastUri == null) {
|
|
broadcastUri = network.getBroadcastUri();
|
|
}
|
|
|
|
URI isolationUri = nic.getIsolationUri();
|
|
|
|
profile = new NicProfile(nic, network, broadcastUri, isolationUri, networkRate);
|
|
concierge.reserve(profile, network, vmProfile, dest, context);
|
|
nic.setIp4Address(profile.getIp4Address());
|
|
nic.setIp6Address(profile.getIp6Address());
|
|
nic.setMacAddress(profile.getMacAddress());
|
|
nic.setIsolationUri(profile.getIsolationUri());
|
|
nic.setBroadcastUri(profile.getBroadCastUri());
|
|
nic.setReserver(concierge.getName());
|
|
nic.setState(Nic.State.Reserved);
|
|
nic.setNetmask(profile.getNetmask());
|
|
nic.setGateway(profile.getGateway());
|
|
nic.setAddressFormat(profile.getFormat());
|
|
updateNic(nic, network.getId(), 1);
|
|
} else {
|
|
profile = new NicProfile(nic, network, nic.getBroadcastUri(), nic.getIsolationUri(), networkRate);
|
|
nic.setState(Nic.State.Reserved);
|
|
updateNic(nic, network.getId(), 1);
|
|
}
|
|
|
|
for (NetworkElement element : _networkElements) {
|
|
if (s_logger.isDebugEnabled()) {
|
|
s_logger.debug("Asking " + element.getName() + " to prepare for " + nic);
|
|
}
|
|
element.prepare(network, profile, vmProfile, dest, context);
|
|
}
|
|
concierge.updateNicProfile(profile, network);
|
|
vmProfile.addNic(profile);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public <T extends VMInstanceVO> void prepareNicForMigration(VirtualMachineProfile<T> vm, DeployDestination dest) {
|
|
List<NicVO> nics = _nicDao.listBy(vm.getId());
|
|
for (NicVO nic : nics) {
|
|
NetworkVO network = _networksDao.findById(nic.getNetworkId());
|
|
NetworkOffering no = _configMgr.getNetworkOffering(network.getNetworkOfferingId());
|
|
Integer networkRate = _configMgr.getNetworkRate(no.getId());
|
|
|
|
NetworkGuru concierge = _networkGurus.get(network.getGuruName());
|
|
NicProfile profile = new NicProfile(nic, network, nic.getBroadcastUri(), nic.getIsolationUri(), networkRate);
|
|
concierge.updateNicProfile(profile, network);
|
|
vm.addNic(profile);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void release(VirtualMachineProfile<? extends VMInstanceVO> vmProfile, boolean forced) {
|
|
List<NicVO> nics = _nicDao.listBy(vmProfile.getId());
|
|
for (NicVO nic : nics) {
|
|
NetworkVO network = _networksDao.findById(nic.getNetworkId());
|
|
if (nic.getState() == Nic.State.Reserved || nic.getState() == Nic.State.Reserving) {
|
|
Nic.State originalState = nic.getState();
|
|
if (nic.getReservationStrategy() == Nic.ReservationStrategy.Start) {
|
|
NetworkGuru concierge = _networkGurus.get(network.getGuruName());
|
|
nic.setState(Nic.State.Releasing);
|
|
_nicDao.update(nic.getId(), nic);
|
|
NicProfile profile = new NicProfile(nic, network, null, null, null);
|
|
if (concierge.release(profile, vmProfile, nic.getReservationId())) {
|
|
nic.setState(Nic.State.Allocated);
|
|
if (originalState == Nic.State.Reserved) {
|
|
updateNic(nic, network.getId(), -1);
|
|
} else {
|
|
_nicDao.update(nic.getId(), nic);
|
|
}
|
|
}
|
|
} else {
|
|
nic.setState(Nic.State.Allocated);
|
|
updateNic(nic, network.getId(), -1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public List<? extends Nic> getNics(VirtualMachine vm) {
|
|
return _nicDao.listBy(vm.getId());
|
|
}
|
|
|
|
private Account findAccountByIpAddress(Ip ipAddress) {
|
|
IPAddressVO address = _ipAddressDao.findById(ipAddress);
|
|
if ((address != null) && (address.getAllocatedToAccountId() != null)) {
|
|
return _accountMgr.getActiveAccount(address.getAllocatedToAccountId());
|
|
}
|
|
return null;
|
|
}
|
|
|
|
|
|
@Override
|
|
public List<NicProfile> getNicProfiles(VirtualMachine vm) {
|
|
List<NicVO> nics = _nicDao.listBy(vm.getId());
|
|
List<NicProfile> profiles = new ArrayList<NicProfile>();
|
|
|
|
if (nics != null) {
|
|
for (Nic nic : nics) {
|
|
NetworkVO network = _networksDao.findById(nic.getNetworkId());
|
|
NetworkOffering no = _configMgr.getNetworkOffering(network.getNetworkOfferingId());
|
|
Integer networkRate = _configMgr.getNetworkRate(no.getId());
|
|
|
|
NetworkGuru concierge = _networkGurus.get(network.getGuruName());
|
|
NicProfile profile = new NicProfile(nic, network, nic.getBroadcastUri(), nic.getIsolationUri(), networkRate);
|
|
concierge.updateNicProfile(profile, network);
|
|
profiles.add(profile);
|
|
}
|
|
}
|
|
return profiles;
|
|
}
|
|
|
|
@Override
|
|
@DB
|
|
public boolean disassociateIpAddress(DisassociateIPAddrCmd cmd) throws PermissionDeniedException, IllegalArgumentException {
|
|
|
|
Long userId = UserContext.current().getCallerUserId();
|
|
Account caller = UserContext.current().getCaller();
|
|
Ip ipAddress = cmd.getIpAddress();
|
|
|
|
// Verify input parameters
|
|
Account accountByIp = findAccountByIpAddress(ipAddress);
|
|
if (accountByIp == null) {
|
|
throw new InvalidParameterValueException("Unable to find account owner for ip " + ipAddress);
|
|
}
|
|
|
|
Long accountId = accountByIp.getId();
|
|
if (!_accountMgr.isAdmin(caller.getType())) {
|
|
if (caller.getId() != accountId.longValue()) {
|
|
throw new PermissionDeniedException("account " + caller.getAccountName() + " doesn't own ip address " + ipAddress);
|
|
}
|
|
} else {
|
|
Domain domain = _domainDao.findById(accountByIp.getDomainId());
|
|
_accountMgr.checkAccess(caller, domain);
|
|
}
|
|
|
|
try {
|
|
IPAddressVO ipVO = _ipAddressDao.findById(ipAddress);
|
|
if (ipVO == null) {
|
|
return false;
|
|
}
|
|
|
|
if (ipVO.getAllocatedTime() == null) {
|
|
return true;
|
|
}
|
|
|
|
Account account = _accountMgr.getAccount(accountId);
|
|
if (account == null) {
|
|
return false;
|
|
}
|
|
|
|
if ((ipVO.getAllocatedToAccountId() == null) || (ipVO.getAllocatedToAccountId().longValue() != accountId)) {
|
|
// FIXME: is the user visible in the admin account's domain????
|
|
if (!BaseCmd.isAdmin(account.getType())) {
|
|
if (s_logger.isDebugEnabled()) {
|
|
s_logger.debug("permission denied disassociating IP address " + ipAddress + "; acct: " + accountId + "; ip (acct / dc / dom / alloc): " + ipVO.getAllocatedToAccountId() + " / " + ipVO.getDataCenterId() + " / "
|
|
+ ipVO.getAllocatedInDomainId() + " / " + ipVO.getAllocatedTime());
|
|
}
|
|
throw new PermissionDeniedException("User/account does not own supplied address");
|
|
}
|
|
}
|
|
|
|
if (ipVO.getAllocatedTime() == null) {
|
|
return true;
|
|
}
|
|
|
|
if (ipVO.isSourceNat()) {
|
|
throw new IllegalArgumentException("ip address is used for source nat purposes and can not be disassociated.");
|
|
}
|
|
|
|
VlanVO vlan = _vlanDao.findById(ipVO.getVlanId());
|
|
if (!vlan.getVlanType().equals(VlanType.VirtualNetwork)) {
|
|
throw new IllegalArgumentException("only ip addresses that belong to a virtual network may be disassociated.");
|
|
}
|
|
|
|
// Check for account wide pool. It will have an entry for account_vlan_map.
|
|
if (_accountVlanMapDao.findAccountVlanMap(accountId, ipVO.getVlanId()) != null) {
|
|
throw new PermissionDeniedException(ipAddress + " belongs to Account wide IP pool and cannot be disassociated");
|
|
}
|
|
|
|
return releasePublicIpAddress(ipAddress, accountId, userId);
|
|
|
|
} catch (PermissionDeniedException pde) {
|
|
throw pde;
|
|
} catch (IllegalArgumentException iae) {
|
|
throw iae;
|
|
} catch (Throwable t) {
|
|
s_logger.error("Disassociate IP address threw an exception.", t);
|
|
throw new IllegalArgumentException("Disassociate IP address threw an exception");
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public List<AccountVO> getAccountsUsingNetwork(long networkId) {
|
|
SearchCriteria<AccountVO> sc = AccountsUsingNetworkSearch.create();
|
|
sc.setJoinParameters("nc", "config", networkId);
|
|
return _accountDao.search(sc, null);
|
|
}
|
|
|
|
@Override
|
|
public AccountVO getNetworkOwner(long networkId) {
|
|
SearchCriteria<AccountVO> sc = AccountsUsingNetworkSearch.create();
|
|
sc.setJoinParameters("nc", "config", networkId);
|
|
sc.setJoinParameters("nc", "owner", true);
|
|
List<AccountVO> accounts = _accountDao.search(sc, null);
|
|
return accounts.size() != 0 ? accounts.get(0) : null;
|
|
}
|
|
|
|
@Override
|
|
public List<NetworkVO> getNetworksforOffering(long offeringId, long dataCenterId, long accountId) {
|
|
return _networksDao.getNetworksForOffering(offeringId, dataCenterId, accountId);
|
|
}
|
|
|
|
@Override
|
|
public List<NetworkOfferingVO> listNetworkOfferings() {
|
|
return _networkOfferingDao.listNonSystemNetworkOfferings();
|
|
}
|
|
|
|
@Override
|
|
public String getNextAvailableMacAddressInNetwork(long networkId) throws InsufficientAddressCapacityException {
|
|
String mac = _networksDao.getNextAvailableMacAddress(networkId);
|
|
if (mac == null) {
|
|
throw new InsufficientAddressCapacityException("Unable to create another mac address", Network.class, networkId);
|
|
}
|
|
|
|
return mac;
|
|
}
|
|
|
|
@Override
|
|
@DB
|
|
public Network getNetwork(long id) {
|
|
return _networksDao.findById(id);
|
|
}
|
|
|
|
@Override
|
|
public List<? extends RemoteAccessVpnElement> getRemoteAccessVpnElements() {
|
|
List<RemoteAccessVpnElement> elements = new ArrayList<RemoteAccessVpnElement>();
|
|
for (NetworkElement element : _networkElements) {
|
|
if (element instanceof RemoteAccessVpnElement) {
|
|
elements.add((RemoteAccessVpnElement) element);
|
|
}
|
|
}
|
|
|
|
return elements;
|
|
}
|
|
|
|
@Override
|
|
public void cleanupNics(VirtualMachineProfile<? extends VMInstanceVO> vm) {
|
|
List<NicVO> nics = _nicDao.listBy(vm.getId());
|
|
for (NicVO nic : nics) {
|
|
nic.setState(Nic.State.Deallocating);
|
|
_nicDao.update(nic.getId(), nic);
|
|
NetworkVO network = _networksDao.findById(nic.getNetworkId());
|
|
NicProfile profile = new NicProfile(nic, network, null, null, null);
|
|
NetworkGuru guru = _networkGurus.get(network.getGuruName());
|
|
guru.deallocate(network, profile, vm);
|
|
_nicDao.remove(nic.getId());
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void expungeNics(VirtualMachineProfile<? extends VMInstanceVO> vm) {
|
|
List<NicVO> nics = _nicDao.listIncludingRemovedBy(vm.getId());
|
|
for (NicVO nic : nics) {
|
|
_nicDao.expunge(nic.getId());
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public Network createNetwork(CreateNetworkCmd cmd) throws InvalidParameterValueException, PermissionDeniedException {
|
|
Long networkOfferingId = cmd.getNetworkOfferingId();
|
|
Long zoneId = cmd.getZoneId();
|
|
String gateway = cmd.getGateway();
|
|
String startIP = cmd.getStartIp();
|
|
String endIP = cmd.getEndIp();
|
|
String netmask = cmd.getNetmask();
|
|
String networkDomain = cmd.getNetworkDomain();
|
|
String vlanId = cmd.getVlan();
|
|
String name = cmd.getNetworkName();
|
|
String displayText = cmd.getDisplayText();
|
|
Boolean isShared = cmd.getIsShared();
|
|
Boolean isDefault = cmd.isDefault();
|
|
|
|
//finalize owner for the network
|
|
Account ctxAccount = UserContext.current().getCaller();
|
|
String accountName = cmd.getAccountName();
|
|
Long domainId = cmd.getDomainId();
|
|
|
|
Account owner = _accountMgr.finalizeOwner(ctxAccount, accountName, domainId);
|
|
|
|
return createNetwork(networkOfferingId, name, displayText, isShared, isDefault, zoneId, gateway, startIP, endIP, netmask, vlanId, networkDomain, owner);
|
|
}
|
|
|
|
@Override @DB
|
|
public Network createNetwork(long networkOfferingId, String name, String displayText, Boolean isShared, Boolean isDefault, Long zoneId, String gateway, String startIP, String endIP, String netmask, String vlanId, String networkDomain, Account owner) throws InvalidParameterValueException, PermissionDeniedException {
|
|
Account ctxAccount = UserContext.current().getCaller();
|
|
Long userId = UserContext.current().getCallerUserId();
|
|
String cidr = null;
|
|
if (gateway != null && netmask != null) {
|
|
cidr = NetUtils.ipAndNetMaskToCidr(gateway, netmask);
|
|
}
|
|
|
|
// if end ip is not specified, default it to startIp
|
|
if (endIP == null && startIP != null) {
|
|
endIP = startIP;
|
|
}
|
|
|
|
// Check if network offering exists
|
|
NetworkOfferingVO networkOffering = _networkOfferingDao.findById(networkOfferingId);
|
|
if (networkOffering == null || networkOffering.isSystemOnly()) {
|
|
throw new InvalidParameterValueException("Unable to find network offeirng by id " + networkOfferingId);
|
|
}
|
|
|
|
// allow isDefault to be set only for Virtual network
|
|
if (networkOffering.getTrafficType() == TrafficType.Guest) {
|
|
if (isDefault != null) {
|
|
throw new InvalidParameterValueException("Can specify isDefault parameter only for Public network. ");
|
|
} else {
|
|
isDefault = true;
|
|
}
|
|
} else {
|
|
if (isDefault == null) {
|
|
isDefault = false;
|
|
}
|
|
}
|
|
|
|
// If networkDomain is not specified, take it from the global configuration
|
|
if (networkDomain == null) {
|
|
networkDomain = _networkDomain;
|
|
}
|
|
|
|
// Check if zone exists
|
|
if (zoneId == null || ((_dcDao.findById(zoneId)) == null)) {
|
|
throw new InvalidParameterValueException("Please specify a valid zone.");
|
|
}
|
|
|
|
DataCenter zone = _dcDao.findById(zoneId);
|
|
if (zone.getNetworkType() == NetworkType.Basic) {
|
|
throw new InvalidParameterValueException("Network creation is not allowed in zone with network type " + NetworkType.Basic);
|
|
}
|
|
|
|
// Don't allow to create network with vlan that already exists in the system
|
|
if (vlanId != null) {
|
|
String uri = "vlan://" + vlanId;
|
|
List<NetworkVO> networks = _networksDao.listBy(zoneId, uri);
|
|
if ((networks != null && !networks.isEmpty())) {
|
|
throw new InvalidParameterValueException("Network with vlan " + vlanId + " already exists in zone " + zoneId);
|
|
}
|
|
}
|
|
|
|
// VlanId can be specified only when network offering supports it
|
|
if (ctxAccount.getType() == Account.ACCOUNT_TYPE_NORMAL && vlanId != null && !networkOffering.getSpecifyVlan()) {
|
|
throw new InvalidParameterValueException("Can't specify vlan because network offering doesn't support it");
|
|
}
|
|
|
|
Transaction txn = Transaction.currentTxn();
|
|
txn.start();
|
|
try {
|
|
// Create network
|
|
DataCenterDeployment plan = new DataCenterDeployment(zoneId, null, null, null);
|
|
NetworkVO userNetwork = new NetworkVO();
|
|
userNetwork.setNetworkDomain(networkDomain);
|
|
|
|
// cidr should be set only when the user is admin
|
|
if (ctxAccount.getType() == Account.ACCOUNT_TYPE_ADMIN) {
|
|
if (cidr != null && gateway != null) {
|
|
userNetwork.setCidr(cidr);
|
|
userNetwork.setGateway(gateway);
|
|
if (vlanId != null) {
|
|
userNetwork.setBroadcastUri(URI.create("vlan://" + vlanId));
|
|
userNetwork.setBroadcastDomainType(BroadcastDomainType.Vlan);
|
|
if (!vlanId.equalsIgnoreCase(Vlan.UNTAGGED)) {
|
|
userNetwork.setBroadcastDomainType(BroadcastDomainType.Vlan);
|
|
} else {
|
|
userNetwork.setBroadcastDomainType(BroadcastDomainType.Native);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
List<NetworkVO> networks = setupNetwork(owner, networkOffering, userNetwork, plan, name, displayText, isShared, isDefault);
|
|
Long networkId = null;
|
|
|
|
Network network = null;
|
|
if (networks == null || networks.isEmpty()) {
|
|
txn.rollback();
|
|
throw new CloudRuntimeException("Fail to create a network");
|
|
} else {
|
|
network = networks.get(0);
|
|
networkId = networks.get(0).getId();
|
|
if (network.getGuestType() == GuestIpType.Virtual) {
|
|
s_logger.debug("Creating a source natp ip for " + network);
|
|
PublicIp ip = assignSourceNatIpAddress(owner, network, userId);
|
|
if (ip == null) {
|
|
throw new InsufficientAddressCapacityException("Unable to assign source nat ip address to owner for this network", DataCenter.class, zoneId);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Don't pass owner to create vlan when network offering is of type Direct - done to prevent accountVlanMap entry
|
|
// creation when vlan is mapped to network
|
|
if (network.getGuestType() == GuestIpType.Direct) {
|
|
owner = null;
|
|
}
|
|
|
|
if (ctxAccount.getType() == Account.ACCOUNT_TYPE_ADMIN && network.getGuestType() == GuestIpType.Direct && startIP != null && endIP != null && gateway != null) {
|
|
// Create vlan ip range
|
|
Vlan vlan = _configMgr.createVlanAndPublicIpRange(userId, zoneId, null, startIP, endIP, gateway, netmask, false, vlanId, owner, networkId);
|
|
if (vlan == null) {
|
|
txn.rollback();
|
|
throw new CloudRuntimeException("Failed to create a vlan");
|
|
}
|
|
}
|
|
txn.commit();
|
|
|
|
return networks.get(0);
|
|
} catch (Exception ex) {
|
|
s_logger.warn("Unexpected exception while creating network ", ex);
|
|
txn.rollback();
|
|
} finally {
|
|
txn.close();
|
|
}
|
|
return null;
|
|
}
|
|
|
|
@Override
|
|
public List<? extends Network> searchForNetworks(ListNetworksCmd cmd) {
|
|
Object id = cmd.getId();
|
|
Object keyword = cmd.getKeyword();
|
|
Long zoneId = cmd.getZoneId();
|
|
Account account = UserContext.current().getCaller();
|
|
Long domainId = cmd.getDomainId();
|
|
String accountName = cmd.getAccountName();
|
|
String type = cmd.getType();
|
|
String trafficType = cmd.getTrafficType();
|
|
Boolean isSystem = cmd.getIsSystem();
|
|
Boolean isShared = cmd.getIsShared();
|
|
Boolean isDefault = cmd.isDefault();
|
|
Long accountId = null;
|
|
|
|
if (isSystem == null) {
|
|
isSystem = false;
|
|
}
|
|
|
|
// Account/domainId parameters and isSystem are mutually exclusive
|
|
if (isSystem && (accountName != null || domainId != null)) {
|
|
throw new InvalidParameterValueException("System network belongs to system, account and domainId parameters can't be specified");
|
|
}
|
|
|
|
if (_accountMgr.isAdmin(account.getType())) {
|
|
if (domainId != null) {
|
|
if ((account != null) && !_domainDao.isChildDomain(account.getDomainId(), domainId)) {
|
|
throw new PermissionDeniedException("Invalid domain id (" + domainId + ") given, unable to list networks");
|
|
}
|
|
|
|
if (accountName != null) {
|
|
account = _accountMgr.getActiveAccount(accountName, domainId);
|
|
if (account == null) {
|
|
throw new InvalidParameterValueException("Unable to find account " + accountName + " in domain " + domainId);
|
|
}
|
|
accountId = account.getId();
|
|
}
|
|
} else {
|
|
accountId = account.getId();
|
|
}
|
|
} else {
|
|
accountName = account.getAccountName();
|
|
domainId = account.getDomainId();
|
|
accountId = account.getId();
|
|
}
|
|
|
|
Filter searchFilter = new Filter(NetworkVO.class, "id", false, cmd.getStartIndex(), cmd.getPageSizeVal());
|
|
SearchBuilder<NetworkVO> sb = _networksDao.createSearchBuilder();
|
|
|
|
// Don't display networks created of system network offerings
|
|
SearchBuilder<NetworkOfferingVO> networkOfferingSearch = _networkOfferingDao.createSearchBuilder();
|
|
networkOfferingSearch.and("systemOnly", networkOfferingSearch.entity().isSystemOnly(), SearchCriteria.Op.EQ);
|
|
if (isSystem) {
|
|
networkOfferingSearch.and("trafficType", networkOfferingSearch.entity().getTrafficType(), SearchCriteria.Op.EQ);
|
|
}
|
|
sb.join("networkOfferingSearch", networkOfferingSearch, sb.entity().getNetworkOfferingId(), networkOfferingSearch.entity().getId(), JoinBuilder.JoinType.INNER);
|
|
|
|
SearchBuilder<DataCenterVO> zoneSearch = _dcDao.createSearchBuilder();
|
|
zoneSearch.and("networkType", zoneSearch.entity().getNetworkType(), SearchCriteria.Op.EQ);
|
|
sb.join("zoneSearch", zoneSearch, sb.entity().getDataCenterId(), zoneSearch.entity().getId(), JoinBuilder.JoinType.INNER);
|
|
|
|
SearchCriteria<NetworkVO> sc = sb.create();
|
|
|
|
if (!isSystem) {
|
|
sc.setJoinParameters("networkOfferingSearch", "systemOnly", false);
|
|
} else {
|
|
sc.setJoinParameters("networkOfferingSearch", "systemOnly", true);
|
|
sc.setJoinParameters("zoneSearch", "networkType", NetworkType.Advanced.toString());
|
|
}
|
|
|
|
if (keyword != null) {
|
|
SearchCriteria<NetworkVO> ssc = _networksDao.createSearchCriteria();
|
|
ssc.addOr("name", SearchCriteria.Op.LIKE, "%" + keyword + "%");
|
|
sc.addAnd("name", SearchCriteria.Op.SC, ssc);
|
|
}
|
|
|
|
if (id != null) {
|
|
sc.addAnd("id", SearchCriteria.Op.EQ, id);
|
|
}
|
|
|
|
if (zoneId != null) {
|
|
sc.addAnd("dataCenterId", SearchCriteria.Op.EQ, zoneId);
|
|
}
|
|
|
|
if (type != null) {
|
|
sc.addAnd("guestType", SearchCriteria.Op.EQ, type);
|
|
}
|
|
|
|
if (!isSystem && (isShared == null || !isShared) && accountName != null && domainId != null) {
|
|
sc.addAnd("accountId", SearchCriteria.Op.EQ, accountId);
|
|
sc.addAnd("isShared", SearchCriteria.Op.EQ, false);
|
|
}
|
|
|
|
if (isShared != null) {
|
|
sc.addAnd("isShared", SearchCriteria.Op.EQ, isShared);
|
|
}
|
|
|
|
if (isDefault != null) {
|
|
sc.addAnd("isDefault", SearchCriteria.Op.EQ, isDefault);
|
|
}
|
|
|
|
if (trafficType != null) {
|
|
sc.addAnd("trafficType", SearchCriteria.Op.EQ, trafficType);
|
|
}
|
|
|
|
List<NetworkVO> networks = _networksDao.search(sc, searchFilter);
|
|
|
|
return networks;
|
|
}
|
|
|
|
@Override
|
|
@DB
|
|
public boolean deleteNetwork(long networkId) throws InvalidParameterValueException, PermissionDeniedException {
|
|
Long userId = UserContext.current().getCallerUserId();
|
|
Account caller = UserContext.current().getCaller();
|
|
|
|
// Verify network id
|
|
NetworkVO network = _networksDao.findById(networkId);
|
|
if (network == null) {
|
|
throw new InvalidParameterValueException("unable to find network " + networkId);
|
|
}
|
|
|
|
// Perform permission check
|
|
if (!_accountMgr.isAdmin(caller.getType())) {
|
|
if (network.getAccountId() != caller.getId()) {
|
|
throw new PermissionDeniedException("Account " + caller.getAccountName() + " does not own network id=" + networkId + ", permission denied");
|
|
}
|
|
} else {
|
|
Account owner = _accountMgr.getAccount(network.getAccountId());
|
|
_accountMgr.checkAccess(caller, owner);
|
|
}
|
|
|
|
return this.destroyNetwork(networkId, userId);
|
|
}
|
|
|
|
@Override
|
|
@DB
|
|
public void shutdownNetwork(long networkId) {
|
|
Transaction txn = Transaction.currentTxn();
|
|
txn.start();
|
|
NetworkVO network = _networksDao.lockRow(networkId, true);
|
|
if (network == null) {
|
|
s_logger.debug("Unable to find network with id: " + networkId);
|
|
return;
|
|
}
|
|
if (network.getState() != Network.State.Implemented && network.getState() != Network.State.Shutdown) {
|
|
s_logger.debug("Network is not implemented: " + network);
|
|
return;
|
|
}
|
|
network.setState(Network.State.Shutdown);
|
|
_networksDao.update(network.getId(), network);
|
|
txn.commit();
|
|
|
|
boolean success = true;
|
|
for (NetworkElement element : _networkElements) {
|
|
try {
|
|
if (s_logger.isDebugEnabled()) {
|
|
s_logger.debug("Sending network shutdown to " + element);
|
|
}
|
|
element.shutdown(network, null);
|
|
} catch (ResourceUnavailableException e) {
|
|
s_logger.warn("Unable to complete shutdown of the network due to element: " + element.getName(), e);
|
|
success = false;
|
|
} catch (ConcurrentOperationException e) {
|
|
s_logger.warn("Unable to complete shutdown of the network due to element: " + element.getName(), e);
|
|
success = false;
|
|
} catch (Exception e) {
|
|
s_logger.warn("Unable to complete shutdown of the network due to element: " + element.getName(), e);
|
|
success = false;
|
|
}
|
|
}
|
|
|
|
txn.start();
|
|
if (success) {
|
|
if (s_logger.isDebugEnabled()) {
|
|
s_logger.debug("Network id=" + networkId + " is shutdown successfully, cleaning up corresponding resources now.");
|
|
}
|
|
NetworkGuru guru = _networkGurus.get(network.getGuruName());
|
|
guru.destroy(network, _networkOfferingDao.findById(network.getNetworkOfferingId()));
|
|
network.setBroadcastUri(null);
|
|
network.setState(Network.State.Allocated);
|
|
_networksDao.update(network.getId(), network);
|
|
_networksDao.clearCheckForGc(networkId);
|
|
} else {
|
|
network.setState(Network.State.Implemented);
|
|
_networksDao.update(network.getId(), network);
|
|
}
|
|
txn.commit();
|
|
}
|
|
|
|
@DB
|
|
@Override
|
|
public boolean destroyNetwork(long networkId, long callerUserId) {
|
|
NetworkVO network = _networksDao.findById(networkId);
|
|
if (network == null) {
|
|
s_logger.debug("Unable to find network with id: " + networkId);
|
|
return false;
|
|
}
|
|
|
|
// Shutdown network first
|
|
shutdownNetwork(networkId);
|
|
|
|
// get updated state for the network
|
|
network = _networksDao.findById(networkId);
|
|
if (network.getState() != Network.State.Allocated && network.getState() != Network.State.Setup) {
|
|
s_logger.debug("Network is not not in the correct state to be destroyed: " + network.getState());
|
|
return false;
|
|
}
|
|
|
|
boolean success = true;
|
|
|
|
//release ip addresses associated with the network if there are any
|
|
List<IPAddressVO> ipsToRelease = _ipAddressDao.listByAssociatedNetwork(networkId);
|
|
if (ipsToRelease != null && !ipsToRelease.isEmpty()) {
|
|
for (IPAddressVO ip : ipsToRelease) {
|
|
_ipAddressDao.unassignIpAddress(ip.getAddress());
|
|
}
|
|
|
|
s_logger.debug("Ip addresses are unassigned successfully as a part of network id=" + networkId + " destroy");
|
|
}
|
|
|
|
for (NetworkElement element : _networkElements) {
|
|
try {
|
|
if (s_logger.isDebugEnabled()) {
|
|
s_logger.debug("Sending destroy to " + element);
|
|
}
|
|
element.destroy(network);
|
|
} catch (ResourceUnavailableException e) {
|
|
s_logger.warn("Unable to complete destroy of the network due to element: " + element.getName(), e);
|
|
success = false;
|
|
} catch (ConcurrentOperationException e) {
|
|
s_logger.warn("Unable to complete destroy of the network due to element: " + element.getName(), e);
|
|
success = false;
|
|
} catch (Exception e) {
|
|
s_logger.warn("Unable to complete destroy of the network due to element: " + element.getName(), e);
|
|
success = false;
|
|
}
|
|
}
|
|
|
|
if (success) {
|
|
if (s_logger.isDebugEnabled()) {
|
|
s_logger.debug("Network id=" + networkId + " is destroyed successfully, cleaning up corresponding resources now.");
|
|
}
|
|
NetworkGuru guru = _networkGurus.get(network.getGuruName());
|
|
Account owner = _accountMgr.getAccount(network.getAccountId());
|
|
|
|
Transaction txn = Transaction.currentTxn();
|
|
txn.start();
|
|
guru.trash(network, _networkOfferingDao.findById(network.getNetworkOfferingId()), owner);
|
|
|
|
if (!deleteVlansInNetwork(network.getId(), callerUserId)) {
|
|
success = false;
|
|
s_logger.warn("Failed to delete network " + network + "; was unable to cleanup corresponding ip ranges");
|
|
} else {
|
|
// commit transaction only when ips and vlans for the network are released successfully
|
|
network.setState(Network.State.Destroy);
|
|
_networksDao.update(network.getId(), network);
|
|
_networksDao.remove(network.getId());
|
|
txn.commit();
|
|
}
|
|
}
|
|
|
|
return success;
|
|
}
|
|
|
|
private boolean deleteVlansInNetwork(long networkId, long userId) {
|
|
List<VlanVO> vlans = _vlanDao.listVlansByNetworkId(networkId);
|
|
boolean result = true;
|
|
for (VlanVO vlan : vlans) {
|
|
if (!_configMgr.deleteVlanAndPublicIpRange(_accountMgr.getSystemUser().getId(), vlan.getId())) {
|
|
s_logger.warn("Failed to delete vlan " + vlan.getId() + ");");
|
|
result = false;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
@Override
|
|
public boolean applyRules(List<? extends FirewallRule> rules, boolean continueOnError) throws ResourceUnavailableException {
|
|
if (rules == null || rules.size() == 0) {
|
|
s_logger.debug("There are no rules to forward to the network elements");
|
|
return true;
|
|
}
|
|
|
|
boolean success = true;
|
|
Network network = _networksDao.findById(rules.get(0).getNetworkId());
|
|
for (NetworkElement ne : _networkElements) {
|
|
try {
|
|
boolean handled = ne.applyRules(network, rules);
|
|
s_logger.debug("Network Rules for network " + network.getId() + " were " + (handled ? "" : " not") + " handled by " + ne.getName());
|
|
} catch (ResourceUnavailableException e) {
|
|
if (!continueOnError) {
|
|
throw e;
|
|
}
|
|
s_logger.warn("Problems with " + ne.getName() + " but pushing on", e);
|
|
success = false;
|
|
}
|
|
}
|
|
|
|
return success;
|
|
}
|
|
|
|
public class NetworkGarbageCollector implements Runnable {
|
|
|
|
@Override
|
|
public void run() {
|
|
try {
|
|
List<Long> shutdownList = new ArrayList<Long>();
|
|
long currentTime = System.currentTimeMillis() >> 10;
|
|
HashMap<Long, Long> stillFree = new HashMap<Long, Long>();
|
|
|
|
List<Long> networkIds = _networksDao.findNetworksToGarbageCollect();
|
|
for (Long networkId : networkIds) {
|
|
Long time = _lastNetworkIdsToFree.remove(networkId);
|
|
if (time == null) {
|
|
if (s_logger.isDebugEnabled()) {
|
|
s_logger.debug("We found network " + networkId + " to be free for the first time. Adding it to the list: " + currentTime);
|
|
}
|
|
stillFree.put(networkId, currentTime);
|
|
} else if (time > (currentTime - _networkGcWait)) {
|
|
if (s_logger.isDebugEnabled()) {
|
|
s_logger.debug("Network " + networkId + " is still free but it's not time to shutdown yet: " + time);
|
|
}
|
|
stillFree.put(networkId, time);
|
|
} else {
|
|
shutdownList.add(networkId);
|
|
}
|
|
}
|
|
|
|
_lastNetworkIdsToFree = stillFree;
|
|
|
|
for (Long networkId : shutdownList) {
|
|
try {
|
|
shutdownNetwork(networkId);
|
|
} catch (Exception e) {
|
|
s_logger.warn("Unable to shutdown network: " + networkId);
|
|
}
|
|
}
|
|
} catch (Exception e) {
|
|
s_logger.warn("Caught exception while running network gc: ", e);
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public boolean restartNetwork(RestartNetworkCmd cmd) throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException {
|
|
// This method restarts all network elements belonging to the network
|
|
Long networkId = cmd.getNetworkId();
|
|
Network network = _networksDao.findById(networkId);
|
|
Account owner = _accountMgr.getAccount(network.getAccountId());
|
|
User caller = _accountMgr.getActiveUser(UserContext.current().getCallerUserId());
|
|
Account callerAccount = _accountMgr.getActiveAccount(caller.getAccountId());
|
|
|
|
ReservationContext context = new ReservationContextImpl(null, null, caller, owner);
|
|
|
|
_accountMgr.checkAccess(callerAccount, network);
|
|
|
|
s_logger.debug("Restarting network " + networkId + "...");
|
|
|
|
boolean success = true;
|
|
for (NetworkElement element : _networkElements) {
|
|
success = element.restart(network, context);
|
|
if (!success) {
|
|
s_logger.warn("Failed to restart network element " + element + " as a part of network restart");
|
|
return success;
|
|
}
|
|
}
|
|
|
|
s_logger.debug("Network " + networkId + " is restarted successfully.");
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public int getActiveNicsInNetwork(long networkId) {
|
|
return _networksDao.getActiveNicsIn(networkId);
|
|
}
|
|
|
|
@Override
|
|
public Map<Service, Map<Capability, String>> getZoneCapabilities(long zoneId) {
|
|
DataCenterVO dc = _dcDao.findById(zoneId);
|
|
if (dc == null) {
|
|
throw new InvalidParameterValueException("Zone id=" + zoneId + " doesn't exist in the system.");
|
|
}
|
|
|
|
// Get all service providers from the datacenter
|
|
Map<Service, String> providers = new HashMap<Service, String>();
|
|
providers.put(Service.Firewall, dc.getFirewallProvider());
|
|
providers.put(Service.Lb, dc.getLoadBalancerProvider());
|
|
providers.put(Service.Vpn, dc.getVpnProvider());
|
|
providers.put(Service.Dns, dc.getDnsProvider());
|
|
providers.put(Service.Gateway, dc.getGatewayProvider());
|
|
providers.put(Service.UserData, dc.getUserDataProvider());
|
|
providers.put(Service.Dhcp, dc.getDhcpProvider());
|
|
|
|
Map<Service, Map<Capability, String>> networkCapabilities = new HashMap<Service, Map<Capability, String>>();
|
|
|
|
for (NetworkElement element : _networkElements) {
|
|
if (providers.isEmpty()) {
|
|
break;
|
|
}
|
|
Map<Service, Map<Capability, String>> elementCapabilities = element.getCapabilities();
|
|
if (elementCapabilities != null) {
|
|
Iterator<Service> it = providers.keySet().iterator();
|
|
while (it.hasNext()) {
|
|
Service service = it.next();
|
|
String zoneProvider = providers.get(service);
|
|
if (zoneProvider != null) {
|
|
if (zoneProvider.equalsIgnoreCase(element.getProvider().getName())) {
|
|
if (elementCapabilities.containsKey(service)) {
|
|
Map<Capability, String> capabilities = elementCapabilities.get(service);
|
|
// Verify if Service support capability
|
|
if (capabilities != null) {
|
|
for (Capability capability : capabilities.keySet()) {
|
|
assert (service.containsCapability(capability)) : "Capability " + capability.getName() + " is not supported by the service " + service.getName();
|
|
}
|
|
}
|
|
networkCapabilities.put(service, capabilities);
|
|
it.remove();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return networkCapabilities;
|
|
}
|
|
|
|
@Override
|
|
public Network getSystemNetworkByZoneAndTrafficType(long zoneId, TrafficType trafficType) {
|
|
// find system public network offering
|
|
Long networkOfferingId = null;
|
|
List<NetworkOfferingVO> offerings = _networkOfferingDao.listSystemNetworkOfferings();
|
|
for (NetworkOfferingVO offering : offerings) {
|
|
if (offering.getTrafficType() == trafficType) {
|
|
networkOfferingId = offering.getId();
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (networkOfferingId == null) {
|
|
throw new InvalidParameterValueException("Unable to find system network offering with traffic type " + trafficType);
|
|
}
|
|
|
|
List<NetworkVO> networks = _networksDao.listBy(Account.ACCOUNT_ID_SYSTEM, networkOfferingId, zoneId);
|
|
if (networks == null) {
|
|
throw new InvalidParameterValueException("Unable to find network with traffic type " + trafficType + " in zone " + zoneId);
|
|
}
|
|
return networks.get(0);
|
|
}
|
|
|
|
@Override
|
|
public PublicIpAddress getPublicIpAddress(Ip ip) {
|
|
IPAddressVO addr = _ipAddressDao.findById(ip);
|
|
if (addr == null) {
|
|
return null;
|
|
}
|
|
|
|
return new PublicIp(addr, _vlanDao.findById(addr.getVlanId()), NetUtils.createSequenceBasedMacAddress(addr.getMacAddress()));
|
|
}
|
|
|
|
@Override
|
|
public List<VlanVO> listPodVlans(long podId) {
|
|
List<VlanVO> vlans = _vlanDao.listVlansForPodByType(podId, VlanType.DirectAttached);
|
|
return vlans;
|
|
}
|
|
|
|
@Override
|
|
public List<NetworkVO> listNetworksUsedByVm(long vmId, boolean isSystem) {
|
|
List<NetworkVO> networks = new ArrayList<NetworkVO>();
|
|
|
|
List<NicVO> nics = _nicDao.listBy(vmId);
|
|
if (nics != null) {
|
|
for (Nic nic : nics) {
|
|
NetworkVO network = _networksDao.findByIdIncludingRemoved(nic.getNetworkId());
|
|
NetworkOffering no = _networkOfferingDao.findByIdIncludingRemoved(network.getNetworkOfferingId());
|
|
if (no.isSystemOnly() == isSystem) {
|
|
networks.add(network);
|
|
}
|
|
}
|
|
}
|
|
|
|
return networks;
|
|
}
|
|
|
|
@Override
|
|
public Nic getNicInNetwork(long vmId, long networkId) {
|
|
return _nicDao.findByInstanceIdAndNetworkId(networkId, vmId);
|
|
}
|
|
|
|
@Override @DB
|
|
public boolean associateIpAddressListToAccount(long userId, long accountId, long zoneId, Long vlanId) throws InsufficientAddressCapacityException,
|
|
ConcurrentOperationException, ResourceUnavailableException {
|
|
|
|
Account account = _accountMgr.getActiveAccount(accountId);
|
|
if (account == null) {
|
|
s_logger.warn("Unable to find active account: " + accountId);
|
|
}
|
|
|
|
Network network = null;
|
|
long allocatedIps = 0;
|
|
|
|
//create new Virtual network for the user if it doesn't exist
|
|
List<? extends Network> networks = getVirtualNetworksOwnedByAccountInZone(account.getAccountName(), account.getDomainId(), zoneId);
|
|
if (networks.size() == 0) {
|
|
List<? extends NetworkOffering> offerings = _configMgr.listNetworkOfferings(TrafficType.Guest, false);
|
|
network = createNetwork(offerings.get(0).getId(), account.getAccountName() + "-network", account.getAccountName() + "-network", false, null, zoneId, null, null, null, null, null, null, account);
|
|
|
|
if (network == null){
|
|
s_logger.warn("Failed to create default Virtual network for the account " + accountId + "in zone " + zoneId);
|
|
return false;
|
|
} else {
|
|
//sourceNat ip is allocated as a part of networkCreate
|
|
allocatedIps++;
|
|
}
|
|
} else {
|
|
assert (networks.size() <= 1) : "Too many virtual networks. This logic should be obsolete";
|
|
network = networks.get(0);
|
|
}
|
|
|
|
//Associate ip addresses
|
|
long ipCount = _ipAddressDao.countIPs(zoneId, vlanId, false);
|
|
if (ipCount > 0) {
|
|
while (allocatedIps < ipCount) {
|
|
fetchNewPublicIp(zoneId, null, vlanId, account, VlanType.VirtualNetwork, network.getId(), false, true);
|
|
allocatedIps++;
|
|
}
|
|
|
|
if (network.getState() == Network.State.Implemented) {
|
|
s_logger.debug("Applying ip associations for vlan id=" + vlanId + " in network " + network);
|
|
return applyIpAssociations(network, false);
|
|
} else {
|
|
s_logger.trace("Network id=" + network.getId() + " is not Implemented, no need to apply ipAssociations");
|
|
return true;
|
|
}
|
|
} else {
|
|
s_logger.trace("Found 0 ips to assign in vlan id=" + vlanId);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public Nic getNicForTraffic(long vmId, TrafficType type) {
|
|
SearchCriteria<NicVO> sc = NicForTrafficTypeSearch.create();
|
|
sc.setParameters("instance", vmId);
|
|
sc.setJoinParameters("network", "traffictype", type);
|
|
|
|
List<NicVO> vos = _nicDao.search(sc, null);
|
|
assert vos.size() <= 1 : "If we have multiple networks of the same type, then this method should no longer be used.";
|
|
return vos.size() == 1 ? vos.get(0) : null;
|
|
}
|
|
|
|
@Override
|
|
public IpAddress getIp(Ip ip) {
|
|
return _ipAddressDao.findById(ip);
|
|
}
|
|
|
|
@Override
|
|
public NetworkProfile getNetworkProfile(long networkId) {
|
|
NetworkVO network = _networksDao.findById(networkId);
|
|
NetworkGuru concierge = _networkGurus.get(network.getGuruName());
|
|
NetworkProfile profile = new NetworkProfile(network, null, null);
|
|
concierge.updateNetworkProfile(profile);
|
|
|
|
return profile;
|
|
}
|
|
|
|
@Override
|
|
public Network getDefaultNetworkForVm(long vmId) {
|
|
Nic defaultNic = getDefaultNic(vmId);
|
|
if (defaultNic == null) {
|
|
return null;
|
|
} else {
|
|
return _networksDao.findById(defaultNic.getNetworkId());
|
|
}
|
|
}
|
|
|
|
|
|
@Override
|
|
public Nic getDefaultNic(long vmId) {
|
|
List<NicVO> nics = _nicDao.listBy(vmId);
|
|
Nic defaultNic = null;
|
|
if (nics != null) {
|
|
for (Nic nic: nics) {
|
|
if (nic.isDefaultNic()) {
|
|
defaultNic = nic;
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
s_logger.debug("Unable to find default network for the vm; vm doesn't have any nics");
|
|
return null;
|
|
}
|
|
|
|
if (defaultNic == null) {
|
|
s_logger.debug("Unable to find default network for the vm; vm doesn't have default nic");
|
|
}
|
|
|
|
return defaultNic;
|
|
|
|
}
|
|
|
|
@Override
|
|
public List<? extends PasswordResetElement> getPasswordResetElements() {
|
|
List<PasswordResetElement> elements = new ArrayList<PasswordResetElement>();
|
|
for (NetworkElement element : _networkElements) {
|
|
if (element instanceof PasswordResetElement) {
|
|
elements.add((PasswordResetElement) element);
|
|
}
|
|
}
|
|
return elements;
|
|
}
|
|
}
|