| /** |
| * 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.DomainVO; |
| import com.cloud.domain.dao.DomainDao; |
| import com.cloud.event.ActionEvent; |
| 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.IpAddress.State; |
| 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.network.vpn.RemoteAccessVpnService; |
| 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 |
| RemoteAccessVpnService _vpnMgr; |
| @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()); |
| |
| if (assign) { |
| markPublicIpAsAllocated(addr); |
| } else { |
| addr.setState(IpAddress.State.Allocating); |
| } |
| addr.setState(assign ? IpAddress.State.Allocated : IpAddress.State.Allocating); |
| |
| if (vlanUse != VlanType.DirectAttached) { |
| addr.setAssociatedWithNetworkId(networkId); |
| } |
| |
| _ipAddressDao.update(addr.getId(), addr); |
| |
| txn.commit(); |
| long macAddress = NetUtils.createSequenceBasedMacAddress(addr.getMacAddress()); |
| |
| return new PublicIp(addr, _vlanDao.findById(addr.getVlanId()), macAddress); |
| } |
| |
| @DB |
| protected void markPublicIpAsAllocated(IPAddressVO addr) { |
| |
| assert (addr.getState() == IpAddress.State.Allocating || addr.getState() == IpAddress.State.Free) : "Unable to transition from state " + addr.getState() + " to " + IpAddress.State.Allocated; |
| |
| Transaction txn = Transaction.currentTxn(); |
| |
| Account owner = _accountMgr.getAccount(addr.getAccountId()); |
| long isSourceNat = (addr.isSourceNat()) ? 1 : 0; |
| |
| txn.start(); |
| addr.setState(IpAddress.State.Allocated); |
| _ipAddressDao.update(addr.getId(), addr); |
| |
| //Save usage event |
| if (owner.getAccountId() != Account.ACCOUNT_ID_SYSTEM) { |
| UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_NET_IP_ASSIGN, owner.getId(), addr.getDataCenterId(), addr.getId(), addr.getAddress().toString(), isSourceNat); |
| _usageEventDao.persist(usageEvent); |
| _accountMgr.incrementResourceCount(owner.getId(), ResourceType.public_ip); |
| } |
| |
| txn.commit(); |
| } |
| |
| @Override @DB |
| public void unassignPublicIpAddress(IPAddressVO addr) { |
| Transaction txn = Transaction.currentTxn(); |
| Account owner = _accountMgr.getAccount(addr.getAccountId()); |
| long isSourceNat = (addr.isSourceNat()) ? 1 : 0; |
| |
| txn.start(); |
| |
| _ipAddressDao.unassignIpAddress(addr.getId()); |
| if (owner.getAccountId() != Account.ACCOUNT_ID_SYSTEM) { |
| UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_NET_IP_RELEASE, owner.getId(), addr.getDataCenterId(), addr.getId(), addr.getAddress().toString(), isSourceNat); |
| _usageEventDao.persist(usageEvent); |
| } |
| |
| _accountMgr.decrementResourceCount(owner.getId(), ResourceType.public_ip); |
| |
| txn.commit(); |
| } |
| |
| @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(); |
| |
| markPublicIpAsAllocated(sourceNat); |
| _ipAddressDao.update(sourceNat.getId(), sourceNat); |
| |
| |
| // Increment the number of public IPs for this accountId in the database |
| |
| } 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())); |
| } |
| |
| 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; |
| } |
| |
| @Override |
| 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.setAssociatedWithNetworkId(network.getId()); |
| markPublicIpAsAllocated(addr); |
| |
| } else if (addr.getState() == IpAddress.State.Releasing) { |
| unassignPublicIpAddress(addr); |
| } |
| } |
| } |
| |
| 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 @ActionEvent (eventType=EventTypes.EVENT_NET_IP_ASSIGN, eventDescription="allocating Ip", create=true) |
| public IpAddress allocateIP(AssociateIPAddrCmd cmd) throws ResourceAllocationException, 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; |
| |
| 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); |
| } |
| UserContext.current().setEventDetails("Ip Id: "+ip.getId()); |
| Ip ipAddress = ip.getAddress(); |
| |
| s_logger.debug("Got " + ipAddress + " to assign for account " + owner.getId() + " in zone " + network.getDataCenterId()); |
| |
| txn.commit(); |
| } finally { |
| if (accountToLock != null) { |
| _accountDao.releaseFromLockTable(ownerId); |
| s_logger.debug("Associate IP address lock released"); |
| } |
| } |
| |
| return ip; |
| } |
| |
| @Override @DB @ActionEvent (eventType=EventTypes.EVENT_NET_IP_ASSIGN, eventDescription="associating Ip", async=true) |
| public IpAddress associateIP(AssociateIPAddrCmd cmd) throws ResourceAllocationException, ResourceUnavailableException, InsufficientAddressCapacityException, ConcurrentOperationException { |
| Account caller = UserContext.current().getCaller(); |
| Account owner = null; |
| |
| IpAddress ipToAssoc = getIp(cmd.getEntityId()); |
| if (ipToAssoc != null) { |
| _accountMgr.checkAccess(caller, ipToAssoc); |
| owner = _accountMgr.getAccount(ipToAssoc.getAccountId()); |
| } else { |
| s_logger.debug("Unable to find ip address by id: " + cmd.getEntityId()); |
| return null; |
| } |
| |
| Network network = _networksDao.findById(ipToAssoc.getAssociatedWithNetworkId()); |
| |
| IPAddressVO ip = _ipAddressDao.findById(cmd.getEntityId()); |
| boolean success = false; |
| try { |
| success = applyIpAssociations(network, false); |
| if (success) { |
| s_logger.debug("Successfully associated ip address " + ip.getAddress().addr() + " for account " + owner.getId() + " in zone " + network.getDataCenterId()); |
| } else { |
| s_logger.warn("Failed to associate ip address " + ip.getAddress().addr() + " 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 (!success) { |
| if (ip != null) { |
| try { |
| s_logger.warn("Failed to associate ip address " + ip); |
| _ipAddressDao.markAsUnavailable(ip.getId()); |
| if (!applyIpAssociations(network, true)) { |
| //if fail to apply ip assciations again, unassign ip address without updating resource count and generating usage event as there is no need to keep it in the db |
| _ipAddressDao.unassignIpAddress(ip.getId()); |
| } |
| } catch (Exception e) { |
| s_logger.warn("Unable to disassociate ip address for recovery", e); |
| } |
| } |
| } |
| } |
| } |
| |
| @Override |
| public boolean releasePublicIpAddress(long addrId, long ownerId, long userId) { |
| IPAddressVO ip = _ipAddressDao.markAsUnavailable(addrId); |
| assert (ip != null) : "Unable to mark the ip address id=" + addrId + " owned by " + ownerId + " as unavailable."; |
| if (ip == null) { |
| return true; |
| } |
| |
| if (s_logger.isDebugEnabled()) { |
| s_logger.debug("Releasing ip id=" + addrId + "; sourceNat = " + ip.isSourceNat()); |
| } |
| |
| boolean success = true; |
| try { |
| if (!_rulesMgr.revokeAllRules(addrId, 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(addrId)) { |
| 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) { |
| s_logger.debug("released a public ip id=" + addrId); |
| } |
| |
| 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.getCidr() == 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; |
| } |
| } else if (predefined != null && predefined.getCidr() != null && predefined.getBroadcastUri() == null && predefined.getBroadcastUri() == null) { |
| List<NetworkVO> configs = _networksDao.listBy(owner.getId(), offering.getId(), plan.getDataCenterId(), predefined.getCidr()); |
| 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 void applyProfileToNicForRelease(NicVO vo, NicProfile profile) { |
| vo.setGateway(profile.getGateway()); |
| vo.setAddressFormat(profile.getFormat()); |
| vo.setIp4Address(profile.getIp4Address()); |
| vo.setIp6Address(profile.getIp6Address()); |
| vo.setMacAddress(profile.getMacAddress()); |
| vo.setReservationStrategy(profile.getReservationStrategy()); |
| vo.setBroadcastUri(profile.getBroadCastUri()); |
| vo.setIsolationUri(profile.getIsolationUri()); |
| vo.setNetmask(profile.getNetmask()); |
| } |
| |
| 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())) { |
| applyProfileToNicForRelease(nic, profile); |
| 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(Long ipAddressId) { |
| IPAddressVO address = _ipAddressDao.findById(ipAddressId); |
| 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 @ActionEvent (eventType=EventTypes.EVENT_NET_IP_RELEASE, eventDescription="disassociating Ip") |
| public boolean disassociateIpAddress(DisassociateIPAddrCmd cmd) throws PermissionDeniedException, IllegalArgumentException { |
| |
| Long userId = UserContext.current().getCallerUserId(); |
| Account caller = UserContext.current().getCaller(); |
| Long ipAddressId = cmd.getIpAddressId(); |
| |
| // Verify input parameters |
| Account accountByIp = findAccountByIpAddress(ipAddressId); |
| if (accountByIp == null) { |
| throw new InvalidParameterValueException("Unable to find account owner for ip " + ipAddressId); |
| } |
| |
| 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 id=" + ipAddressId); |
| } |
| } else { |
| Domain domain = _domainDao.findById(accountByIp.getDomainId()); |
| _accountMgr.checkAccess(caller, domain); |
| } |
| |
| try { |
| IPAddressVO ipVO = _ipAddressDao.findById(ipAddressId); |
| 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 id=" + ipAddressId + "; 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("Ip address id=" + ipAddressId + " belongs to Account wide IP pool and cannot be disassociated"); |
| } |
| |
| return releasePublicIpAddress(ipAddressId, 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 @DB @ActionEvent (eventType=EventTypes.EVENT_NETWORK_CREATE, eventDescription="creating network") |
| public Network createNetwork(CreateNetworkCmd cmd) throws InsufficientCapacityException, ConcurrentOperationException { |
| 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(); |
| Long userId = UserContext.current().getCallerUserId(); |
| |
| Transaction txn = Transaction.currentTxn(); |
| |
| // 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); |
| // 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 = "cs"+Long.toHexString(owner.getId())+_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); |
| } |
| |
| String cidr = null; |
| if (gateway != null && netmask != null) { |
| cidr = NetUtils.ipAndNetMaskToCidr(gateway, netmask); |
| } |
| |
| // 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"); |
| } |
| |
| txn.start(); |
| Network network = createNetwork(networkOfferingId, name, displayText, isShared, isDefault, zoneId, gateway, cidr, vlanId, networkDomain, owner); |
| |
| // 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 |
| _configMgr.createVlanAndPublicIpRange(userId, zoneId, null, startIP, endIP, gateway, netmask, false, vlanId, owner, network.getId()); |
| } |
| |
| txn.commit(); |
| |
| return network; |
| } |
| |
| @Override @DB |
| public Network createNetwork(long networkOfferingId, String name, String displayText, Boolean isShared, Boolean isDefault, Long zoneId, String gateway, String cidr, String vlanId, String networkDomain, Account owner) |
| throws ConcurrentOperationException, InsufficientCapacityException { |
| Account ctxAccount = UserContext.current().getCaller(); |
| Long userId = UserContext.current().getCallerUserId(); |
| |
| NetworkOfferingVO networkOffering = _networkOfferingDao.findById(networkOfferingId); |
| DataCenterVO zone = _dcDao.findById(zoneId); |
| |
| Transaction txn = Transaction.currentTxn(); |
| txn.start(); |
| // 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); |
| |
| Network network = null; |
| if (networks == null || networks.isEmpty()) { |
| throw new CloudRuntimeException("Fail to create a network"); |
| } else { |
| if (networks.size() > 0 && networks.get(0).getGuestType() == GuestIpType.Virtual && networks.get(0).getTrafficType() == TrafficType.Guest) { |
| Network defaultGuestNetwork = networks.get(0); |
| for (Network nw : networks) { |
| if (nw.getCidr() != null && nw.getCidr().equals(zone.getGuestNetworkCidr())) { |
| defaultGuestNetwork = nw; |
| } |
| } |
| network = defaultGuestNetwork; |
| } else { |
| network = networks.get(0); |
| } |
| |
| 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); |
| } |
| } |
| } |
| |
| txn.commit(); |
| UserContext.current().setEventDetails("Network Id: "+ network.getId()); |
| return network; |
| } |
| |
| @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; |
| String path = 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(); |
| } |
| |
| if (account.getType() == Account.ACCOUNT_TYPE_DOMAIN_ADMIN) { |
| DomainVO domain = _domainDao.findById(account.getDomainId()); |
| if (domain != null) { |
| path = domain.getPath(); |
| } |
| } |
| } 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); |
| |
| |
| if (path != null) { |
| //for domain admin we should show only subdomains information |
| SearchBuilder<DomainVO> domainSearch = _domainDao.createSearchBuilder(); |
| domainSearch.and("path", domainSearch.entity().getPath(), SearchCriteria.Op.LIKE); |
| sb.join("domainSearch", domainSearch, sb.entity().getDomainId(), domainSearch.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); |
| } |
| |
| if (!isSystem && path != null && (isShared == null || !isShared)) { |
| sc.setJoinParameters("domainSearch", "path", path + "%"); |
| } |
| |
| List<NetworkVO> networks = _networksDao.search(sc, searchFilter); |
| |
| return networks; |
| } |
| |
| @Override |
| @ActionEvent (eventType=EventTypes.EVENT_NETWORK_DELETE, eventDescription="deleting network") |
| public boolean deleteNetwork(long networkId) throws InvalidParameterValueException, PermissionDeniedException { |
| //Don't allow to delete network via api call when it has vms assigned to it |
| int nicCount = getActiveNicsInNetwork(networkId); |
| if (nicCount > 0) { |
| throw new InvalidParameterValueException("Unable to remove the network id=" + networkId + " as it has active Nics."); |
| } |
| |
| 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 deleteNetworkInternal(networkId, userId); |
| } |
| |
| @Override |
| @DB |
| public boolean deleteNetworkInternal(long networkId, long userId) throws InvalidParameterValueException, PermissionDeniedException { |
| 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 - for Virtual case |
| List<IPAddressVO> ipsToRelease = _ipAddressDao.listByAssociatedNetwork(networkId); |
| if (ipsToRelease != null && !ipsToRelease.isEmpty()) { |
| for (IPAddressVO ip : ipsToRelease) { |
| unassignPublicIpAddress(ip); |
| } |
| |
| s_logger.debug("Ip addresses associated with network " + networkId + " 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(); |
| NetworkVO 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 + "..."); |
| for (NetworkElement element : _networkElements) { |
| //stop and start the network element |
| if (!element.restart(network, context)) { |
| s_logger.warn("Failed to restart network element(s) as a part of network id" + networkId + " restart"); |
| return false; |
| } |
| } |
| |
| //associate all ip addresses |
| if (!applyIpAssociations(network, false)) { |
| s_logger.warn("Failed to apply ip addresses as a part of network id" + networkId + " restart"); |
| return false; |
| } |
| |
| //apply port forwarding rules |
| if (!_rulesMgr.applyPortForwardingRulesForNetwork(networkId, false, context.getAccount())) { |
| s_logger.warn("Failed to reapply firewall rule(s) as a part of network id=" + networkId + " restart"); |
| } |
| |
| //apply load balancer rules |
| if (!_lbMgr.applyLoadBalancersForNetwork(networkId)) { |
| s_logger.warn("Failed to reapply load balancer rules as a part of network id=" + networkId + " restart"); |
| return false; |
| } |
| |
| //apply vpn rules |
| List<? extends RemoteAccessVpn> vpnsToReapply = _vpnMgr.listRemoteAccessVpns(networkId); |
| if (vpnsToReapply != null) { |
| for (RemoteAccessVpn vpn : vpnsToReapply) { |
| if (_vpnMgr.startRemoteAccessVpn(vpn.getServerAddressId()) == null) { |
| s_logger.warn("Failed to reapply load balancer rules as a part of network id=" + networkId + " restart"); |
| return false; |
| } |
| } |
| } |
| |
| s_logger.debug("Network id=" + 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 Map<Capability, String> getServiceCapability(long zoneId, Service service) { |
| Map<Service, Map<Capability, String>> networkCapabilities = getZoneCapabilities(zoneId); |
| return networkCapabilities.get(service); |
| } |
| |
| @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(long ipAddressId) { |
| IPAddressVO addr = _ipAddressDao.findById(ipAddressId); |
| 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, Network network) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException { |
| Account owner = _accountMgr.getActiveAccount(accountId); |
| boolean createNetwork = true; |
| |
| Transaction txn= Transaction.currentTxn(); |
| |
| txn.start(); |
| |
| if (network != null) { |
| createNetwork = false; |
| } else { |
| List<? extends Network> networks = getVirtualNetworksOwnedByAccountInZone(owner.getAccountName(), owner.getDomainId(), zoneId); |
| if (networks.size() == 0) { |
| createNetwork = true; |
| } else { |
| network = networks.get(0); |
| } |
| } |
| |
| // create new Virtual network for the user if it doesn't exist |
| if (createNetwork) { |
| List<? extends NetworkOffering> offerings = _configMgr.listNetworkOfferings(TrafficType.Guest, false); |
| network = createNetwork(offerings.get(0).getId(), owner.getAccountName() + "-network", owner.getAccountName() + "-network", false, true, zoneId, null, null, null, null, owner); |
| |
| if (network == null) { |
| s_logger.warn("Failed to create default Virtual network for the account " + accountId + "in zone " + zoneId); |
| return false; |
| } |
| } |
| |
| |
| //update all ips with a network id, mark them as allocated and update resourceCount/usage |
| List<IPAddressVO> ips = _ipAddressDao.listByVlanId(vlanId); |
| for (IPAddressVO addr : ips) { |
| if (!addr.isSourceNat() && addr.getState() != State.Allocated) { |
| addr.setAssociatedWithNetworkId(network.getId()); |
| addr.setSourceNat(false); |
| addr.setAllocatedTime(new Date()); |
| addr.setAllocatedInDomainId(owner.getDomainId()); |
| addr.setAllocatedToAccountId(owner.getId()); |
| addr.setState(IpAddress.State.Allocating); |
| markPublicIpAsAllocated(addr); |
| } |
| } |
| |
| txn.commit(); |
| 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(long ipAddressId) { |
| return _ipAddressDao.findById(ipAddressId); |
| } |
| |
| @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; |
| } |
| |
| @Override |
| public boolean zoneIsConfiguredForExternalNetworking(long zoneId) { |
| DataCenterVO zone = _dcDao.findById(zoneId); |
| |
| return (zone.getGatewayProvider().equals(Network.Provider.JuniperSRX.getName()) && zone.getFirewallProvider().equals(Network.Provider.JuniperSRX.getName()) && zone.getLoadBalancerProvider().equals( |
| Network.Provider.F5BigIp.getName())); |
| |
| } |
| } |