// Licensed to the Apache Software Foundation (ASF) under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information // regarding copyright ownership. The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. package com.cloud.network; import com.cloud.agent.AgentManager; import com.cloud.agent.Listener; import com.cloud.agent.api.*; import com.cloud.agent.api.to.NicTO; import com.cloud.alert.AlertManager; import com.cloud.api.ApiDBUtils; import com.cloud.configuration.Config; import com.cloud.configuration.ConfigurationManager; import com.cloud.configuration.Resource.ResourceType; import com.cloud.configuration.dao.ConfigurationDao; import com.cloud.dc.*; import com.cloud.dc.DataCenter.NetworkType; import com.cloud.dc.Vlan.VlanType; import com.cloud.dc.dao.AccountVlanMapDao; import com.cloud.dc.dao.DataCenterDao; import com.cloud.dc.dao.DataCenterVnetDao; 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.ActionEventUtils; import com.cloud.event.EventTypes; import com.cloud.event.UsageEventUtils; import com.cloud.event.dao.UsageEventDao; import com.cloud.exception.*; import com.cloud.host.Host; import com.cloud.host.HostVO; import com.cloud.host.Status; import com.cloud.host.dao.HostDao; import com.cloud.server.ConfigurationServer; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.network.IpAddress.State; import com.cloud.network.Network.*; import com.cloud.network.Networks.AddressFormat; import com.cloud.network.Networks.BroadcastDomainType; import com.cloud.network.Networks.IsolationType; import com.cloud.network.Networks.TrafficType; import com.cloud.network.addr.PublicIp; import com.cloud.network.dao.*; import com.cloud.network.element.*; import com.cloud.network.guru.NetworkGuru; import com.cloud.network.lb.LoadBalancingRulesManager; import com.cloud.network.rules.*; import com.cloud.network.rules.FirewallRule.Purpose; import com.cloud.network.rules.FirewallRuleVO; import com.cloud.network.rules.LoadBalancerContainer.Scheme; import com.cloud.network.rules.PortForwardingRuleVO; import com.cloud.network.rules.RulesManager; import com.cloud.network.rules.StaticNat; import com.cloud.network.rules.StaticNatRule; import com.cloud.network.rules.StaticNatRuleImpl; import com.cloud.network.rules.dao.PortForwardingRulesDao; import com.cloud.network.vpc.NetworkACLManager; import com.cloud.network.vpc.VpcManager; import com.cloud.network.vpc.dao.PrivateIpDao; import com.cloud.network.vpn.RemoteAccessVpnService; import com.cloud.offering.NetworkOffering; import com.cloud.offering.NetworkOffering.Availability; import com.cloud.offerings.NetworkOfferingServiceMapVO; import com.cloud.offerings.NetworkOfferingVO; import com.cloud.offerings.dao.NetworkOfferingDao; import com.cloud.offerings.dao.NetworkOfferingDetailsDao; import com.cloud.offerings.dao.NetworkOfferingServiceMapDao; import com.cloud.org.Grouping; import com.cloud.user.*; import com.cloud.user.dao.AccountDao; import com.cloud.user.dao.UserDao; import com.cloud.utils.Journal; import com.cloud.utils.NumbersUtil; import com.cloud.utils.Pair; import com.cloud.utils.component.AdapterBase; import com.cloud.utils.component.ManagerBase; import com.cloud.utils.concurrency.NamedThreadFactory; import com.cloud.utils.db.*; import com.cloud.utils.db.JoinBuilder.JoinType; import com.cloud.utils.db.SearchCriteria.Op; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.fsm.NoTransitionException; import com.cloud.utils.fsm.StateMachine2; import com.cloud.utils.net.Ip; import com.cloud.utils.net.NetUtils; import com.cloud.vm.*; import com.cloud.vm.Nic.ReservationStrategy; import com.cloud.vm.VirtualMachine.Type; import com.cloud.vm.dao.*; import org.apache.cloudstack.acl.ControlledEntity.ACLType; import org.apache.cloudstack.acl.SecurityChecker.AccessType; import org.apache.cloudstack.region.PortableIp; import org.apache.cloudstack.region.PortableIpDao; import org.apache.cloudstack.region.PortableIpVO; import org.apache.cloudstack.region.Region; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; import javax.ejb.Local; import javax.inject.Inject; import javax.naming.ConfigurationException; import java.net.URI; import java.util.*; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; /** * NetworkManagerImpl implements NetworkManager. */ @Component @Local(value = { NetworkManager.class}) public class NetworkManagerImpl extends ManagerBase implements NetworkManager, Listener { static final Logger s_logger = Logger.getLogger(NetworkManagerImpl.class); @Inject DataCenterDao _dcDao = null; @Inject VlanDao _vlanDao = null; @Inject IPAddressDao _ipAddressDao = null; @Inject AccountDao _accountDao = null; @Inject DomainDao _domainDao = null; @Inject UserDao _userDao = null; @Inject ConfigurationDao _configDao; @Inject UserVmDao _userVmDao = 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 RemoteAccessVpnService _vpnMgr; @Inject PodVlanMapDao _podVlanMapDao; @Inject NetworkOfferingDetailsDao _ntwkOffDetailsDao; @Inject ConfigurationServer _configServer; @Inject AccountGuestVlanMapDao _accountGuestVlanMapDao; @Inject DataCenterVnetDao _datacenterVnetDao; List _networkGurus; public List getNetworkGurus() { return _networkGurus; } public void setNetworkGurus(List _networkGurus) { this._networkGurus = _networkGurus; } List _networkElements; public List getNetworkElements() { return _networkElements; } public void setNetworkElements(List _networkElements) { this._networkElements = _networkElements; } @Inject NetworkDomainDao _networkDomainDao; List _ipDeployers; public List getIpDeployers() { return _ipDeployers; } public void setIpDeployers(List _ipDeployers) { this._ipDeployers = _ipDeployers; } List _dhcpProviders; public List getDhcpProviders() { return _dhcpProviders; } public void setDhcpProviders(List _dhcpProviders) { this._dhcpProviders = _dhcpProviders; } @Inject VMInstanceDao _vmDao; @Inject FirewallManager _firewallMgr; @Inject FirewallRulesDao _firewallDao; @Inject ResourceLimitService _resourceLimitMgr; @Inject NetworkOfferingServiceMapDao _ntwkOfferingSrvcDao; @Inject PhysicalNetworkDao _physicalNetworkDao; @Inject PhysicalNetworkServiceProviderDao _pNSPDao; @Inject PortForwardingRulesDao _portForwardingRulesDao; @Inject LoadBalancerDao _lbDao; @Inject PhysicalNetworkTrafficTypeDao _pNTrafficTypeDao; @Inject AgentManager _agentMgr; @Inject HostDao _hostDao; @Inject NetworkServiceMapDao _ntwkSrvcDao; @Inject StorageNetworkManager _stnwMgr; @Inject VpcManager _vpcMgr; @Inject PrivateIpDao _privateIpDao; @Inject NetworkACLManager _networkACLMgr; @Inject UsageEventDao _usageEventDao; @Inject NetworkModel _networkModel; @Inject NicSecondaryIpDao _nicSecondaryIpDao; @Inject UserIpv6AddressDao _ipv6Dao; @Inject Ipv6AddressManager _ipv6Mgr; @Inject PortableIpDao _portableIpDao; protected StateMachine2 _stateMachine; private final HashMap _systemNetworks = new HashMap(5); private static Long _privateOfferingId = null; ScheduledExecutorService _executor; SearchBuilder AssignIpAddressSearch; SearchBuilder AssignIpAddressFromPodVlanSearch; int _networkGcWait; int _networkGcInterval; int _networkLockTimeout; private Map _configs; HashMap _lastNetworkIdsToFree = new HashMap(); @Override public PublicIp assignPublicIpAddress(long dcId, Long podId, Account owner, VlanType type, Long networkId, String requestedIp, boolean isSystem) throws InsufficientAddressCapacityException { return fetchNewPublicIp(dcId, podId, null, owner, type, networkId, false, true, requestedIp, isSystem, null); } @Override public PublicIp assignPublicIpAddressFromVlans(long dcId, Long podId, Account owner, VlanType type, List vlanDbIds, Long networkId, String requestedIp, boolean isSystem) throws InsufficientAddressCapacityException { return fetchNewPublicIp(dcId, podId, vlanDbIds , owner, type, networkId, false, true, requestedIp, isSystem, null); } @DB public PublicIp fetchNewPublicIp(long dcId, Long podId, List vlanDbIds, Account owner, VlanType vlanUse, Long guestNetworkId, boolean sourceNat, boolean assign, String requestedIp, boolean isSystem, Long vpcId) throws InsufficientAddressCapacityException { StringBuilder errorMessage = new StringBuilder("Unable to get ip adress in "); boolean fetchFromDedicatedRange = false; List dedicatedVlanDbIds = new ArrayList(); List nonDedicatedVlanDbIds = new ArrayList(); Transaction txn = Transaction.currentTxn(); txn.start(); SearchCriteria sc = null; if (podId != null) { sc = AssignIpAddressFromPodVlanSearch.create(); sc.setJoinParameters("podVlanMapSB", "podId", podId); errorMessage.append(" pod id=" + podId); } else { sc = AssignIpAddressSearch.create(); errorMessage.append(" zone id=" + dcId); } // If owner has dedicated Public IP ranges, fetch IP from the dedicated range // Otherwise fetch IP from the system pool List maps = _accountVlanMapDao.listAccountVlanMapsByAccount(owner.getId()); for (AccountVlanMapVO map : maps) { if (vlanDbIds == null || vlanDbIds.contains(map.getVlanDbId())) dedicatedVlanDbIds.add(map.getVlanDbId()); } List nonDedicatedVlans = _vlanDao.listZoneWideNonDedicatedVlans(dcId); for (VlanVO nonDedicatedVlan : nonDedicatedVlans) { if (vlanDbIds == null || vlanDbIds.contains(nonDedicatedVlan.getId())) nonDedicatedVlanDbIds.add(nonDedicatedVlan.getId()); } if (dedicatedVlanDbIds != null && !dedicatedVlanDbIds.isEmpty()) { fetchFromDedicatedRange = true; sc.setParameters("vlanId", dedicatedVlanDbIds.toArray()); errorMessage.append(", vlanId id=" + dedicatedVlanDbIds.toArray()); } else if (nonDedicatedVlanDbIds != null && !nonDedicatedVlanDbIds.isEmpty()) { sc.setParameters("vlanId", nonDedicatedVlanDbIds.toArray()); errorMessage.append(", vlanId id=" + nonDedicatedVlanDbIds.toArray()); } else { if (podId != null) { InsufficientAddressCapacityException ex = new InsufficientAddressCapacityException ("Insufficient address capacity", Pod.class, podId); ex.addProxyObject(ApiDBUtils.findPodById(podId).getUuid()); throw ex; } s_logger.warn(errorMessage.toString()); InsufficientAddressCapacityException ex = new InsufficientAddressCapacityException ("Insufficient address capacity", DataCenter.class, dcId); ex.addProxyObject(ApiDBUtils.findZoneById(dcId).getUuid()); throw ex; } sc.setParameters("dc", dcId); DataCenter zone = _configMgr.getZone(dcId); // for direct network take ip addresses only from the vlans belonging to the network if (vlanUse == VlanType.DirectAttached) { sc.setJoinParameters("vlan", "networkId", guestNetworkId); errorMessage.append(", network id=" + guestNetworkId); } sc.setJoinParameters("vlan", "type", vlanUse); if (requestedIp != null) { sc.addAnd("address", SearchCriteria.Op.EQ, requestedIp); errorMessage.append(": requested ip " + requestedIp + " is not available"); } Filter filter = new Filter(IPAddressVO.class, "vlanId", true, 0l, 1l); List addrs = _ipAddressDao.lockRows(sc, filter, true); // If all the dedicated IPs of the owner are in use fetch an IP from the system pool if (addrs.size() == 0 && fetchFromDedicatedRange) { if (nonDedicatedVlanDbIds != null && !nonDedicatedVlanDbIds.isEmpty()) { fetchFromDedicatedRange = false; sc.setParameters("vlanId", nonDedicatedVlanDbIds.toArray()); errorMessage.append(", vlanId id=" + nonDedicatedVlanDbIds.toArray()); addrs = _ipAddressDao.lockRows(sc, filter, true); } } if (addrs.size() == 0) { if (podId != null) { InsufficientAddressCapacityException ex = new InsufficientAddressCapacityException ("Insufficient address capacity", Pod.class, podId); // for now, we hardcode the table names, but we should ideally do a lookup for the tablename from the VO object. ex.addProxyObject(ApiDBUtils.findPodById(podId).getUuid()); throw ex; } s_logger.warn(errorMessage.toString()); InsufficientAddressCapacityException ex = new InsufficientAddressCapacityException ("Insufficient address capacity", DataCenter.class, dcId); ex.addProxyObject(ApiDBUtils.findZoneById(dcId).getUuid()); throw ex; } assert (addrs.size() == 1) : "Return size is incorrect: " + addrs.size(); if (!fetchFromDedicatedRange) { // Check that the maximum number of public IPs for the given accountId will not be exceeded try { _resourceLimitMgr.checkResourceLimit(owner, ResourceType.public_ip); } catch (ResourceAllocationException ex) { s_logger.warn("Failed to allocate resource of type " + ex.getResourceType() + " for account " + owner); throw new AccountLimitException("Maximum number of public IP addresses for account: " + owner.getAccountName() + " has been exceeded."); } } IPAddressVO addr = addrs.get(0); addr.setSourceNat(sourceNat); addr.setAllocatedTime(new Date()); addr.setAllocatedInDomainId(owner.getDomainId()); addr.setAllocatedToAccountId(owner.getId()); addr.setSystem(isSystem); if (assign) { markPublicIpAsAllocated(addr); } else { addr.setState(IpAddress.State.Allocating); } addr.setState(assign ? IpAddress.State.Allocated : IpAddress.State.Allocating); if (vlanUse != VlanType.DirectAttached || zone.getNetworkType() == NetworkType.Basic) { addr.setAssociatedWithNetworkId(guestNetworkId); addr.setVpcId(vpcId); } _ipAddressDao.update(addr.getId(), addr); txn.commit(); if (vlanUse == VlanType.VirtualNetwork) { _firewallMgr.addSystemFirewallRules(addr, owner); } return PublicIp.createFromAddrAndVlan(addr, _vlanDao.findById(addr.getVlanId())); } @DB @Override public 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.getAllocatedToAccountId()); txn.start(); addr.setState(IpAddress.State.Allocated); _ipAddressDao.update(addr.getId(), addr); // Save usage event if (owner.getAccountId() != Account.ACCOUNT_ID_SYSTEM) { VlanVO vlan = _vlanDao.findById(addr.getVlanId()); String guestType = vlan.getVlanType().toString(); if (!isIpDedicated(addr)) { UsageEventUtils.publishUsageEvent(EventTypes.EVENT_NET_IP_ASSIGN, owner.getId(), addr.getDataCenterId(), addr.getId(), addr.getAddress().toString(), addr.isSourceNat(), guestType, addr.getSystem(), addr.getClass().getName(), addr.getUuid()); } // don't increment resource count for direct and dedicated ip addresses if (addr.getAssociatedWithNetworkId() != null && !isIpDedicated(addr)) { _resourceLimitMgr.incrementResourceCount(owner.getId(), ResourceType.public_ip); } } txn.commit(); } private boolean isIpDedicated(IPAddressVO addr) { List maps = _accountVlanMapDao.listAccountVlanMapsByVlan(addr.getVlanId()); if (maps != null && !maps.isEmpty()) return true; return false; } @Override public PublicIp assignSourceNatIpAddressToGuestNetwork(Account owner, Network guestNetwork) throws InsufficientAddressCapacityException, ConcurrentOperationException { assert (guestNetwork.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 = guestNetwork.getDataCenterId(); IPAddressVO sourceNatIp = getExistingSourceNatInNetwork(owner.getId(), guestNetwork.getId()); PublicIp ipToReturn = null; if (sourceNatIp != null) { ipToReturn = PublicIp.createFromAddrAndVlan(sourceNatIp, _vlanDao.findById(sourceNatIp.getVlanId())); } else { ipToReturn = assignDedicateIpAddress(owner, guestNetwork.getId(), null, dcId, true); } return ipToReturn; } @Override public PublicIp assignVpnGatewayIpAddress(long dcId, Account owner, long vpcId) throws InsufficientAddressCapacityException, ConcurrentOperationException { return assignDedicateIpAddress(owner, null, vpcId, dcId, false); } @DB @Override public PublicIp assignDedicateIpAddress(Account owner, Long guestNtwkId, Long vpcId, long dcId, boolean isSourceNat) throws ConcurrentOperationException, InsufficientAddressCapacityException { long ownerId = owner.getId(); PublicIp ip = null; Transaction txn = Transaction.currentTxn(); try { txn.start(); owner = _accountDao.acquireInLockTable(ownerId); if (owner == null) { // this ownerId comes from owner or type Account. See the class "AccountVO" and the annotations in that class // to get the table name and field name that is queried to fill this ownerid. ConcurrentOperationException ex = new ConcurrentOperationException("Unable to lock account"); } if (s_logger.isDebugEnabled()) { s_logger.debug("lock account " + ownerId + " is acquired"); } ip = fetchNewPublicIp(dcId, null, null, owner, VlanType.VirtualNetwork, guestNtwkId, isSourceNat, false, null, false, vpcId); IPAddressVO publicIp = ip.ip(); markPublicIpAsAllocated(publicIp); _ipAddressDao.update(publicIp.getId(), publicIp); 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); } } } @Override public boolean applyIpAssociations(Network network, boolean continueOnError) throws ResourceUnavailableException { List userIps = _ipAddressDao.listByAssociatedNetwork(network.getId(), null); List publicIps = new ArrayList(); if (userIps != null && !userIps.isEmpty()) { for (IPAddressVO userIp : userIps) { PublicIp publicIp = PublicIp.createFromAddrAndVlan(userIp, _vlanDao.findById(userIp.getVlanId())); publicIps.add(publicIp); } } boolean success = applyIpAssociations(network, false, continueOnError, publicIps); if (success) { for (IPAddressVO addr : userIps) { if (addr.getState() == IpAddress.State.Allocating) { markPublicIpAsAllocated(addr); } else if (addr.getState() == IpAddress.State.Releasing) { // Cleanup all the resources for ip address if there are any, and only then un-assign ip in the // system if (cleanupIpResources(addr.getId(), Account.ACCOUNT_ID_SYSTEM, _accountMgr.getSystemAccount())) { s_logger.debug("Unassiging ip address " + addr); _ipAddressDao.unassignIpAddress(addr.getId()); } else { success = false; s_logger.warn("Failed to release resources for ip address id=" + addr.getId()); } } } } return success; } @Override public boolean applyIpAssociations(Network network, boolean rulesRevoked, boolean continueOnError, List publicIps) throws ResourceUnavailableException { boolean success = true; Map> ipToServices = _networkModel.getIpToServices(publicIps, rulesRevoked, true); Map> providerToIpList = _networkModel.getProviderToIpList(network, ipToServices); for (Provider provider : providerToIpList.keySet()) { try { ArrayList ips = providerToIpList.get(provider); if (ips == null || ips.isEmpty()) { continue; } IpDeployer deployer = null; NetworkElement element = _networkModel.getElementImplementingProvider(provider.getName()); if (!(element instanceof IpDeployingRequester)) { throw new CloudRuntimeException("Element " + element + " is not a IpDeployingRequester!"); } deployer = ((IpDeployingRequester)element).getIpDeployer(network); if (deployer == null) { throw new CloudRuntimeException("Fail to get ip deployer for element: " + element); } Set services = new HashSet(); for (PublicIpAddress ip : ips) { if (!ipToServices.containsKey(ip)) { continue; } services.addAll(ipToServices.get(ip)); } deployer.applyIps(network, ips, services); } catch (ResourceUnavailableException e) { success = false; if (!continueOnError) { throw e; } else { s_logger.debug("Resource is not available: " + provider.getName(), e); } } } return success; } protected List getIsolatedNetworksWithSourceNATOwnedByAccountInZone(long zoneId, Account owner) { return _networksDao.listSourceNATEnabledNetworks(owner.getId(), zoneId, Network.GuestType.Isolated); } private IpAddress allocateIP(Account ipOwner, boolean isSystem, long zoneId) throws ResourceAllocationException, InsufficientAddressCapacityException, ConcurrentOperationException { Account caller = UserContext.current().getCaller(); long callerUserId = UserContext.current().getCallerUserId(); // check permissions _accountMgr.checkAccess(caller, null, false, ipOwner); DataCenter zone = _configMgr.getZone(zoneId); return allocateIp(ipOwner, isSystem, caller, callerUserId, zone); } @DB @Override public IpAddress allocateIp(Account ipOwner, boolean isSystem, Account caller, long callerUserId, DataCenter zone) throws ConcurrentOperationException, ResourceAllocationException, InsufficientAddressCapacityException { VlanType vlanType = VlanType.VirtualNetwork; boolean assign = false; if (Grouping.AllocationState.Disabled == zone.getAllocationState() && !_accountMgr.isRootAdmin(caller.getType())) { // zone is of type DataCenter. See DataCenterVO.java. PermissionDeniedException ex = new PermissionDeniedException("Cannot perform this operation, " + "Zone is currently disabled"); ex.addProxyObject("data_center", zone.getId(), "zoneId"); throw ex; } PublicIp ip = null; Transaction txn = Transaction.currentTxn(); Account accountToLock = null; try { if (s_logger.isDebugEnabled()) { s_logger.debug("Associate IP address called by the user " + callerUserId + " account " + ipOwner.getId()); } accountToLock = _accountDao.acquireInLockTable(ipOwner.getId()); if (accountToLock == null) { s_logger.warn("Unable to lock account: " + ipOwner.getId()); throw new ConcurrentOperationException("Unable to acquire account lock"); } if (s_logger.isDebugEnabled()) { s_logger.debug("Associate IP address lock acquired"); } txn.start(); ip = fetchNewPublicIp(zone.getId(), null, null, ipOwner, vlanType, null, false, assign, null, isSystem, null); if (ip == null) { InsufficientAddressCapacityException ex = new InsufficientAddressCapacityException ("Unable to find available public IP addresses", DataCenter.class, zone.getId()); ex.addProxyObject(ApiDBUtils.findZoneById(zone.getId()).getUuid()); throw ex; } UserContext.current().setEventDetails("Ip Id: " + ip.getId()); Ip ipAddress = ip.getAddress(); s_logger.debug("Got " + ipAddress + " to assign for account " + ipOwner.getId() + " in zone " + zone.getId()); txn.commit(); } finally { if (accountToLock != null) { if (s_logger.isDebugEnabled()) { s_logger.debug("Releasing lock account " + ipOwner); } _accountDao.releaseFromLockTable(ipOwner.getId()); s_logger.debug("Associate IP address lock released"); } } return ip; } @Override @DB public IpAddress allocatePortableIp(Account ipOwner, Account caller, long dcId, Long networkId, Long vpcID) throws ConcurrentOperationException, ResourceAllocationException, InsufficientAddressCapacityException { Transaction txn = Transaction.currentTxn(); GlobalLock portableIpLock = GlobalLock.getInternLock("PortablePublicIpRange"); PortableIpVO allocatedPortableIp; IPAddressVO ipaddr; try { portableIpLock.lock(5); txn.start(); //TODO: get the region ID corresponding to running management server List portableIpVOs = _portableIpDao.listByRegionIdAndState(1, PortableIp.State.Free); if (portableIpVOs == null || portableIpVOs.isEmpty()) { InsufficientAddressCapacityException ex = new InsufficientAddressCapacityException ("Unable to find available portable IP addresses", Region.class, new Long(1)); throw ex; } // allocate first portable IP to the user allocatedPortableIp = portableIpVOs.get(0); allocatedPortableIp.setAllocatedTime(new Date()); allocatedPortableIp.setAllocatedToAccountId(ipOwner.getAccountId()); allocatedPortableIp.setAllocatedInDomainId(ipOwner.getDomainId()); allocatedPortableIp.setState(PortableIp.State.Allocated); _portableIpDao.update(allocatedPortableIp.getId(), allocatedPortableIp); // provision portable IP range VLAN long physicalNetworkId = _networkModel.getDefaultPhysicalNetworkByZoneAndTrafficType(dcId, TrafficType.Public).getId(); Network network = _networkModel.getNetwork(physicalNetworkId); String range = allocatedPortableIp.getAddress() + "-" + allocatedPortableIp.getAddress(); VlanVO vlan = new VlanVO(VlanType.VirtualNetwork, allocatedPortableIp.getVlan(), allocatedPortableIp.getGateway(), allocatedPortableIp.getNetmask(), dcId, range, network.getId(), network.getId(), null, null, null); vlan = _vlanDao.persist(vlan); // provision the portable IP in to user_ip_address table ipaddr = new IPAddressVO(new Ip(allocatedPortableIp.getAddress()), dcId, networkId, vpcID, network.getId(), network.getId(), vlan.getId(), true); ipaddr.setState(State.Allocated); ipaddr.setAllocatedTime(new Date()); ipaddr.setAllocatedInDomainId(ipOwner.getDomainId()); ipaddr.setAllocatedToAccountId(ipOwner.getId()); ipaddr= _ipAddressDao.persist(ipaddr); txn.commit(); } finally { portableIpLock.unlock(); } return ipaddr; } protected IPAddressVO getExistingSourceNatInNetwork(long ownerId, Long networkId) { List addrs = _networkModel.listPublicIpsAssignedToGuestNtwk(ownerId, networkId, true); IPAddressVO sourceNatIp = null; if (addrs.isEmpty()) { return null; } else { // Account already has ip addresses for (IpAddress addr : addrs) { if (addr.isSourceNat()) { sourceNatIp = _ipAddressDao.findById(addr.getId()); return sourceNatIp; } } assert (sourceNatIp != null) : "How do we get a bunch of ip addresses but none of them are source nat? " + "account=" + ownerId + "; networkId=" + networkId; } return sourceNatIp; } @DB @Override public IPAddressVO associateIPToGuestNetwork(long ipId, long networkId, boolean releaseOnFailure) throws ResourceAllocationException, ResourceUnavailableException, InsufficientAddressCapacityException, ConcurrentOperationException { Account caller = UserContext.current().getCaller(); Account owner = null; IPAddressVO ipToAssoc = _ipAddressDao.findById(ipId); if (ipToAssoc != null) { Network network = _networksDao.findById(networkId); if (network == null) { throw new InvalidParameterValueException("Invalid network id is given"); } DataCenter zone = _configMgr.getZone(network.getDataCenterId()); if (zone.getNetworkType() == NetworkType.Advanced) { if (network.getGuestType() == Network.GuestType.Shared) { if (isSharedNetworkOfferingWithServices(network.getNetworkOfferingId())) { _accountMgr.checkAccess(UserContext.current().getCaller(), AccessType.UseNetwork, false, network); } else { throw new InvalidParameterValueException("IP can be associated with guest network of 'shared' type only if " + "network services Source Nat, Static Nat, Port Forwarding, Load balancing, firewall are enabled in the network"); } } } else { _accountMgr.checkAccess(caller, null, true, ipToAssoc); } owner = _accountMgr.getAccount(ipToAssoc.getAllocatedToAccountId()); } else { s_logger.debug("Unable to find ip address by id: " + ipId); return null; } if (ipToAssoc.getAssociatedWithNetworkId() != null) { s_logger.debug("IP " + ipToAssoc + " is already assocaited with network id" + networkId); return ipToAssoc; } Network network = _networksDao.findById(networkId); if (network != null) { _accountMgr.checkAccess(owner, AccessType.UseNetwork, false, network); } else { s_logger.debug("Unable to find ip address by id: " + ipId); return null; } DataCenter zone = _configMgr.getZone(network.getDataCenterId()); // allow associating IP addresses to guest network only if (network.getTrafficType() != TrafficType.Guest) { throw new InvalidParameterValueException("Ip address can be associated to the network with trafficType " + TrafficType.Guest); } // Check that network belongs to IP owner - skip this check // - if zone is basic zone as there is just one guest network, // - if shared network in Advanced zone // - and it belongs to the system if (network.getAccountId() != owner.getId()) { if (zone.getNetworkType() != NetworkType.Basic && !(zone.getNetworkType() == NetworkType.Advanced && network.getGuestType() == Network.GuestType.Shared)) { throw new InvalidParameterValueException("The owner of the network is not the same as owner of the IP"); } } // In Advance zone only allow to do IP assoc // - for Isolated networks with source nat service enabled // - for shared networks with source nat service enabled if (zone.getNetworkType() == NetworkType.Advanced && !(_networkModel.areServicesSupportedInNetwork(network.getId(), Service.SourceNat))) { throw new InvalidParameterValueException("In zone of type " + NetworkType.Advanced + " ip address can be associated only to the network of guest type " + GuestType.Isolated + " with the " + Service.SourceNat.getName() + " enabled"); } NetworkOffering offering = _networkOfferingDao.findById(network.getNetworkOfferingId()); boolean sharedSourceNat = offering.getSharedSourceNat(); boolean isSourceNat = false; if (!sharedSourceNat) { if (getExistingSourceNatInNetwork(owner.getId(), networkId) == null) { if (network.getGuestType() == GuestType.Isolated && network.getVpcId() == null) { isSourceNat = true; } } } s_logger.debug("Associating ip " + ipToAssoc + " to network " + network); IPAddressVO ip = _ipAddressDao.findById(ipId); //update ip address with networkId ip.setAssociatedWithNetworkId(networkId); ip.setSourceNat(isSourceNat); _ipAddressDao.update(ipId, ip); boolean success = false; try { success = applyIpAssociations(network, false); if (success) { s_logger.debug("Successfully associated ip address " + ip.getAddress().addr() + " to network " + network); } else { s_logger.warn("Failed to associate ip address " + ip.getAddress().addr() + " to network " + network); } return ip; } finally { if (!success && releaseOnFailure) { if (ip != null) { try { s_logger.warn("Failed to associate ip address, so releasing ip from the database " + 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 IPAddressVO associatePortableIPToGuestNetwork(long ipAddrId, long networkId, boolean releaseOnFailure) throws ResourceAllocationException, ResourceUnavailableException, InsufficientAddressCapacityException, ConcurrentOperationException { return associateIPToGuestNetwork(ipAddrId, networkId, releaseOnFailure); } @DB @Override public IPAddressVO disassociatePortableIPToGuestNetwork(long ipId, long networkId) throws ResourceAllocationException, ResourceUnavailableException, InsufficientAddressCapacityException, ConcurrentOperationException { Account caller = UserContext.current().getCaller(); Account owner = null; Network network = _networksDao.findById(networkId); if (network == null) { throw new InvalidParameterValueException("Invalid network id is given"); } IPAddressVO ipToAssoc = _ipAddressDao.findById(ipId); if (ipToAssoc != null) { if (ipToAssoc.getAssociatedWithNetworkId() == null) { throw new InvalidParameterValueException("IP " + ipToAssoc + " is not associated with any network"); } if (ipToAssoc.getAssociatedWithNetworkId() != network.getId()) { throw new InvalidParameterValueException("IP " + ipToAssoc + " is not associated with network id" + networkId); } DataCenter zone = _configMgr.getZone(network.getDataCenterId()); if (zone.getNetworkType() == NetworkType.Advanced) { if (network.getGuestType() == Network.GuestType.Shared) { assert (isSharedNetworkOfferingWithServices(network.getNetworkOfferingId())); _accountMgr.checkAccess(UserContext.current().getCaller(), AccessType.UseNetwork, false, network); } } else { _accountMgr.checkAccess(caller, null, true, ipToAssoc); } owner = _accountMgr.getAccount(ipToAssoc.getAllocatedToAccountId()); } else { s_logger.debug("Unable to find ip address by id: " + ipId); return null; } DataCenter zone = _configMgr.getZone(network.getDataCenterId()); // Check that network belongs to IP owner - skip this check // - if zone is basic zone as there is just one guest network, // - if shared network in Advanced zone // - and it belongs to the system if (network.getAccountId() != owner.getId()) { if (zone.getNetworkType() != NetworkType.Basic && !(zone.getNetworkType() == NetworkType.Advanced && network.getGuestType() == Network.GuestType.Shared)) { throw new InvalidParameterValueException("The owner of the network is not the same as owner of the IP"); } } // Check if IP has any services (rules) associated in the network List ipList = new ArrayList(); PublicIp publicIp = PublicIp.createFromAddrAndVlan(ipToAssoc, _vlanDao.findById(ipToAssoc.getVlanId())); ipList.add(publicIp); Map> ipToServices = _networkModel.getIpToServices(ipList, false, true); if (ipToServices != null & !ipToServices.isEmpty()) { Set services = ipToServices.get(publicIp); if (services != null && !services.isEmpty()) { throw new InvalidParameterValueException("IP " + ipToAssoc + " has services and rules associated in the network " + networkId); } } IPAddressVO ip = _ipAddressDao.findById(ipId); ip.setAssociatedWithNetworkId(null); _ipAddressDao.update(ipId, ip); try { boolean success = applyIpAssociations(network, false); if (success) { s_logger.debug("Successfully associated ip address " + ip.getAddress().addr() + " to network " + network); } else { s_logger.warn("Failed to associate ip address " + ip.getAddress().addr() + " to network " + network); } return ip; } finally { } } @Override public boolean isPortableIpTransferableFromNetwork(long ipAddrId, long networkId) { Network network = _networksDao.findById(networkId); if (network == null) { throw new InvalidParameterValueException("Invalid network id is given"); } IPAddressVO ip = _ipAddressDao.findById(ipAddrId); if (ip == null) { throw new InvalidParameterValueException("Invalid network id is given"); } // Check if IP has any services (rules) associated in the network List ipList = new ArrayList(); PublicIp publicIp = PublicIp.createFromAddrAndVlan(ip, _vlanDao.findById(ip.getVlanId())); ipList.add(publicIp); Map> ipToServices = _networkModel.getIpToServices(ipList, false, true); if (ipToServices != null & !ipToServices.isEmpty()) { Set ipServices = ipToServices.get(publicIp); if (ipServices != null && !ipServices.isEmpty()) { return false; } } return true; } @DB @Override public void transferPortableIP(long ipAddrId, long currentNetworkId, long newNetworkId) throws ResourceAllocationException, ResourceUnavailableException, InsufficientAddressCapacityException, ConcurrentOperationException { Network srcNetwork = _networksDao.findById(currentNetworkId); if (srcNetwork == null) { throw new InvalidParameterValueException("Invalid source network id " + currentNetworkId +" is given"); } Network dstNetwork = _networksDao.findById(newNetworkId); if (dstNetwork == null) { throw new InvalidParameterValueException("Invalid source network id " + newNetworkId +" is given"); } IPAddressVO ip = _ipAddressDao.findById(ipAddrId); if (ip == null) { throw new InvalidParameterValueException("Invalid portable ip address id is given"); } Transaction txn = Transaction.currentTxn(); txn.start(); assert(isPortableIpTransferableFromNetwork(ipAddrId, currentNetworkId)); if (srcNetwork.getVpcId() != null) { _vpcMgr.unassignIPFromVpcNetwork(ipAddrId, currentNetworkId); } else { disassociatePortableIPToGuestNetwork(ipAddrId, currentNetworkId); } associatePortableIPToGuestNetwork(ipAddrId, newNetworkId, false); if (dstNetwork.getVpcId() != null) { ip.setVpcId(dstNetwork.getVpcId()); } else { ip.setVpcId(null); } _ipAddressDao.update(ipAddrId, ip); txn.commit(); ActionEventUtils.onActionEvent(User.UID_SYSTEM, Account.ACCOUNT_ID_SYSTEM, Domain.ROOT_DOMAIN, EventTypes.EVENT_PORTABLE_IP_TRANSFER, "Portable IP associated is transferred from network " + currentNetworkId + " to " + newNetworkId); } @Override @DB public boolean disassociatePublicIpAddress(long addrId, long userId, Account caller) { boolean success = true; // Cleanup all ip address resources - PF/LB/Static nat rules if (!cleanupIpResources(addrId, userId, caller)) { success = false; s_logger.warn("Failed to release resources for ip address id=" + addrId); } IPAddressVO ip = markIpAsUnavailable(addrId); assert (ip != null) : "Unable to mark the ip address id=" + addrId + " as unavailable."; if (ip == null) { return true; } if (s_logger.isDebugEnabled()) { s_logger.debug("Releasing ip id=" + addrId + "; sourceNat = " + ip.isSourceNat()); } 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 never get to here because we used true when applyIpAssociations", e); } } else { if (ip.getState() == IpAddress.State.Releasing) { _ipAddressDao.unassignIpAddress(ip.getId()); } } if (success) { if (ip.isPortable()) { releasePortableIpAddress(addrId); } s_logger.debug("Released a public ip id=" + addrId); } return success; } @DB private void releasePortableIpAddress(long addrId) { Transaction txn = Transaction.currentTxn(); GlobalLock portableIpLock = GlobalLock.getInternLock("PortablePublicIpRange"); txn.start(); try { portableIpLock.lock(5); IPAddressVO ip = _ipAddressDao.findById(addrId); // unassign portable IP PortableIpVO portableIp = _portableIpDao.findByIpAddress(ip.getAddress().addr()); _portableIpDao.unassignIpAddress(portableIp.getId()); // removed the provisioned vlan VlanVO vlan = _vlanDao.findById(ip.getVlanId()); _vlanDao.expunge(vlan.getId()); // remove the provisioned public ip address _ipAddressDao.expunge(ip.getId()); txn.commit(); } finally { portableIpLock.releaseRef(); } } @Override @DB public boolean configure(final String name, final Map params) throws ConfigurationException { _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); _networkLockTimeout = NumbersUtil.parseInt(_configs.get(Config.NetworkLockTimeout.key()), 600); // populate providers Map> defaultSharedNetworkOfferingProviders = new HashMap>(); Set defaultProviders = new HashSet(); defaultProviders.add(Network.Provider.VirtualRouter); defaultSharedNetworkOfferingProviders.put(Service.Dhcp, defaultProviders); defaultSharedNetworkOfferingProviders.put(Service.Dns, defaultProviders); defaultSharedNetworkOfferingProviders.put(Service.UserData, defaultProviders); Map> defaultIsolatedNetworkOfferingProviders = defaultSharedNetworkOfferingProviders; Map> defaultSharedSGEnabledNetworkOfferingProviders = new HashMap>(); defaultSharedSGEnabledNetworkOfferingProviders.put(Service.Dhcp, defaultProviders); defaultSharedSGEnabledNetworkOfferingProviders.put(Service.Dns, defaultProviders); defaultSharedSGEnabledNetworkOfferingProviders.put(Service.UserData, defaultProviders); Set sgProviders = new HashSet(); sgProviders.add(Provider.SecurityGroupProvider); defaultSharedSGEnabledNetworkOfferingProviders.put(Service.SecurityGroup, sgProviders); Map> defaultIsolatedSourceNatEnabledNetworkOfferingProviders = new HashMap>(); defaultProviders.clear(); defaultProviders.add(Network.Provider.VirtualRouter); defaultIsolatedSourceNatEnabledNetworkOfferingProviders.put(Service.Dhcp, defaultProviders); defaultIsolatedSourceNatEnabledNetworkOfferingProviders.put(Service.Dns, defaultProviders); defaultIsolatedSourceNatEnabledNetworkOfferingProviders.put(Service.UserData, defaultProviders); defaultIsolatedSourceNatEnabledNetworkOfferingProviders.put(Service.Firewall, defaultProviders); defaultIsolatedSourceNatEnabledNetworkOfferingProviders.put(Service.Gateway, defaultProviders); defaultIsolatedSourceNatEnabledNetworkOfferingProviders.put(Service.Lb, defaultProviders); defaultIsolatedSourceNatEnabledNetworkOfferingProviders.put(Service.SourceNat, defaultProviders); defaultIsolatedSourceNatEnabledNetworkOfferingProviders.put(Service.StaticNat, defaultProviders); defaultIsolatedSourceNatEnabledNetworkOfferingProviders.put(Service.PortForwarding, defaultProviders); defaultIsolatedSourceNatEnabledNetworkOfferingProviders.put(Service.Vpn, defaultProviders); Map> defaultVPCOffProviders = new HashMap>(); defaultProviders.clear(); defaultProviders.add(Network.Provider.VirtualRouter); defaultVPCOffProviders.put(Service.Dhcp, defaultProviders); defaultVPCOffProviders.put(Service.Dns, defaultProviders); defaultVPCOffProviders.put(Service.UserData, defaultProviders); defaultVPCOffProviders.put(Service.NetworkACL, defaultProviders); defaultVPCOffProviders.put(Service.Gateway, defaultProviders); defaultVPCOffProviders.put(Service.Lb, defaultProviders); defaultVPCOffProviders.put(Service.SourceNat, defaultProviders); defaultVPCOffProviders.put(Service.StaticNat, defaultProviders); defaultVPCOffProviders.put(Service.PortForwarding, defaultProviders); defaultVPCOffProviders.put(Service.Vpn, defaultProviders); Transaction txn = Transaction.currentTxn(); txn.start(); // diff between offering #1 and #2 - securityGroup is enabled for the first, and disabled for the third NetworkOfferingVO offering = null; if (_networkOfferingDao.findByUniqueName(NetworkOffering.QuickCloudNoServices) == null) { offering = _configMgr.createNetworkOffering(NetworkOffering.QuickCloudNoServices, "Offering for QuickCloud with no services", TrafficType.Guest, null, true, Availability.Optional, null, new HashMap>(), true, Network.GuestType.Shared, false, null, true, null, true, false, null); offering.setState(NetworkOffering.State.Enabled); _networkOfferingDao.update(offering.getId(), offering); } if (_networkOfferingDao.findByUniqueName(NetworkOffering.DefaultSharedNetworkOfferingWithSGService) == null) { offering = _configMgr.createNetworkOffering(NetworkOffering.DefaultSharedNetworkOfferingWithSGService, "Offering for Shared Security group enabled networks", TrafficType.Guest, null, true, Availability.Optional, null, defaultSharedNetworkOfferingProviders, true, Network.GuestType.Shared, false, null, true, null, true, false, null); offering.setState(NetworkOffering.State.Enabled); _networkOfferingDao.update(offering.getId(), offering); } if (_networkOfferingDao.findByUniqueName(NetworkOffering.DefaultSharedNetworkOffering) == null) { offering = _configMgr.createNetworkOffering(NetworkOffering.DefaultSharedNetworkOffering, "Offering for Shared networks", TrafficType.Guest, null, true, Availability.Optional, null, defaultSharedNetworkOfferingProviders, true, Network.GuestType.Shared, false, null, true, null, true, false, null); offering.setState(NetworkOffering.State.Enabled); _networkOfferingDao.update(offering.getId(), offering); } Map> defaultINetworkOfferingProvidersForVpcNetwork = new HashMap>(); defaultProviders.clear(); defaultProviders.add(Network.Provider.VPCVirtualRouter); defaultINetworkOfferingProvidersForVpcNetwork.put(Service.Dhcp, defaultProviders); defaultINetworkOfferingProvidersForVpcNetwork.put(Service.Dns, defaultProviders); defaultINetworkOfferingProvidersForVpcNetwork.put(Service.UserData, defaultProviders); defaultINetworkOfferingProvidersForVpcNetwork.put(Service.Firewall, defaultProviders); defaultINetworkOfferingProvidersForVpcNetwork.put(Service.Gateway, defaultProviders); defaultINetworkOfferingProvidersForVpcNetwork.put(Service.Lb, defaultProviders); defaultINetworkOfferingProvidersForVpcNetwork.put(Service.SourceNat, defaultProviders); defaultINetworkOfferingProvidersForVpcNetwork.put(Service.StaticNat, defaultProviders); defaultINetworkOfferingProvidersForVpcNetwork.put(Service.PortForwarding, defaultProviders); defaultINetworkOfferingProvidersForVpcNetwork.put(Service.Vpn, defaultProviders); if (_networkOfferingDao.findByUniqueName(NetworkOffering.DefaultIsolatedNetworkOfferingWithSourceNatService) == null) { offering = _configMgr.createNetworkOffering(NetworkOffering.DefaultIsolatedNetworkOfferingWithSourceNatService, "Offering for Isolated networks with Source Nat service enabled", TrafficType.Guest, null, false, Availability.Required, null, defaultINetworkOfferingProvidersForVpcNetwork, true, Network.GuestType.Isolated, false, null, true, null, false, false, null); offering.setState(NetworkOffering.State.Enabled); _networkOfferingDao.update(offering.getId(), offering); } if (_networkOfferingDao.findByUniqueName(NetworkOffering.DefaultIsolatedNetworkOfferingForVpcNetworks) == null) { offering = _configMgr.createNetworkOffering(NetworkOffering.DefaultIsolatedNetworkOfferingForVpcNetworks, "Offering for Isolated VPC networks with Source Nat service enabled", TrafficType.Guest, null, false, Availability.Optional, null, defaultVPCOffProviders, true, Network.GuestType.Isolated, false, null, false, null, false, false, null); offering.setState(NetworkOffering.State.Enabled); _networkOfferingDao.update(offering.getId(), offering); } if (_networkOfferingDao.findByUniqueName(NetworkOffering.DefaultIsolatedNetworkOfferingForVpcNetworksNoLB) == null) { //remove LB service defaultVPCOffProviders.remove(Service.Lb); offering = _configMgr.createNetworkOffering(NetworkOffering.DefaultIsolatedNetworkOfferingForVpcNetworksNoLB, "Offering for Isolated VPC networks with Source Nat service enabled and LB service disabled", TrafficType.Guest, null, false, Availability.Optional, null, defaultVPCOffProviders, true, Network.GuestType.Isolated, false, null, false, null, false, false, null); offering.setState(NetworkOffering.State.Enabled); _networkOfferingDao.update(offering.getId(), offering); } if (_networkOfferingDao.findByUniqueName(NetworkOffering.DefaultIsolatedNetworkOffering) == null) { offering = _configMgr.createNetworkOffering(NetworkOffering.DefaultIsolatedNetworkOffering, "Offering for Isolated networks with no Source Nat service", TrafficType.Guest, null, true, Availability.Optional, null, defaultIsolatedNetworkOfferingProviders, true, Network.GuestType.Isolated, false, null, true, null, true, false, null); offering.setState(NetworkOffering.State.Enabled); _networkOfferingDao.update(offering.getId(), offering); } Map> netscalerServiceProviders = new HashMap>(); Set vrProvider = new HashSet(); vrProvider.add(Provider.VirtualRouter); Set sgProvider = new HashSet(); sgProvider.add(Provider.SecurityGroupProvider); Set nsProvider = new HashSet(); nsProvider.add(Provider.Netscaler); netscalerServiceProviders.put(Service.Dhcp, vrProvider); netscalerServiceProviders.put(Service.Dns, vrProvider); netscalerServiceProviders.put(Service.UserData, vrProvider); netscalerServiceProviders.put(Service.SecurityGroup, sgProvider); netscalerServiceProviders.put(Service.StaticNat, nsProvider); netscalerServiceProviders.put(Service.Lb, nsProvider); Map> serviceCapabilityMap = new HashMap>(); Map elb = new HashMap(); elb.put(Capability.ElasticLb, "true"); Map eip = new HashMap(); eip.put(Capability.ElasticIp, "true"); serviceCapabilityMap.put(Service.Lb, elb); serviceCapabilityMap.put(Service.StaticNat, eip); if (_networkOfferingDao.findByUniqueName(NetworkOffering.DefaultSharedEIPandELBNetworkOffering) == null) { offering = _configMgr.createNetworkOffering(NetworkOffering.DefaultSharedEIPandELBNetworkOffering, "Offering for Shared networks with Elastic IP and Elastic LB capabilities", TrafficType.Guest, null, true, Availability.Optional, null, netscalerServiceProviders, true, Network.GuestType.Shared, false, null, true, serviceCapabilityMap, true, false, null); offering.setState(NetworkOffering.State.Enabled); offering.setDedicatedLB(false); _networkOfferingDao.update(offering.getId(), offering); } txn.commit(); 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.IN); SearchBuilder 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 podVlanSearch = _vlanDao.createSearchBuilder(); podVlanSearch.and("type", podVlanSearch.entity().getVlanType(), Op.EQ); podVlanSearch.and("networkId", podVlanSearch.entity().getNetworkId(), Op.EQ); SearchBuilder 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(); _executor = Executors.newScheduledThreadPool(1, new NamedThreadFactory("Network-Scavenger")); _agentMgr.registerForHostEvents(this, true, false, true); Network.State.getStateMachine().registerListener(new NetworkStateListener(_usageEventDao, _networksDao)); s_logger.info("Network Manager is configured."); return true; } @Override public boolean start() { _executor.scheduleWithFixedDelay(new NetworkGarbageCollector(), _networkGcInterval, _networkGcInterval, TimeUnit.SECONDS); return true; } @Override public boolean stop() { return true; } protected NetworkManagerImpl() { setStateMachine(); } @Override public List setupNetwork(Account owner, NetworkOffering offering, DeploymentPlan plan, String name, String displayText, boolean isDefault) throws ConcurrentOperationException { return setupNetwork(owner, offering, null, plan, name, displayText, false, null, null, null, null, true); } @Override @DB public List setupNetwork(Account owner, NetworkOffering offering, Network predefined, DeploymentPlan plan, String name, String displayText, boolean errorIfAlreadySetup, Long domainId, ACLType aclType, Boolean subdomainAccess, Long vpcId, Boolean isDisplayNetworkEnabled) throws ConcurrentOperationException { Account locked = _accountDao.acquireInLockTable(owner.getId()); if (locked == null) { throw new ConcurrentOperationException("Unable to acquire lock on " + owner); } try { if (predefined == null || (offering.getTrafficType() != TrafficType.Guest && predefined.getCidr() == null && predefined.getBroadcastUri() == null && !(predefined.getBroadcastDomainType() == BroadcastDomainType.Vlan || predefined.getBroadcastDomainType() == BroadcastDomainType.Lswitch))) { List 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)); } if (errorIfAlreadySetup) { InvalidParameterValueException ex = new InvalidParameterValueException("Found existing network configuration (with specified id) for offering (with specified id)"); ex.addProxyObject(offering, offering.getId(), "offeringId"); ex.addProxyObject(configs.get(0), configs.get(0).getId(), "networkConfigId"); throw ex; } else { return configs; } } } else if (predefined != null && predefined.getCidr() != null && predefined.getBroadcastUri() == null && vpcId == null) { // don't allow to have 2 networks with the same cidr in the same zone for the account List configs = _networksDao.listBy(owner.getId(), plan.getDataCenterId(), predefined.getCidr(), true); if (configs.size() > 0) { if (s_logger.isDebugEnabled()) { s_logger.debug("Found existing network configuration for offering " + offering + ": " + configs.get(0)); } if (errorIfAlreadySetup) { InvalidParameterValueException ex = new InvalidParameterValueException("Found existing network configuration (with specified id) for offering (with specified id)"); ex.addProxyObject(offering, offering.getId(), "offeringId"); ex.addProxyObject(configs.get(0), configs.get(0).getId(), "networkConfigId"); throw ex; } else { return configs; } } } List networks = new ArrayList(); long related = -1; for (NetworkGuru guru : _networkGurus) { Network network = guru.design(offering, plan, predefined, owner); if (network == null) { continue; } if (network.getId() != -1) { if (network instanceof NetworkVO) { networks.add((NetworkVO) network); } else { networks.add(_networksDao.findById(network.getId())); } continue; } long id = _networksDao.getNextInSequence(Long.class, "id"); if (related == -1) { related = id; } Transaction txn = Transaction.currentTxn(); txn.start(); NetworkVO vo = new NetworkVO(id, network, offering.getId(), guru.getName(), owner.getDomainId(), owner.getId(), related, name, displayText, predefined.getNetworkDomain(), offering.getGuestType(), plan.getDataCenterId(), plan.getPhysicalNetworkId(), aclType, offering.getSpecifyIpRanges(), vpcId); vo.setDisplayNetwork(isDisplayNetworkEnabled == null ? true : isDisplayNetworkEnabled); networks.add(_networksDao.persist(vo, vo.getGuestType() == Network.GuestType.Isolated, finalizeServicesAndProvidersForNetwork(offering, plan.getPhysicalNetworkId()))); if (domainId != null && aclType == ACLType.Domain) { _networksDao.addDomainToNetwork(id, domainId, subdomainAccess); } txn.commit(); } if (networks.size() < 1) { // see networkOfferingVO.java CloudRuntimeException ex = new CloudRuntimeException("Unable to convert network offering with specified id to network profile"); ex.addProxyObject(offering, offering.getId(), "offeringId"); throw ex; } return networks; } finally { s_logger.debug("Releasing lock for " + locked); _accountDao.releaseFromLockTable(locked.getId()); } } @Override @DB public void allocate(VirtualMachineProfile vm, List> networks) throws InsufficientCapacityException, ConcurrentOperationException { Transaction txn = Transaction.currentTxn(); txn.start(); int deviceId = 0; boolean[] deviceIds = new boolean[networks.size()]; Arrays.fill(deviceIds, false); List nics = new ArrayList(networks.size()); NicProfile defaultNic = null; for (Pair network : networks) { NetworkVO config = network.first(); NicProfile requested = network.second(); Boolean isDefaultNic = false; if (vm != null && (requested != null && requested.isDefaultNic())) { isDefaultNic = true; } while (deviceIds[deviceId] && deviceId < deviceIds.length) { deviceId++; } Pair vmNicPair = allocateNic(requested, config, isDefaultNic, deviceId, vm); NicProfile vmNic = vmNicPair.first(); if (vmNic == null) { continue; } deviceId = vmNicPair.second(); int devId = vmNic.getDeviceId(); if (devId > deviceIds.length) { throw new IllegalArgumentException("Device id for nic is too large: " + vmNic); } if (deviceIds[devId]) { throw new IllegalArgumentException("Conflicting device id for two different nics: " + vmNic); } deviceIds[devId] = true; if (vmNic.isDefaultNic()) { if (defaultNic != null) { throw new IllegalArgumentException("You cannot specify two nics as default nics: nic 1 = " + defaultNic + "; nic 2 = " + vmNic); } defaultNic = vmNic; } nics.add(vmNic); vm.addNic(vmNic); } if (nics.size() != networks.size()) { s_logger.warn("Number of nics " + nics.size() + " doesn't match number of requested networks " + networks.size()); throw new CloudRuntimeException("Number of nics " + nics.size() + " doesn't match number of requested networks " + networks.size()); } if (nics.size() == 1) { nics.get(0).setDefaultNic(true); } txn.commit(); } @DB @Override public Pair allocateNic(NicProfile requested, Network network, Boolean isDefaultNic, int deviceId, VirtualMachineProfile vm) throws InsufficientVirtualNetworkCapcityException, InsufficientAddressCapacityException, ConcurrentOperationException{ NetworkVO ntwkVO = _networksDao.findById(network.getId()); s_logger.debug("Allocating nic for vm " + vm.getVirtualMachine() + " in network " + network + " with requested profile " + requested); NetworkGuru guru = AdapterBase.getAdapterByName(_networkGurus, ntwkVO.getGuruName()); if (requested != null && requested.getMode() == null) { requested.setMode(network.getMode()); } NicProfile profile = guru.allocate(network, requested, vm); if (isDefaultNic != null) { profile.setDefaultNic(isDefaultNic); } if (profile == null) { return null; } if (requested != null && requested.getMode() == null) { profile.setMode(requested.getMode()); } else { profile.setMode(network.getMode()); } NicVO vo = new NicVO(guru.getName(), vm.getId(), network.getId(), vm.getType()); deviceId = applyProfileToNic(vo, profile, deviceId); vo = _nicDao.persist(vo); Integer networkRate = _networkModel.getNetworkRate(network.getId(), vm.getId()); NicProfile vmNic = new NicProfile(vo, network, vo.getBroadcastUri(), vo.getIsolationUri(), networkRate, _networkModel.isSecurityGroupSupportedInNetwork(network), _networkModel.getNetworkTag(vm.getHypervisorType(), network)); return new Pair(vmNic, Integer.valueOf(deviceId)); } protected Integer applyProfileToNic(NicVO vo, NicProfile profile, Integer deviceId) { if (profile.getDeviceId() != null) { vo.setDeviceId(profile.getDeviceId()); } else if (deviceId != null) { vo.setDeviceId(deviceId++); } if (profile.getReservationStrategy() != null) { vo.setReservationStrategy(profile.getReservationStrategy()); } vo.setDefaultNic(profile.isDefaultNic()); vo.setIp4Address(profile.getIp4Address()); vo.setAddressFormat(profile.getFormat()); 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); vo.setIp6Address(profile.getIp6Address()); vo.setIp6Gateway(profile.getIp6Gateway()); vo.setIp6Cidr(profile.getIp6Cidr()); 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()); if (profile.getReservationStrategy() != null) { vo.setReservationStrategy(profile.getReservationStrategy()); } vo.setBroadcastUri(profile.getBroadCastUri()); vo.setIsolationUri(profile.getIsolationUri()); vo.setNetmask(profile.getNetmask()); } protected void applyProfileToNetwork(NetworkVO network, NetworkProfile profile) { network.setBroadcastUri(profile.getBroadcastUri()); network.setDns1(profile.getDns1()); network.setDns2(profile.getDns2()); network.setPhysicalNetworkId(profile.getPhysicalNetworkId()); } 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 = _networkModel.getNetworkRate(config.getId(), null); to.setNetworkRateMbps(networkRate); to.setUuid(config.getUuid()); return to; } @Override @DB public Pair implementNetwork(long networkId, DeployDestination dest, ReservationContext context) throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException { Transaction.currentTxn(); Pair implemented = new Pair(null, null); NetworkVO network = _networksDao.acquireInLockTable(networkId, _networkLockTimeout); if (network == null) { // see NetworkVO.java ConcurrentOperationException ex = new ConcurrentOperationException("Unable to acquire network configuration"); ex.addProxyObject(ApiDBUtils.findNetworkById(networkId).getUuid()); throw ex; } if (s_logger.isDebugEnabled()) { s_logger.debug("Lock is acquired for network id " + networkId + " as a part of network implement"); } try { NetworkGuru guru = AdapterBase.getAdapterByName(_networkGurus, network.getGuruName()); Network.State state = network.getState(); if (state == Network.State.Implemented || state == Network.State.Implementing) { s_logger.debug("Network id=" + networkId + " is already implemented"); implemented.set(guru, network); return implemented; } if (state == Network.State.Setup) { DataCenterVO zone = _dcDao.findById(network.getDataCenterId()); if (!isSharedNetworkOfferingWithServices(network.getNetworkOfferingId()) || (zone.getNetworkType() == NetworkType.Basic)) { s_logger.debug("Network id=" + networkId + " is already implemented"); implemented.set(guru, network); return implemented; } } if (s_logger.isDebugEnabled()) { s_logger.debug("Asking " + guru.getName() + " to implement " + network); } NetworkOfferingVO offering = _networkOfferingDao.findById(network.getNetworkOfferingId()); network.setReservationId(context.getReservationId()); if (isSharedNetworkWithServices(network)) { network.setState(Network.State.Implementing); } else { stateTransitTo(network, Event.ImplementNetwork); } Network result = guru.implement(network, offering, dest, context); network.setCidr(result.getCidr()); network.setBroadcastUri(result.getBroadcastUri()); network.setGateway(result.getGateway()); network.setMode(result.getMode()); network.setPhysicalNetworkId(result.getPhysicalNetworkId()); _networksDao.update(networkId, network); // implement network elements and re-apply all the network rules implementNetworkElementsAndResources(dest, context, network, offering); if (isSharedNetworkWithServices(network)) { network.setState(Network.State.Implemented); } else { stateTransitTo(network,Event.OperationSucceeded); } network.setRestartRequired(false); _networksDao.update(network.getId(), network); implemented.set(guru, network); return implemented; } catch (NoTransitionException e) { s_logger.error(e.getMessage()); return null; } finally { if (implemented.first() == null) { s_logger.debug("Cleaning up because we're unable to implement the network " + network); try { if (isSharedNetworkWithServices(network)) { network.setState(Network.State.Shutdown); _networksDao.update(networkId, network); } else { stateTransitTo(network,Event.OperationFailed); } } catch (NoTransitionException e) { s_logger.error(e.getMessage()); } shutdownNetwork(networkId, context, false); } _networksDao.releaseFromLockTable(networkId); if (s_logger.isDebugEnabled()) { s_logger.debug("Lock is released for network id " + networkId + " as a part of network implement"); } } } @Override public boolean equals(Object o) { return super.equals(o); //To change body of overridden methods use File | Settings | File Templates. } @Override public void implementNetworkElementsAndResources(DeployDestination dest, ReservationContext context, NetworkVO network, NetworkOfferingVO offering) throws ConcurrentOperationException, InsufficientAddressCapacityException, ResourceUnavailableException, InsufficientCapacityException { // Associate a source NAT IP (if one isn't already associated with the network) if this is a // 1) 'Isolated' or 'Shared' guest virtual network in the advance zone // 2) network has sourceNat service // 3) network offering does not support a shared source NAT rule boolean sharedSourceNat = offering.getSharedSourceNat(); DataCenter zone = _dcDao.findById(network.getDataCenterId()); if (!sharedSourceNat && _networkModel.areServicesSupportedInNetwork(network.getId(), Service.SourceNat) && (network.getGuestType() == Network.GuestType.Isolated || (network.getGuestType() == Network.GuestType.Shared && zone.getNetworkType() == NetworkType.Advanced))) { List ips = null; if (network.getVpcId() != null) { ips = _ipAddressDao.listByAssociatedVpc(network.getVpcId(), true); if (ips.isEmpty()) { throw new CloudRuntimeException("Vpc is not implemented; there is no source nat ip"); } } else { ips = _ipAddressDao.listByAssociatedNetwork(network.getId(), true); } if (ips.isEmpty()) { s_logger.debug("Creating a source nat ip for network " + network); Account owner = _accountMgr.getAccount(network.getAccountId()); assignSourceNatIpAddressToGuestNetwork(owner, network); } } // get providers to implement List providersToImplement = getNetworkProviders(network.getId()); for (NetworkElement element : _networkElements) { if (providersToImplement.contains(element.getProvider())) { if (!_networkModel.isProviderEnabledInPhysicalNetwork(_networkModel.getPhysicalNetworkId(network), element.getProvider().getName())) { // The physicalNetworkId will not get translated into a uuid by the reponse serializer, // because the serializer would look up the NetworkVO class's table and retrieve the // network id instead of the physical network id. // So just throw this exception as is. We may need to TBD by changing the serializer. throw new CloudRuntimeException("Service provider " + element.getProvider().getName() + " either doesn't exist or is not enabled in physical network id: " + network.getPhysicalNetworkId()); } if (s_logger.isDebugEnabled()) { s_logger.debug("Asking " + element.getName() + " to implemenet " + network); } if (!element.implement(network, offering, dest, context)) { CloudRuntimeException ex = new CloudRuntimeException("Failed to implement provider " + element.getProvider().getName() + " for network with specified id"); ex.addProxyObject(network, network.getId(), "networkId"); throw ex; } } } // reapply all the firewall/staticNat/lb rules s_logger.debug("Reprogramming network " + network + " as a part of network implement"); if (!reprogramNetworkRules(network.getId(), UserContext.current().getCaller(), network)) { s_logger.warn("Failed to re-program the network as a part of network " + network + " implement"); // see DataCenterVO.java ResourceUnavailableException ex = new ResourceUnavailableException("Unable to apply network rules as a part of network " + network + " implement", DataCenter.class, network.getDataCenterId()); ex.addProxyObject(ApiDBUtils.findZoneById(network.getDataCenterId()).getUuid()); throw ex; } } protected boolean prepareElement(NetworkElement element, NetworkVO network, NicProfile profile, VirtualMachineProfile vmProfile, DeployDestination dest, ReservationContext context) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException { element.prepare(network, profile, vmProfile, dest, context); if (vmProfile.getType() == Type.User && element.getProvider() != null) { if (_networkModel.areServicesSupportedInNetwork(network.getId(), Service.Dhcp) && _networkModel.isProviderSupportServiceInNetwork(network.getId(), Service.Dhcp, element.getProvider()) && element instanceof DhcpServiceProvider) { DhcpServiceProvider sp = (DhcpServiceProvider) element; if (!sp.configDhcpSupportForSubnet(network, profile, vmProfile, dest, context)) { return false; } sp.addDhcpEntry(network, profile, vmProfile, dest, context); } if (_networkModel.areServicesSupportedInNetwork(network.getId(), Service.UserData) && _networkModel.isProviderSupportServiceInNetwork(network.getId(), Service.UserData, element.getProvider()) && element instanceof UserDataServiceProvider) { UserDataServiceProvider sp = (UserDataServiceProvider) element; sp.addPasswordAndUserdata(network, profile, vmProfile, dest, context); } } return true; } @DB protected void updateNic(NicVO nic, long networkId, int count) { Transaction txn = Transaction.currentTxn(); txn.start(); _nicDao.update(nic.getId(), nic); if (nic.getVmType() == VirtualMachine.Type.User) { s_logger.debug("Changing active number of nics for network id=" + networkId + " on " + count); _networksDao.changeActiveNicsBy(networkId, count); } if (nic.getVmType() == VirtualMachine.Type.User || (nic.getVmType() == VirtualMachine.Type.DomainRouter && _networksDao.findById(networkId).getTrafficType() == TrafficType.Guest)) { _networksDao.setCheckForGc(networkId); } txn.commit(); } @Override public void prepare(VirtualMachineProfile vmProfile, DeployDestination dest, ReservationContext context) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException { List nics = _nicDao.listByVmId(vmProfile.getId()); // we have to implement default nics first - to ensure that default network elements start up first in multiple //nics case // (need for setting DNS on Dhcp to domR's Ip4 address) Collections.sort(nics, new Comparator() { @Override public int compare(NicVO nic1, NicVO nic2) { boolean isDefault1 = nic1.isDefaultNic(); boolean isDefault2 = nic2.isDefaultNic(); return (isDefault1 ^ isDefault2) ? ((isDefault1 ^ true) ? 1 : -1) : 0; } }); for (NicVO nic : nics) { Pair implemented = implementNetwork(nic.getNetworkId(), dest, context); NetworkVO network = implemented.second(); NicProfile profile = prepareNic(vmProfile, dest, context, nic.getId(), network); vmProfile.addNic(profile); } } @Override public NicProfile prepareNic(VirtualMachineProfile vmProfile, DeployDestination dest, ReservationContext context, long nicId, NetworkVO network) throws InsufficientVirtualNetworkCapcityException, InsufficientAddressCapacityException, ConcurrentOperationException, InsufficientCapacityException, ResourceUnavailableException { Integer networkRate = _networkModel.getNetworkRate(network.getId(), vmProfile.getId()); NetworkGuru guru = AdapterBase.getAdapterByName(_networkGurus, network.getGuruName()); NicVO nic = _nicDao.findById(nicId); 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, _networkModel.isSecurityGroupSupportedInNetwork(network), _networkModel.getNetworkTag(vmProfile.getHypervisorType(), network)); guru.reserve(profile, network, vmProfile, dest, context); nic.setIp4Address(profile.getIp4Address()); nic.setAddressFormat(profile.getFormat()); nic.setIp6Address(profile.getIp6Address()); nic.setMacAddress(profile.getMacAddress()); nic.setIsolationUri(profile.getIsolationUri()); nic.setBroadcastUri(profile.getBroadCastUri()); nic.setReserver(guru.getName()); nic.setState(Nic.State.Reserved); nic.setNetmask(profile.getNetmask()); nic.setGateway(profile.getGateway()); if (profile.getStrategy() != null) { nic.setReservationStrategy(profile.getStrategy()); } updateNic(nic, network.getId(), 1); } else { profile = new NicProfile(nic, network, nic.getBroadcastUri(), nic.getIsolationUri(), networkRate, _networkModel.isSecurityGroupSupportedInNetwork(network), _networkModel.getNetworkTag(vmProfile.getHypervisorType(), network)); guru.updateNicProfile(profile, network); 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); } if(!prepareElement(element, network, profile, vmProfile, dest, context)) { throw new InsufficientAddressCapacityException("unable to configure the dhcp service, due to insufficiant address capacity",Network.class, network.getId()); } } profile.setSecurityGroupEnabled(_networkModel.isSecurityGroupSupportedInNetwork(network)); guru.updateNicProfile(profile, network); return profile; } @Override public void prepareNicForMigration(VirtualMachineProfile vm, DeployDestination dest) { List nics = _nicDao.listByVmId(vm.getId()); ReservationContext context = new ReservationContextImpl(UUID.randomUUID().toString(), null, null); for (NicVO nic : nics) { NetworkVO network = _networksDao.findById(nic.getNetworkId()); Integer networkRate = _networkModel.getNetworkRate(network.getId(), vm.getId()); NetworkGuru guru = AdapterBase.getAdapterByName(_networkGurus, network.getGuruName()); NicProfile profile = new NicProfile(nic, network, nic.getBroadcastUri(), nic.getIsolationUri(), networkRate, _networkModel.isSecurityGroupSupportedInNetwork(network), _networkModel.getNetworkTag(vm.getHypervisorType(), network)); if(guru instanceof NetworkMigrationResponder){ if(!((NetworkMigrationResponder) guru).prepareMigration(profile, network, vm, dest, context)){ s_logger.error("NetworkGuru "+guru+" prepareForMigration failed."); // XXX: Transaction error } } for (NetworkElement element : _networkElements) { if(element instanceof NetworkMigrationResponder){ if(!((NetworkMigrationResponder) element).prepareMigration(profile, network, vm, dest, context)){ s_logger.error("NetworkElement "+element+" prepareForMigration failed."); // XXX: Transaction error } } } guru.updateNicProfile(profile, network); vm.addNic(profile); } } private NicProfile findNicProfileById(VirtualMachineProfile vm, long id){ for(NicProfile nic: vm.getNics()){ if(nic.getId() == id){ return nic; } } return null; } @Override public void commitNicForMigration( VirtualMachineProfile src, VirtualMachineProfile dst) { for(NicProfile nicSrc: src.getNics()){ NetworkVO network = _networksDao.findById(nicSrc.getNetworkId()); NetworkGuru guru = AdapterBase.getAdapterByName(_networkGurus, network.getGuruName()); NicProfile nicDst = findNicProfileById(dst, nicSrc.getId()); ReservationContext src_context = new ReservationContextImpl(nicSrc.getReservationId(), null, null); ReservationContext dst_context = new ReservationContextImpl(nicDst.getReservationId(), null, null); if(guru instanceof NetworkMigrationResponder){ ((NetworkMigrationResponder) guru).commitMigration(nicSrc, network, src, src_context, dst_context); } for (NetworkElement element : _networkElements) { if(element instanceof NetworkMigrationResponder){ ((NetworkMigrationResponder) element).commitMigration(nicSrc, network, src, src_context, dst_context); } } // update the reservation id NicVO nicVo = _nicDao.findById(nicDst.getId()); nicVo.setReservationId(nicDst.getReservationId()); _nicDao.persist(nicVo); } } @Override public void rollbackNicForMigration( VirtualMachineProfile src, VirtualMachineProfile dst) { for(NicProfile nicDst: dst.getNics()){ NetworkVO network = _networksDao.findById(nicDst.getNetworkId()); NetworkGuru guru = AdapterBase.getAdapterByName(_networkGurus, network.getGuruName()); NicProfile nicSrc = findNicProfileById(src, nicDst.getId()); ReservationContext src_context = new ReservationContextImpl(nicSrc.getReservationId(), null, null); ReservationContext dst_context = new ReservationContextImpl(nicDst.getReservationId(), null, null); if(guru instanceof NetworkMigrationResponder){ ((NetworkMigrationResponder) guru).rollbackMigration(nicDst, network, dst, src_context, dst_context); } for (NetworkElement element : _networkElements) { if(element instanceof NetworkMigrationResponder){ ((NetworkMigrationResponder) element).rollbackMigration(nicDst, network, dst, src_context, dst_context); } } } } @Override @DB public void release(VirtualMachineProfile vmProfile, boolean forced) throws ConcurrentOperationException, ResourceUnavailableException { List nics = _nicDao.listByVmId(vmProfile.getId()); for (NicVO nic : nics) { releaseNic(vmProfile, nic); } } @Override @DB public void releaseNic(VirtualMachineProfile vmProfile, Nic nic) throws ConcurrentOperationException, ResourceUnavailableException { NicVO nicVO = _nicDao.findById(nic.getId()); releaseNic(vmProfile, nicVO); } @DB protected void releaseNic(VirtualMachineProfile vmProfile, NicVO nicVO) throws ConcurrentOperationException, ResourceUnavailableException { //lock the nic Transaction txn = Transaction.currentTxn(); txn.start(); NicVO nic = _nicDao.lockRow(nicVO.getId(), true); if (nic == null) { throw new ConcurrentOperationException("Unable to acquire lock on nic " + nic); } Nic.State originalState = nic.getState(); NetworkVO network = _networksDao.findById(nicVO.getNetworkId()); if (originalState == Nic.State.Reserved || originalState == Nic.State.Reserving) { if (nic.getReservationStrategy() == Nic.ReservationStrategy.Start) { NetworkGuru guru = AdapterBase.getAdapterByName(_networkGurus, network.getGuruName()); nic.setState(Nic.State.Releasing); _nicDao.update(nic.getId(), nic); NicProfile profile = new NicProfile(nic, network, nic.getBroadcastUri(), nic.getIsolationUri(), null, _networkModel.isSecurityGroupSupportedInNetwork(network), _networkModel.getNetworkTag(vmProfile.getHypervisorType(), network)); if (guru.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); } } //commit the transaction before proceeding releasing nic profile on the network elements txn.commit(); // Perform release on network elements for (NetworkElement element : _networkElements) { if (s_logger.isDebugEnabled()) { s_logger.debug("Asking " + element.getName() + " to release " + nic); } //NOTE: Context appear to never be used in release method //implementations. Consider removing it from interface Element element.release(network, profile, vmProfile, null); } } else { nic.setState(Nic.State.Allocated); updateNic(nic, network.getId(), -1); txn.commit(); } } } @Override public void cleanupNics(VirtualMachineProfile vm) { if (s_logger.isDebugEnabled()) { s_logger.debug("Cleaning network for vm: " + vm.getId()); } List nics = _nicDao.listByVmId(vm.getId()); for (NicVO nic : nics) { removeNic(vm, nic); } } @Override public void removeNic(VirtualMachineProfile vm, Nic nic) { removeNic(vm, _nicDao.findById(nic.getId())); } protected void removeNic(VirtualMachineProfile vm, NicVO nic) { 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, _networkModel.isSecurityGroupSupportedInNetwork(network), _networkModel.getNetworkTag(vm.getHypervisorType(), network)); /* * We need to release the nics with a Create ReservationStrategy here * because the nic is now being removed. */ if (nic.getReservationStrategy() == Nic.ReservationStrategy.Create) { for (NetworkElement element : _networkElements) { if (s_logger.isDebugEnabled()) { s_logger.debug("Asking " + element.getName() + " to release " + nic); } try { element.release(network, profile, vm, null); } catch (ConcurrentOperationException ex) { s_logger.warn("release failed during the nic " + nic.toString() + " removeNic due to ", ex); } catch (ResourceUnavailableException ex) { s_logger.warn("release failed during the nic " + nic.toString() + " removeNic due to ", ex); } } } NetworkGuru guru = AdapterBase.getAdapterByName(_networkGurus, network.getGuruName()); guru.deallocate(network, profile, vm); _nicDao.remove(nic.getId()); s_logger.debug("Removed nic id=" + nic.getId()); //remove the secondary ip addresses corresponding to to this nic if (!removeVmSecondaryIpsOfNic(nic.getId())) { s_logger.debug("Removing nic " + nic.getId() + " secondary ip addreses failed"); } } @Override public void expungeNics(VirtualMachineProfile vm) { List nics = _nicDao.listByVmIdIncludingRemoved(vm.getId()); for (NicVO nic : nics) { _nicDao.expunge(nic.getId()); } } @Override @DB public Network createGuestNetwork(long networkOfferingId, String name, String displayText, String gateway, String cidr, String vlanId, String networkDomain, Account owner, Long domainId, PhysicalNetwork pNtwk, long zoneId, ACLType aclType, Boolean subdomainAccess, Long vpcId, String ip6Gateway, String ip6Cidr, Boolean isDisplayNetworkEnabled, String isolatedPvlan) throws ConcurrentOperationException, InsufficientCapacityException, ResourceAllocationException { NetworkOfferingVO ntwkOff = _networkOfferingDao.findById(networkOfferingId); // this method supports only guest network creation if (ntwkOff.getTrafficType() != TrafficType.Guest) { s_logger.warn("Only guest networks can be created using this method"); return null; } boolean updateResourceCount = resourceCountNeedsUpdate(ntwkOff, aclType); //check resource limits if (updateResourceCount) { _resourceLimitMgr.checkResourceLimit(owner, ResourceType.network); } // Validate network offering if (ntwkOff.getState() != NetworkOffering.State.Enabled) { // see NetworkOfferingVO InvalidParameterValueException ex = new InvalidParameterValueException("Can't use specified network offering id as its stat is not " + NetworkOffering.State.Enabled); ex.addProxyObject(ntwkOff, ntwkOff.getId(), "networkOfferingId"); throw ex; } // Validate physical network if (pNtwk.getState() != PhysicalNetwork.State.Enabled) { // see PhysicalNetworkVO.java InvalidParameterValueException ex = new InvalidParameterValueException("Specified physical network id is" + " in incorrect state:" + pNtwk.getState()); ex.addProxyObject("physical_network", pNtwk.getId(), "physicalNetworkId"); throw ex; } boolean ipv6 = false; if (ip6Gateway != null && ip6Cidr != null) { ipv6 = true; } // Validate zone DataCenterVO zone = _dcDao.findById(zoneId); if (zone.getNetworkType() == NetworkType.Basic) { if (ipv6) { throw new InvalidParameterValueException("IPv6 is not supported in Basic zone"); } // In Basic zone the network should have aclType=Domain, domainId=1, subdomainAccess=true if (aclType == null || aclType != ACLType.Domain) { throw new InvalidParameterValueException("Only AclType=Domain can be specified for network creation in Basic zone"); } // Only one guest network is supported in Basic zone List guestNetworks = _networksDao.listByZoneAndTrafficType(zone.getId(), TrafficType.Guest); if (!guestNetworks.isEmpty()) { throw new InvalidParameterValueException("Can't have more than one Guest network in zone with network type " + NetworkType.Basic); } // if zone is basic, only Shared network offerings w/o source nat service are allowed if (!(ntwkOff.getGuestType() == GuestType.Shared && !_networkModel.areServicesSupportedByNetworkOffering(ntwkOff.getId(), Service.SourceNat))) { throw new InvalidParameterValueException("For zone of type " + NetworkType.Basic + " only offerings of " + "guestType " + GuestType.Shared + " with disabled " + Service.SourceNat.getName() + " service are allowed"); } if (domainId == null || domainId != Domain.ROOT_DOMAIN) { throw new InvalidParameterValueException("Guest network in Basic zone should be dedicated to ROOT domain"); } if (subdomainAccess == null) { subdomainAccess = true; } else if (!subdomainAccess) { throw new InvalidParameterValueException("Subdomain access should be set to true for the" + " guest network in the Basic zone"); } if (vlanId == null) { vlanId = Vlan.UNTAGGED; } else { if (!vlanId.equalsIgnoreCase(Vlan.UNTAGGED)) { throw new InvalidParameterValueException("Only vlan " + Vlan.UNTAGGED + " can be created in " + "the zone of type " + NetworkType.Basic); } } } else if (zone.getNetworkType() == NetworkType.Advanced) { if (zone.isSecurityGroupEnabled()) { if (ipv6) { throw new InvalidParameterValueException("IPv6 is not supported with security group!"); } if (isolatedPvlan != null) { throw new InvalidParameterValueException("Isolated Private VLAN is not supported with security group!"); } // Only Account specific Isolated network with sourceNat service disabled are allowed in security group // enabled zone if ( ntwkOff.getGuestType() != GuestType.Shared ){ throw new InvalidParameterValueException("Only shared guest network can be created in security group enabled zone"); } if ( _networkModel.areServicesSupportedByNetworkOffering(ntwkOff.getId(), Service.SourceNat)) { throw new InvalidParameterValueException("Service SourceNat is not allowed in security group enabled zone"); } if (!( _networkModel.areServicesSupportedByNetworkOffering(ntwkOff.getId(), Service.SecurityGroup))) { throw new InvalidParameterValueException("network must have SecurityGroup provider in security group enabled zone"); } } //don't allow eip/elb networks in Advance zone if (ntwkOff.getElasticIp() || ntwkOff.getElasticLb()) { throw new InvalidParameterValueException("Elastic IP and Elastic LB services are supported in zone of type " + NetworkType.Basic); } } // VlanId can be specified only when network offering supports it boolean vlanSpecified = (vlanId != null); if (vlanSpecified != ntwkOff.getSpecifyVlan()) { if (vlanSpecified) { throw new InvalidParameterValueException("Can't specify vlan; corresponding offering says specifyVlan=false"); } else { throw new InvalidParameterValueException("Vlan has to be specified; corresponding offering says specifyVlan=true"); } } if (vlanId != null) { String uri = "vlan://" + vlanId; // For Isolated networks, don't allow to create network with vlan that already exists in the zone if (ntwkOff.getGuestType() == GuestType.Isolated) { if (_networksDao.countByZoneAndUri(zoneId, uri) > 0) { throw new InvalidParameterValueException("Network with vlan " + vlanId + " already exists in zone " + zoneId); } else { List dcVnets = _datacenterVnetDao.findVnet(zoneId, vlanId.toString()); //for the network that is created as part of private gateway, //the vnet is not coming from the data center vnet table, so the list can be empty if (!dcVnets.isEmpty()) { DataCenterVnetVO dcVnet = dcVnets.get(0); // Fail network creation if specified vlan is dedicated to a different account if (dcVnet.getAccountGuestVlanMapId() != null) { Long accountGuestVlanMapId = dcVnet.getAccountGuestVlanMapId(); AccountGuestVlanMapVO map = _accountGuestVlanMapDao.findById(accountGuestVlanMapId); if (map.getAccountId() != owner.getAccountId()) { throw new InvalidParameterValueException("Vlan " + vlanId + " is dedicated to a different account"); } // Fail network creation if owner has a dedicated range of vlans but the specified vlan belongs to the system pool } else { List maps = _accountGuestVlanMapDao.listAccountGuestVlanMapsByAccount(owner.getAccountId()); if (maps != null && !maps.isEmpty()) { int vnetsAllocatedToAccount = _datacenterVnetDao.countVnetsAllocatedToAccount(zoneId, owner.getAccountId()); int vnetsDedicatedToAccount = _datacenterVnetDao.countVnetsDedicatedToAccount(zoneId, owner.getAccountId()); if (vnetsAllocatedToAccount < vnetsDedicatedToAccount) { throw new InvalidParameterValueException("Specified vlan " + vlanId + " doesn't belong" + " to the vlan range dedicated to the owner "+ owner.getAccountName()); } } } } } } else { // don't allow to creating shared network with given Vlan ID, if there already exists a isolated network or // shared network with same Vlan ID in the zone if (_networksDao.countByZoneUriAndGuestType(zoneId, uri, GuestType.Isolated) > 0 || _networksDao.countByZoneUriAndGuestType(zoneId, uri, GuestType.Shared) > 0) { throw new InvalidParameterValueException("There is a isolated/shared network with vlan id: " + vlanId + " already exists " + "in zone " + zoneId); } } } // If networkDomain is not specified, take it from the global configuration if (_networkModel.areServicesSupportedByNetworkOffering(networkOfferingId, Service.Dns)) { Map dnsCapabilities = _networkModel.getNetworkOfferingServiceCapabilities (_configMgr.getNetworkOffering(networkOfferingId), Service.Dns); String isUpdateDnsSupported = dnsCapabilities.get(Capability.AllowDnsSuffixModification); if (isUpdateDnsSupported == null || !Boolean.valueOf(isUpdateDnsSupported)) { if (networkDomain != null) { // TBD: NetworkOfferingId and zoneId. Send uuids instead. throw new InvalidParameterValueException("Domain name change is not supported by network offering id=" + networkOfferingId + " in zone id=" + zoneId); } } else { if (networkDomain == null) { // 1) Get networkDomain from the corresponding account/domain/zone if (aclType == ACLType.Domain) { networkDomain = _networkModel.getDomainNetworkDomain(domainId, zoneId); } else if (aclType == ACLType.Account) { networkDomain = _networkModel.getAccountNetworkDomain(owner.getId(), zoneId); } // 2) If null, generate networkDomain using domain suffix from the global config variables if (networkDomain == null) { networkDomain = "cs" + Long.toHexString(owner.getId()) + _configServer.getConfigValue(Config.GuestDomainSuffix.key(), Config.ConfigurationParameterScope.zone.toString(), zoneId); } } else { // validate network domain if (!NetUtils.verifyDomainName(networkDomain)) { throw new InvalidParameterValueException( "Invalid network domain. Total length shouldn't exceed 190 chars. Each domain " + "label must be between 1 and 63 characters long, can contain ASCII letters 'a' through 'z', the digits '0' through '9', " + "and the hyphen ('-'); can't start or end with \"-\""); } } } } // In Advance zone Cidr for Shared networks and Isolated networks w/o source nat service can't be NULL - 2.2.x // limitation, remove after we introduce support for multiple ip ranges // with different Cidrs for the same Shared network boolean cidrRequired = zone.getNetworkType() == NetworkType.Advanced && ntwkOff.getTrafficType() == TrafficType.Guest && (ntwkOff.getGuestType() == GuestType.Shared || (ntwkOff.getGuestType() == GuestType.Isolated && !_networkModel.areServicesSupportedByNetworkOffering(ntwkOff.getId(), Service.SourceNat))); if (cidr == null && ip6Cidr == null && cidrRequired) { throw new InvalidParameterValueException("StartIp/endIp/gateway/netmask are required when create network of" + " type " + Network.GuestType.Shared + " and network of type " + GuestType.Isolated + " with service " + Service.SourceNat.getName() + " disabled"); } // No cidr can be specified in Basic zone if (zone.getNetworkType() == NetworkType.Basic && cidr != null) { throw new InvalidParameterValueException("StartIp/endIp/gateway/netmask can't be specified for zone of type " + NetworkType.Basic); } // Check if cidr is RFC1918 compliant if the network is Guest Isolated for IPv4 if (cidr != null && ntwkOff.getGuestType() == Network.GuestType.Isolated && ntwkOff.getTrafficType() == TrafficType.Guest) { if (!NetUtils.validateGuestCidr(cidr)) { throw new InvalidParameterValueException("Virtual Guest Cidr " + cidr + " is not RFC1918 compliant"); } } Transaction txn = Transaction.currentTxn(); txn.start(); Long physicalNetworkId = null; if (pNtwk != null) { physicalNetworkId = pNtwk.getId(); } DataCenterDeployment plan = new DataCenterDeployment(zoneId, null, null, null, null, physicalNetworkId); NetworkVO userNetwork = new NetworkVO(); userNetwork.setNetworkDomain(networkDomain); if (cidr != null && gateway != null) { userNetwork.setCidr(cidr); userNetwork.setGateway(gateway); } if (ip6Cidr != null && ip6Gateway != null) { userNetwork.setIp6Cidr(ip6Cidr); userNetwork.setIp6Gateway(ip6Gateway); } if (vlanId != null) { if (isolatedPvlan == null) { userNetwork.setBroadcastUri(URI.create("vlan://" + vlanId)); if (!vlanId.equalsIgnoreCase(Vlan.UNTAGGED)) { userNetwork.setBroadcastDomainType(BroadcastDomainType.Vlan); } else { userNetwork.setBroadcastDomainType(BroadcastDomainType.Native); } } else { if (vlanId.equalsIgnoreCase(Vlan.UNTAGGED)) { throw new InvalidParameterValueException("Cannot support pvlan with untagged primary vlan!"); } userNetwork.setBroadcastUri(NetUtils.generateUriForPvlan(vlanId, isolatedPvlan)); userNetwork.setBroadcastDomainType(BroadcastDomainType.Pvlan); } } List networks = setupNetwork(owner, ntwkOff, userNetwork, plan, name, displayText, true, domainId, aclType, subdomainAccess, vpcId, isDisplayNetworkEnabled); 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() == Network.GuestType.Isolated && 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 { // For shared network network = networks.get(0); } } if (updateResourceCount) { _resourceLimitMgr.incrementResourceCount(owner.getId(), ResourceType.network); } txn.commit(); UserContext.current().setEventDetails("Network Id: " + network.getId()); return network; } @Override @DB public boolean shutdownNetwork(long networkId, ReservationContext context, boolean cleanupElements) { boolean result = false; Transaction txn = Transaction.currentTxn(); NetworkVO network = _networksDao.lockRow(networkId, true); if (network == null) { s_logger.debug("Unable to find network with id: " + networkId); return false; } if (network.getState() != Network.State.Implemented && network.getState() != Network.State.Shutdown) { s_logger.debug("Network is not implemented: " + network); return false; } txn.start(); if (isSharedNetworkWithServices(network)) { network.setState(Network.State.Shutdown); _networksDao.update(network.getId(), network); } else { try { stateTransitTo(network, Event.DestroyNetwork); } catch (NoTransitionException e) { network.setState(Network.State.Shutdown); _networksDao.update(network.getId(), network); } } txn.commit(); boolean success = shutdownNetworkElementsAndResources(context, cleanupElements, network); txn.start(); if (success) { if (s_logger.isDebugEnabled()) { s_logger.debug("Network id=" + networkId + " is shutdown successfully, cleaning up corresponding resources now."); } NetworkGuru guru = AdapterBase.getAdapterByName(_networkGurus, network.getGuruName()); NetworkProfile profile = convertNetworkToNetworkProfile(network.getId()); guru.shutdown(profile, _networkOfferingDao.findById(network.getNetworkOfferingId())); applyProfileToNetwork(network, profile); DataCenterVO zone = _dcDao.findById(network.getDataCenterId()); if (isSharedNetworkOfferingWithServices(network.getNetworkOfferingId()) && (zone.getNetworkType() == NetworkType.Advanced)) { network.setState(Network.State.Setup); } else { try { stateTransitTo(network, Event.OperationSucceeded); } catch (NoTransitionException e) { network.setState(Network.State.Allocated); network.setRestartRequired(false); } } _networksDao.update(network.getId(), network); _networksDao.clearCheckForGc(networkId); result = true; } else { try { stateTransitTo(network, Event.OperationFailed); } catch (NoTransitionException e) { network.setState(Network.State.Implemented); _networksDao.update(network.getId(), network); } result = false; } txn.commit(); return result; } @Override public boolean shutdownNetworkElementsAndResources(ReservationContext context, boolean cleanupElements, NetworkVO network) { // 1) Cleanup all the rules for the network. If it fails, just log the failure and proceed with shutting down // the elements boolean cleanupResult = true; try { cleanupResult = shutdownNetworkResources(network.getId(), context.getAccount(), context.getCaller().getId()); } catch (Exception ex) { s_logger.warn("shutdownNetworkRules failed during the network " + network + " shutdown due to ", ex); } finally { // just warn the administrator that the network elements failed to shutdown if (!cleanupResult) { s_logger.warn("Failed to cleanup network id=" + network.getId() + " resources as a part of shutdownNetwork"); } } // 2) Shutdown all the network elements // get providers to shutdown List providersToShutdown = getNetworkProviders(network.getId()); boolean success = true; for (NetworkElement element : _networkElements) { if (providersToShutdown.contains(element.getProvider())) { try { if (!_networkModel.isProviderEnabledInPhysicalNetwork(_networkModel.getPhysicalNetworkId(network), element.getProvider().getName())) { s_logger.warn("Unable to complete shutdown of the network elements due to element: " + element.getName() + " either doesn't exist or not enabled in the physical network " + _networkModel.getPhysicalNetworkId(network)); success = false; } if (s_logger.isDebugEnabled()) { s_logger.debug("Sending network shutdown to " + element.getName()); } if (!element.shutdown(network, context, cleanupElements)) { s_logger.warn("Unable to complete shutdown of the network elements due to element: " + element.getName()); success = false; } } catch (ResourceUnavailableException e) { s_logger.warn("Unable to complete shutdown of the network elements due to element: " + element.getName(), e); success = false; } catch (ConcurrentOperationException e) { s_logger.warn("Unable to complete shutdown of the network elements due to element: " + element.getName(), e); success = false; } catch (Exception e) { s_logger.warn("Unable to complete shutdown of the network elements due to element: " + element.getName(), e); success = false; } } } return success; } @Override @DB public boolean destroyNetwork(long networkId, ReservationContext context) { Account callerAccount = _accountMgr.getAccount(context.getCaller().getAccountId()); NetworkVO network = _networksDao.findById(networkId); if (network == null) { s_logger.debug("Unable to find network with id: " + networkId); return false; } // Don't allow to delete network via api call when it has vms assigned to it int nicCount = getActiveNicsInNetwork(networkId); if (nicCount > 0) { s_logger.debug("Unable to remove the network id=" + networkId + " as it has active Nics."); return false; } // Make sure that there are no user vms in the network that are not Expunged/Error List userVms = _userVmDao.listByNetworkIdAndStates(networkId); for (UserVmVO vm : userVms) { if (!(vm.getState() == VirtualMachine.State.Expunging && vm.getRemoved() != null)) { s_logger.warn("Can't delete the network, not all user vms are expunged. Vm " + vm + " is in " + vm.getState() + " state"); return false; } } //In Basic zone, make sure that there are no non-removed console proxies and SSVMs using the network DataCenter zone = _configMgr.getZone(network.getDataCenterId()); if (zone.getNetworkType() == NetworkType.Basic) { List systemVms = _vmDao.listNonRemovedVmsByTypeAndNetwork(network.getId(), Type.ConsoleProxy, Type.SecondaryStorageVm); if (systemVms != null && !systemVms.isEmpty()) { s_logger.warn("Can't delete the network, not all consoleProxy/secondaryStorage vms are expunged"); return false; } } // Shutdown network first shutdownNetwork(networkId, context, false); // 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; if (!cleanupNetworkResources(networkId, callerAccount, context.getCaller().getId())) { s_logger.warn("Unable to delete network id=" + networkId + ": failed to cleanup network resources"); return false; } // get providers to destroy List providersToDestroy = getNetworkProviders(network.getId()); for (NetworkElement element : _networkElements) { if (providersToDestroy.contains(element.getProvider())) { try { if (!_networkModel.isProviderEnabledInPhysicalNetwork(_networkModel.getPhysicalNetworkId(network), element.getProvider().getName())) { s_logger.warn("Unable to complete destroy of the network elements due to element: " + element.getName() + " either doesn't exist or not enabled in the physical network " + _networkModel.getPhysicalNetworkId(network)); success = false; } if (s_logger.isDebugEnabled()) { s_logger.debug("Sending destroy to " + element); } if (!element.destroy(network, context)) { success = false; s_logger.warn("Unable to complete destroy of the network: failed to destroy network element " + element.getName()); } } 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 = AdapterBase.getAdapterByName(_networkGurus, 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(), context.getCaller().getId(), callerAccount)) { 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 try { stateTransitTo(network, Event.DestroyNetwork); } catch (NoTransitionException e) { s_logger.debug(e.getMessage()); } _networksDao.remove(network.getId()); NetworkOffering ntwkOff = _configMgr.getNetworkOffering(network.getNetworkOfferingId()); boolean updateResourceCount = resourceCountNeedsUpdate(ntwkOff, network.getAclType()); if (updateResourceCount) { _resourceLimitMgr.decrementResourceCount(owner.getId(), ResourceType.network); } txn.commit(); } } return success; } private boolean resourceCountNeedsUpdate(NetworkOffering ntwkOff, ACLType aclType) { boolean updateResourceCount = (!ntwkOff.getSpecifyVlan() && aclType == ACLType.Account); return updateResourceCount; } protected boolean deleteVlansInNetwork(long networkId, long userId, Account callerAccount) { //cleanup Public vlans List publicVlans = _vlanDao.listVlansByNetworkId(networkId); boolean result = true; for (VlanVO vlan : publicVlans) { if (!_configMgr.deleteVlanAndPublicIpRange(_accountMgr.getSystemUser().getId(), vlan.getId(), callerAccount)) { s_logger.warn("Failed to delete vlan " + vlan.getId() + ");"); result = false; } } //cleanup private vlans int privateIpAllocCount = _privateIpDao.countAllocatedByNetworkId(networkId); if (privateIpAllocCount > 0) { s_logger.warn("Can't delete Private ip range for network " + networkId + " as it has allocated ip addresses"); result = false; } else { _privateIpDao.deleteByNetworkId(networkId); s_logger.debug("Deleted ip range for private network id=" + networkId); } return result; } @Override public boolean applyRules(List rules, FirewallRule.Purpose purpose, NetworkRuleApplier applier, 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()); FirewallRuleVO.TrafficType trafficType = rules.get(0).getTrafficType(); List publicIps = new ArrayList(); if (!(rules.get(0).getPurpose() == FirewallRule.Purpose.Firewall && trafficType == FirewallRule.TrafficType.Egress)) { // get the list of public ip's owned by the network List userIps = _ipAddressDao.listByAssociatedNetwork(network.getId(), null); if (userIps != null && !userIps.isEmpty()) { for (IPAddressVO userIp : userIps) { PublicIp publicIp = PublicIp.createFromAddrAndVlan(userIp, _vlanDao.findById(userIp.getVlanId())); publicIps.add(publicIp); } } // rules can not programmed unless IP is associated with network // service provider, so run IP assoication for // the network so as to ensure IP is associated before applying // rules (in add state) applyIpAssociations(network, false, continueOnError, publicIps); } try { applier.applyRules(network, purpose, rules); } catch (ResourceUnavailableException e) { if (!continueOnError) { throw e; } s_logger.warn("Problems with applying " + purpose + " rules but pushing on", e); success = false; } if (!(rules.get(0).getPurpose() == FirewallRule.Purpose.Firewall && trafficType == FirewallRule.TrafficType.Egress)) { // if all the rules configured on public IP are revoked then // dis-associate IP with network service provider applyIpAssociations(network, true, continueOnError, publicIps); } return success; } public class NetworkGarbageCollector implements Runnable { @Override public void run() { try { List shutdownList = new ArrayList(); long currentTime = System.currentTimeMillis() >> 10; HashMap stillFree = new HashMap(); List 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) { // If network is removed, unset gc flag for it if (_networksDao.findById(networkId) == null) { s_logger.debug("Network id=" + networkId + " is removed, so clearing up corresponding gc check"); _networksDao.clearCheckForGc(networkId); } else { try { User caller = _accountMgr.getSystemUser(); Account owner = _accountMgr.getAccount(_networksDao.findById(networkId).getAccountId()); ReservationContext context = new ReservationContextImpl(null, null, caller, owner); shutdownNetwork(networkId, context, false); } 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 startNetwork(long networkId, DeployDestination dest, ReservationContext context) throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException { // Check if network exists NetworkVO network = _networksDao.findById(networkId); if (network == null) { InvalidParameterValueException ex = new InvalidParameterValueException("Network with specified id doesn't exist"); ex.addProxyObject(network, networkId, "networkId"); throw ex; } // implement the network s_logger.debug("Starting network " + network + "..."); Pair implementedNetwork = implementNetwork(networkId, dest, context); if (implementedNetwork.first() == null) { s_logger.warn("Failed to start the network " + network); return false; } else { return true; } } @Override public boolean restartNetwork(Long networkId, Account callerAccount, User callerUser, boolean cleanup) throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException { NetworkVO network = _networksDao.findById(networkId); s_logger.debug("Restarting network " + networkId + "..."); ReservationContext context = new ReservationContextImpl(null, null, callerUser, callerAccount); if (cleanup) { // shutdown the network s_logger.debug("Shutting down the network id=" + networkId + " as a part of network restart"); if (!shutdownNetworkElementsAndResources(context, true, network)) { s_logger.debug("Failed to shutdown the network elements and resources as a part of network restart: " + network.getState()); setRestartRequired(network, true); return false; } } else { s_logger.debug("Skip the shutting down of network id=" + networkId); } // implement the network elements and rules again DeployDestination dest = new DeployDestination(_dcDao.findById(network.getDataCenterId()), null, null, null); s_logger.debug("Implementing the network " + network + " elements and resources as a part of network restart"); NetworkOfferingVO offering = _networkOfferingDao.findById(network.getNetworkOfferingId()); try { implementNetworkElementsAndResources(dest, context, network, offering); setRestartRequired(network, true); } catch (Exception ex) { s_logger.warn("Failed to implement network " + network + " elements and resources as a part of network restart due to ", ex); return false; } setRestartRequired(network, false); return true; } private void setRestartRequired(NetworkVO network, boolean restartRequired) { s_logger.debug("Marking network " + network + " with restartRequired=" + restartRequired); network.setRestartRequired(restartRequired); _networksDao.update(network.getId(), network); } // This method re-programs the rules/ips for existing network protected boolean reprogramNetworkRules(long networkId, Account caller, NetworkVO network) throws ResourceUnavailableException { boolean success = true; // associate all ip addresses if (!applyIpAssociations(network, false)) { s_logger.warn("Failed to apply ip addresses as a part of network id" + networkId + " restart"); success = false; } // apply static nat if (!_rulesMgr.applyStaticNatsForNetwork(networkId, false, caller)) { s_logger.warn("Failed to apply static nats a part of network id" + networkId + " restart"); success = false; } // apply firewall rules List firewallIngressRulesToApply = _firewallDao.listByNetworkPurposeTrafficType(networkId, Purpose.Firewall, FirewallRule.TrafficType.Ingress); if (!_firewallMgr.applyFirewallRules(firewallIngressRulesToApply, false, caller)) { s_logger.warn("Failed to reapply Ingress firewall rule(s) as a part of network id=" + networkId + " restart"); success = false; } List firewallEgressRulesToApply = _firewallDao.listByNetworkPurposeTrafficType(networkId, Purpose.Firewall, FirewallRule.TrafficType.Egress); if (!_firewallMgr.applyFirewallRules(firewallEgressRulesToApply, false, caller)) { s_logger.warn("Failed to reapply firewall Egress rule(s) as a part of network id=" + networkId + " restart"); success = false; } // apply port forwarding rules if (!_rulesMgr.applyPortForwardingRulesForNetwork(networkId, false, caller)) { s_logger.warn("Failed to reapply port forwarding rule(s) as a part of network id=" + networkId + " restart"); success = false; } // apply static nat rules if (!_rulesMgr.applyStaticNatRulesForNetwork(networkId, false, caller)) { s_logger.warn("Failed to reapply static nat rule(s) as a part of network id=" + networkId + " restart"); success = false; } // apply public load balancer rules if (!_lbMgr.applyLoadBalancersForNetwork(networkId, Scheme.Public)) { s_logger.warn("Failed to reapply Public load balancer rules as a part of network id=" + networkId + " restart"); success = false; } // apply internal load balancer rules if (!_lbMgr.applyLoadBalancersForNetwork(networkId, Scheme.Internal)) { s_logger.warn("Failed to reapply internal load balancer rules as a part of network id=" + networkId + " restart"); success = false; } // apply vpn rules List vpnsToReapply = _vpnMgr.listRemoteAccessVpns(networkId); if (vpnsToReapply != null) { for (RemoteAccessVpn vpn : vpnsToReapply) { // Start remote access vpn per ip if (_vpnMgr.startRemoteAccessVpn(vpn.getServerAddressId(), false) == null) { s_logger.warn("Failed to reapply vpn rules as a part of network id=" + networkId + " restart"); success = false; } } } //apply network ACLs if (!_networkACLMgr.applyACLToNetwork(networkId)) { s_logger.warn("Failed to reapply network ACLs as a part of of network id=" + networkId + " restart"); success = false; } return success; } protected int getActiveNicsInNetwork(long networkId) { return _networksDao.getActiveNicsIn(networkId); } @Override @DB public boolean associateIpAddressListToAccount(long userId, long accountId, long zoneId, Long vlanId, Network guestNetwork) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, ResourceAllocationException { Account owner = _accountMgr.getActiveAccountById(accountId); boolean createNetwork = false; if (guestNetwork != null && guestNetwork.getTrafficType() != TrafficType.Guest) { throw new InvalidParameterValueException("Network " + guestNetwork + " is not of a type " + TrafficType.Guest); } Transaction txn = Transaction.currentTxn(); txn.start(); if (guestNetwork == null) { List networks = getIsolatedNetworksWithSourceNATOwnedByAccountInZone(zoneId, owner); if (networks.size() == 0) { createNetwork = true; } else if (networks.size() == 1) { guestNetwork = networks.get(0); } else { throw new InvalidParameterValueException("Error, more than 1 Guest Isolated Networks with SourceNAT " + "service enabled found for this account, cannot assosiate the IP range, please provide the network ID"); } } // create new Virtual network (Isolated with SourceNAT) for the user if it doesn't exist List requiredOfferings = _networkOfferingDao.listByAvailability(Availability.Required, false); if (requiredOfferings.size() < 1) { throw new CloudRuntimeException("Unable to find network offering with availability=" + Availability.Required + " to automatically create the network as part of createVlanIpRange"); } if (createNetwork) { if (requiredOfferings.get(0).getState() == NetworkOffering.State.Enabled) { long physicalNetworkId = _networkModel.findPhysicalNetworkId(zoneId, requiredOfferings.get(0).getTags(), requiredOfferings.get(0).getTrafficType()); // Validate physical network PhysicalNetwork physicalNetwork = _physicalNetworkDao.findById(physicalNetworkId); if (physicalNetwork == null) { throw new InvalidParameterValueException("Unable to find physical network with id: "+physicalNetworkId + " and tag: " +requiredOfferings.get(0).getTags()); } s_logger.debug("Creating network for account " + owner + " from the network offering id=" + requiredOfferings.get(0).getId() + " as a part of createVlanIpRange process"); guestNetwork = createGuestNetwork(requiredOfferings.get(0).getId(), owner.getAccountName() + "-network" , owner.getAccountName() + "-network", null, null, null, null, owner, null, physicalNetwork, zoneId, ACLType.Account, null, null, null, null, true, null); if (guestNetwork == null) { s_logger.warn("Failed to create default Virtual network for the account " + accountId + "in zone " + zoneId); throw new CloudRuntimeException("Failed to create a Guest Isolated Networks with SourceNAT " + "service enabled as a part of createVlanIpRange, for the account " + accountId + "in zone " + zoneId); } } else { throw new CloudRuntimeException("Required network offering id=" + requiredOfferings.get(0).getId() + " is not in " + NetworkOffering.State.Enabled); } } // Check if there is a source nat ip address for this account; if not - we have to allocate one boolean allocateSourceNat = false; List sourceNat = _ipAddressDao.listByAssociatedNetwork(guestNetwork.getId(), true); if (sourceNat.isEmpty()) { allocateSourceNat = true; } // update all ips with a network id, mark them as allocated and update resourceCount/usage List ips = _ipAddressDao.listByVlanId(vlanId); boolean isSourceNatAllocated = false; for (IPAddressVO addr : ips) { if (addr.getState() != State.Allocated) { if (!isSourceNatAllocated && allocateSourceNat) { addr.setSourceNat(true); isSourceNatAllocated = true; } else { addr.setSourceNat(false); } addr.setAssociatedWithNetworkId(guestNetwork.getId()); addr.setVpcId(guestNetwork.getVpcId()); addr.setAllocatedTime(new Date()); addr.setAllocatedInDomainId(owner.getDomainId()); addr.setAllocatedToAccountId(owner.getId()); addr.setSystem(false); addr.setState(IpAddress.State.Allocating); markPublicIpAsAllocated(addr); } } txn.commit(); // if the network offering has persistent set to true, implement the network if ( createNetwork && requiredOfferings.get(0).getIsPersistent() ) { DataCenter zone = _dcDao.findById(zoneId); DeployDestination dest = new DeployDestination(zone, null, null, null); Account callerAccount = UserContext.current().getCaller(); UserVO callerUser = _userDao.findById(UserContext.current().getCallerUserId()); Journal journal = new Journal.LogJournal("Implementing " + guestNetwork, s_logger); ReservationContext context = new ReservationContextImpl(UUID.randomUUID().toString(), journal, callerUser, callerAccount); s_logger.debug("Implementing network " + guestNetwork + " as a part of network provision for persistent network"); try { Pair implementedNetwork = implementNetwork(guestNetwork.getId(), dest, context); if (implementedNetwork.first() == null) { s_logger.warn("Failed to implement the network " + guestNetwork); } guestNetwork = implementedNetwork.second(); } catch (Exception ex) { s_logger.warn("Failed to implement network " + guestNetwork + " elements and resources as a part of" + " network provision due to ", ex); CloudRuntimeException e = new CloudRuntimeException("Failed to implement network (with specified id)" + " elements and resources as a part of network provision for persistent network"); e.addProxyObject(guestNetwork, guestNetwork.getId(), "networkId"); throw e; } } return true; } @Override public NetworkProfile convertNetworkToNetworkProfile(long networkId) { NetworkVO network = _networksDao.findById(networkId); NetworkGuru guru = AdapterBase.getAdapterByName(_networkGurus, network.getGuruName()); NetworkProfile profile = new NetworkProfile(network); guru.updateNetworkProfile(profile); return profile; } @Override public UserDataServiceProvider getPasswordResetProvider(Network network) { String passwordProvider = _ntwkSrvcDao.getProviderForServiceInNetwork(network.getId(), Service.UserData); if (passwordProvider == null) { s_logger.debug("Network " + network + " doesn't support service " + Service.UserData.getName()); return null; } return (UserDataServiceProvider)_networkModel.getElementImplementingProvider(passwordProvider); } @Override public UserDataServiceProvider getSSHKeyResetProvider(Network network) { String SSHKeyProvider = _ntwkSrvcDao.getProviderForServiceInNetwork(network.getId(), Service.UserData); if (SSHKeyProvider == null) { s_logger.debug("Network " + network + " doesn't support service " + Service.UserData.getName()); return null; } return (UserDataServiceProvider)_networkModel.getElementImplementingProvider(SSHKeyProvider); } @Override public DhcpServiceProvider getDhcpServiceProvider(Network network) { String DhcpProvider = _ntwkSrvcDao.getProviderForServiceInNetwork(network.getId(), Service.UserData); if (DhcpProvider == null) { s_logger.debug("Network " + network + " doesn't support service " + Service.Dhcp.getName()); return null; } return (DhcpServiceProvider)_networkModel.getElementImplementingProvider(DhcpProvider); } protected boolean isSharedNetworkWithServices(Network network) { assert(network != null); DataCenter zone = _configMgr.getZone(network.getDataCenterId()); if (network.getGuestType() == Network.GuestType.Shared && zone.getNetworkType() == NetworkType.Advanced && isSharedNetworkOfferingWithServices(network.getNetworkOfferingId())) { return true; } return false; } protected boolean isSharedNetworkOfferingWithServices(long networkOfferingId) { NetworkOfferingVO networkOffering = _networkOfferingDao.findById(networkOfferingId); if ( (networkOffering.getGuestType() == Network.GuestType.Shared) && ( _networkModel.areServicesSupportedByNetworkOffering(networkOfferingId, Service.SourceNat) || _networkModel.areServicesSupportedByNetworkOffering(networkOfferingId, Service.StaticNat) || _networkModel.areServicesSupportedByNetworkOffering(networkOfferingId, Service.Firewall) || _networkModel.areServicesSupportedByNetworkOffering(networkOfferingId, Service.PortForwarding) || _networkModel.areServicesSupportedByNetworkOffering(networkOfferingId, Service.Lb))) { return true; } return false; } @Override public boolean cleanupIpResources(long ipId, long userId, Account caller) { boolean success = true; // Revoke all firewall rules for the ip try { s_logger.debug("Revoking all " + Purpose.Firewall + "rules as a part of public IP id=" + ipId + " release..."); if (!_firewallMgr.revokeFirewallRulesForIp(ipId, userId, caller)) { s_logger.warn("Unable to revoke all the firewall rules for ip id=" + ipId + " as a part of ip release"); success = false; } } catch (ResourceUnavailableException e) { s_logger.warn("Unable to revoke all firewall rules for ip id=" + ipId + " as a part of ip release", e); success = false; } // Revoke all PF/Static nat rules for the ip try { s_logger.debug("Revoking all " + Purpose.PortForwarding + "/" + Purpose.StaticNat + " rules as a part of public IP id=" + ipId + " release..."); if (!_rulesMgr.revokeAllPFAndStaticNatRulesForIp(ipId, userId, caller)) { s_logger.warn("Unable to revoke all the port forwarding rules for ip id=" + ipId + " as a part of ip release"); success = false; } } catch (ResourceUnavailableException e) { s_logger.warn("Unable to revoke all the port forwarding rules for ip id=" + ipId + " as a part of ip release", e); success = false; } s_logger.debug("Revoking all " + Purpose.LoadBalancing + " rules as a part of public IP id=" + ipId + " release..."); if (!_lbMgr.removeAllLoadBalanacersForIp(ipId, caller, userId)) { s_logger.warn("Unable to revoke all the load balancer rules for ip id=" + ipId + " as a part of ip release"); success = false; } // remote access vpn can be enabled only for static nat ip, so this part should never be executed under normal // conditions // only when ip address failed to be cleaned up as a part of account destroy and was marked as Releasing, this part of // the code would be triggered s_logger.debug("Cleaning up remote access vpns as a part of public IP id=" + ipId + " release..."); try { _vpnMgr.destroyRemoteAccessVpnForIp(ipId, caller); } catch (ResourceUnavailableException e) { s_logger.warn("Unable to destroy remote access vpn for ip id=" + ipId + " as a part of ip release", e); success = false; } return success; } @DB @Override public IPAddressVO markIpAsUnavailable(long addrId) { Transaction txn = Transaction.currentTxn(); IPAddressVO ip = _ipAddressDao.findById(addrId); if (ip.getAllocatedToAccountId() == null && ip.getAllocatedTime() == null) { s_logger.trace("Ip address id=" + addrId + " is already released"); return ip; } if (ip.getState() != State.Releasing) { txn.start(); // don't decrement resource count for direct and dedicated ips if (ip.getAssociatedWithNetworkId() != null && !isIpDedicated(ip)) { _resourceLimitMgr.decrementResourceCount(_ipAddressDao.findById(addrId).getAllocatedToAccountId(), ResourceType.public_ip); } // Save usage event if (ip.getAllocatedToAccountId() != null && ip.getAllocatedToAccountId() != Account.ACCOUNT_ID_SYSTEM) { VlanVO vlan = _vlanDao.findById(ip.getVlanId()); String guestType = vlan.getVlanType().toString(); if (!isIpDedicated(ip)) { UsageEventUtils.publishUsageEvent(EventTypes.EVENT_NET_IP_RELEASE, ip.getAllocatedToAccountId(), ip.getDataCenterId(), addrId, ip.getAddress().addr(), ip.isSourceNat(), guestType, ip.getSystem(), ip.getClass().getName(), ip.getUuid()); } } ip = _ipAddressDao.markAsUnavailable(addrId); txn.commit(); } return ip; } Random _rand = new Random(System.currentTimeMillis()); @Override public List listVmNics(Long vmId, Long nicId) { List result = null; if (nicId == null) { result = _nicDao.listByVmId(vmId); } else { result = _nicDao.listByVmIdAndNicId(vmId, nicId); } return result; } @Override public String allocateGuestIP(Account ipOwner, boolean isSystem, long zoneId, Long networkId, String requestedIp) throws InsufficientAddressCapacityException { String ipaddr = null; Account caller = UserContext.current().getCaller(); long callerUserId = UserContext.current().getCallerUserId(); // check permissions DataCenter zone = _configMgr.getZone(zoneId); Network network = _networksDao.findById(networkId); _accountMgr.checkAccess(caller, null, false, network); ipaddr = acquireGuestIpAddress(network, requestedIp); return ipaddr; } @Override @DB public String acquireGuestIpAddress(Network network, String requestedIp) { if (requestedIp != null && requestedIp.equals(network.getGateway())) { s_logger.warn("Requested ip address " + requestedIp + " is used as a gateway address in network " + network); return null; } Set availableIps = _networkModel.getAvailableIps(network, requestedIp); if (availableIps == null || availableIps.isEmpty()) { return null; } Long[] array = availableIps.toArray(new Long[availableIps.size()]); if (requestedIp != null) { // check that requested ip has the same cidr String[] cidr = network.getCidr().split("/"); boolean isSameCidr = NetUtils.sameSubnetCIDR(requestedIp, NetUtils.long2Ip(array[0]), Integer.parseInt(cidr[1])); if (!isSameCidr) { s_logger.warn("Requested ip address " + requestedIp + " doesn't belong to the network " + network + " cidr"); return null; } else { return requestedIp; } } String result; do { result = NetUtils.long2Ip(array[_rand.nextInt(array.length)]); } while (result.split("\\.")[3].equals("1")); return result; } @Override public boolean applyStaticNats(List staticNats, boolean continueOnError) throws ResourceUnavailableException { Network network = _networksDao.findById(staticNats.get(0).getNetworkId()); boolean success = true; if (staticNats == null || staticNats.size() == 0) { s_logger.debug("There are no static nat rules for the network elements"); return true; } // get the list of public ip's owned by the network List userIps = _ipAddressDao.listByAssociatedNetwork(network.getId(), null); List publicIps = new ArrayList(); if (userIps != null && !userIps.isEmpty()) { for (IPAddressVO userIp : userIps) { PublicIp publicIp = PublicIp.createFromAddrAndVlan(userIp, _vlanDao.findById(userIp.getVlanId())); publicIps.add(publicIp); } } // static NAT rules can not programmed unless IP is associated with network service provider, so run IP // association for the network so as to ensure IP is associated before applying rules (in add state) applyIpAssociations(network, false, continueOnError, publicIps); // get provider StaticNatServiceProvider element = getStaticNatProviderForNetwork(network); try { success = element.applyStaticNats(network, staticNats); } catch (ResourceUnavailableException e) { if (!continueOnError) { throw e; } s_logger.warn("Problems with " + element.getName() + " but pushing on", e); success = false; } // For revoked static nat IP, set the vm_id to null, indicate it should be revoked for (StaticNat staticNat : staticNats) { if (staticNat.isForRevoke()) { for (PublicIp publicIp : publicIps) { if (publicIp.getId() == staticNat.getSourceIpAddressId()) { publicIps.remove(publicIp); IPAddressVO ip = _ipAddressDao.findByIdIncludingRemoved(staticNat.getSourceIpAddressId()); // ip can't be null, otherwise something wrong happened ip.setAssociatedWithVmId(null); publicIp = PublicIp.createFromAddrAndVlan(ip, _vlanDao.findById(ip.getVlanId())); publicIps.add(publicIp); break; } } } } // if all the rules configured on public IP are revoked then, dis-associate IP with network service provider applyIpAssociations(network, true, continueOnError, publicIps); return success; } @DB @Override public boolean reallocate(VirtualMachineProfile vm, DataCenterDeployment dest) throws InsufficientCapacityException, ConcurrentOperationException { VMInstanceVO vmInstance = _vmDao.findById(vm.getId()); DataCenterVO dc = _dcDao.findById(vmInstance.getDataCenterId()); if (dc.getNetworkType() == NetworkType.Basic) { List nics = _nicDao.listByVmId(vmInstance.getId()); NetworkVO network = _networksDao.findById(nics.get(0).getNetworkId()); Pair profile = new Pair(network, null); List> profiles = new ArrayList>(); profiles.add(profile); Transaction txn = Transaction.currentTxn(); txn.start(); try { this.cleanupNics(vm); this.allocate(vm, profiles); } finally { txn.commit(); } } return true; } private boolean cleanupNetworkResources(long networkId, Account caller, long callerUserId) { boolean success = true; Network network = _networksDao.findById(networkId); //remove all PF/Static Nat rules for the network try { if (_rulesMgr.revokeAllPFStaticNatRulesForNetwork(networkId, callerUserId, caller)) { s_logger.debug("Successfully cleaned up portForwarding/staticNat rules for network id=" + networkId); } else { success = false; s_logger.warn("Failed to release portForwarding/StaticNat rules as a part of network id=" + networkId + " cleanup"); } } catch (ResourceUnavailableException ex) { success = false; // shouldn't even come here as network is being cleaned up after all network elements are shutdown s_logger.warn("Failed to release portForwarding/StaticNat rules as a part of network id=" + networkId + " cleanup due to resourceUnavailable ", ex); } //remove all LB rules for the network if (_lbMgr.removeAllLoadBalanacersForNetwork(networkId, caller, callerUserId)) { s_logger.debug("Successfully cleaned up load balancing rules for network id=" + networkId); } else { // shouldn't even come here as network is being cleaned up after all network elements are shutdown success = false; s_logger.warn("Failed to cleanup LB rules as a part of network id=" + networkId + " cleanup"); } //revoke all firewall rules for the network try { if (_firewallMgr.revokeAllFirewallRulesForNetwork(networkId, callerUserId, caller)) { s_logger.debug("Successfully cleaned up firewallRules rules for network id=" + networkId); } else { success = false; s_logger.warn("Failed to cleanup Firewall rules as a part of network id=" + networkId + " cleanup"); } } catch (ResourceUnavailableException ex) { success = false; // shouldn't even come here as network is being cleaned up after all network elements are shutdown s_logger.warn("Failed to cleanup Firewall rules as a part of network id=" + networkId + " cleanup due to resourceUnavailable ", ex); } //revoke all network ACLs for network try { if (_networkACLMgr.revokeACLItemsForNetwork(networkId, callerUserId, caller)) { s_logger.debug("Successfully cleaned up NetworkACLs for network id=" + networkId); } else { success = false; s_logger.warn("Failed to cleanup NetworkACLs as a part of network id=" + networkId + " cleanup"); } } catch (ResourceUnavailableException ex) { success = false; s_logger.warn("Failed to cleanup Network ACLs as a part of network id=" + networkId + " cleanup due to resourceUnavailable ", ex); } //release all ip addresses List ipsToRelease = _ipAddressDao.listByAssociatedNetwork(networkId, null); for (IPAddressVO ipToRelease : ipsToRelease) { if (ipToRelease.getVpcId() == null) { IPAddressVO ip = markIpAsUnavailable(ipToRelease.getId()); assert (ip != null) : "Unable to mark the ip address id=" + ipToRelease.getId() + " as unavailable."; } else { _vpcMgr.unassignIPFromVpcNetwork(ipToRelease.getId(), network.getId()); } } 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 never get to here because we used true when applyIpAssociations", e); } return success; } private boolean shutdownNetworkResources(long networkId, Account caller, long callerUserId) { // This method cleans up network rules on the backend w/o touching them in the DB boolean success = true; Network network = _networksDao.findById(networkId); // Mark all PF rules as revoked and apply them on the backend (not in the DB) List pfRules = _portForwardingRulesDao.listByNetwork(networkId); if (s_logger.isDebugEnabled()) { s_logger.debug("Releasing " + pfRules.size() + " port forwarding rules for network id=" + networkId + " as a part of shutdownNetworkRules"); } for (PortForwardingRuleVO pfRule : pfRules) { s_logger.trace("Marking pf rule " + pfRule + " with Revoke state"); pfRule.setState(FirewallRule.State.Revoke); } try { if (!_firewallMgr.applyRules(pfRules, true, false)) { s_logger.warn("Failed to cleanup pf rules as a part of shutdownNetworkRules"); success = false; } } catch (ResourceUnavailableException ex) { s_logger.warn("Failed to cleanup pf rules as a part of shutdownNetworkRules due to ", ex); success = false; } // Mark all static rules as revoked and apply them on the backend (not in the DB) List firewallStaticNatRules = _firewallDao.listByNetworkAndPurpose(networkId, Purpose.StaticNat); List staticNatRules = new ArrayList(); if (s_logger.isDebugEnabled()) { s_logger.debug("Releasing " + firewallStaticNatRules.size() + " static nat rules for network id=" + networkId + " as a part of shutdownNetworkRules"); } for (FirewallRuleVO firewallStaticNatRule : firewallStaticNatRules) { s_logger.trace("Marking static nat rule " + firewallStaticNatRule + " with Revoke state"); IpAddress ip = _ipAddressDao.findById(firewallStaticNatRule.getSourceIpAddressId()); FirewallRuleVO ruleVO = _firewallDao.findById(firewallStaticNatRule.getId()); if (ip == null || !ip.isOneToOneNat() || ip.getAssociatedWithVmId() == null) { throw new InvalidParameterValueException("Source ip address of the rule id=" + firewallStaticNatRule.getId() + " is not static nat enabled"); } //String dstIp = _networkModel.getIpInNetwork(ip.getAssociatedWithVmId(), firewallStaticNatRule.getNetworkId()); ruleVO.setState(FirewallRule.State.Revoke); staticNatRules.add(new StaticNatRuleImpl(ruleVO, ip.getVmIp())); } try { if (!_firewallMgr.applyRules(staticNatRules, true, false)) { s_logger.warn("Failed to cleanup static nat rules as a part of shutdownNetworkRules"); success = false; } } catch (ResourceUnavailableException ex) { s_logger.warn("Failed to cleanup static nat rules as a part of shutdownNetworkRules due to ", ex); success = false; } try { if (!_lbMgr.revokeLoadBalancersForNetwork(networkId, Scheme.Public)) { s_logger.warn("Failed to cleanup public lb rules as a part of shutdownNetworkRules"); success = false; } } catch (ResourceUnavailableException ex) { s_logger.warn("Failed to cleanup public lb rules as a part of shutdownNetworkRules due to ", ex); success = false; } try { if (!_lbMgr.revokeLoadBalancersForNetwork(networkId, Scheme.Internal)) { s_logger.warn("Failed to cleanup internal lb rules as a part of shutdownNetworkRules"); success = false; } } catch (ResourceUnavailableException ex) { s_logger.warn("Failed to cleanup public lb rules as a part of shutdownNetworkRules due to ", ex); success = false; } // revoke all firewall rules for the network w/o applying them on the DB List firewallRules = _firewallDao.listByNetworkPurposeTrafficType(networkId, Purpose.Firewall, FirewallRule.TrafficType.Ingress); if (s_logger.isDebugEnabled()) { s_logger.debug("Releasing " + firewallRules.size() + " firewall ingress rules for network id=" + networkId + " as a part of shutdownNetworkRules"); } for (FirewallRuleVO firewallRule : firewallRules) { s_logger.trace("Marking firewall ingress rule " + firewallRule + " with Revoke state"); firewallRule.setState(FirewallRule.State.Revoke); } try { if (!_firewallMgr.applyRules(firewallRules, true, false)) { s_logger.warn("Failed to cleanup firewall ingress rules as a part of shutdownNetworkRules"); success = false; } } catch (ResourceUnavailableException ex) { s_logger.warn("Failed to cleanup firewall ingress rules as a part of shutdownNetworkRules due to ", ex); success = false; } List firewallEgressRules = _firewallDao.listByNetworkPurposeTrafficType(networkId, Purpose.Firewall, FirewallRule.TrafficType.Egress); if (s_logger.isDebugEnabled()) { s_logger.debug("Releasing " + firewallEgressRules.size() + " firewall egress rules for network id=" + networkId + " as a part of shutdownNetworkRules"); } for (FirewallRuleVO firewallRule : firewallEgressRules) { s_logger.trace("Marking firewall egress rule " + firewallRule + " with Revoke state"); firewallRule.setState(FirewallRule.State.Revoke); } try { if (!_firewallMgr.applyRules(firewallEgressRules, true, false)) { s_logger.warn("Failed to cleanup firewall egress rules as a part of shutdownNetworkRules"); success = false; } } catch (ResourceUnavailableException ex) { s_logger.warn("Failed to cleanup firewall egress rules as a part of shutdownNetworkRules due to ", ex); success = false; } if(network.getVpcId() != null){ if (s_logger.isDebugEnabled()) { s_logger.debug("Releasing Network ACL Items for network id=" + networkId + " as a part of shutdownNetworkRules"); } try { //revoke all Network ACLs for the network w/o applying them in the DB if (!_networkACLMgr.revokeACLItemsForNetwork(networkId, callerUserId, caller)) { s_logger.warn("Failed to cleanup network ACLs as a part of shutdownNetworkRules"); success = false; } } catch (ResourceUnavailableException ex) { s_logger.warn("Failed to cleanup network ACLs as a part of shutdownNetworkRules due to ", ex); success = false; } } //release all static nats for the network if (!_rulesMgr.applyStaticNatForNetwork(networkId, false, caller, true)) { s_logger.warn("Failed to disable static nats as part of shutdownNetworkRules for network id " + networkId); success = false; } // Get all ip addresses, mark as releasing and release them on the backend List userIps = _ipAddressDao.listByAssociatedNetwork(networkId, null); List publicIpsToRelease = new ArrayList(); if (userIps != null && !userIps.isEmpty()) { for (IPAddressVO userIp : userIps) { userIp.setState(State.Releasing); PublicIp publicIp = PublicIp.createFromAddrAndVlan(userIp, _vlanDao.findById(userIp.getVlanId())); publicIpsToRelease.add(publicIp); } } try { if (!applyIpAssociations(network, true, true, publicIpsToRelease)) { s_logger.warn("Unable to apply ip address associations for " + network + " as a part of shutdownNetworkRules"); success = false; } } catch (ResourceUnavailableException e) { throw new CloudRuntimeException("We should never get to here because we used true when applyIpAssociations", e); } return success; } @Override public boolean processAnswers(long agentId, long seq, Answer[] answers) { return false; } @Override public boolean processCommands(long agentId, long seq, Command[] commands) { return false; } @Override public AgentControlAnswer processControlCommand(long agentId, AgentControlCommand cmd) { return null; } @Override public void processConnect(HostVO host, StartupCommand cmd, boolean forRebalance) throws ConnectionException { if (!(cmd instanceof StartupRoutingCommand)) { return; } long hostId = host.getId(); StartupRoutingCommand startup = (StartupRoutingCommand) cmd; String dataCenter = startup.getDataCenter(); long dcId = -1; DataCenterVO dc = _dcDao.findByName(dataCenter); if (dc == null) { try { dcId = Long.parseLong(dataCenter); dc = _dcDao.findById(dcId); } catch (final NumberFormatException e) { } } if (dc == null) { throw new IllegalArgumentException("Host " + startup.getPrivateIpAddress() + " sent incorrect data center: " + dataCenter); } dcId = dc.getId(); HypervisorType hypervisorType = startup.getHypervisorType(); if (s_logger.isDebugEnabled()) { s_logger.debug("Host's hypervisorType is: " + hypervisorType); } List networkInfoList = new ArrayList(); // list all physicalnetworks in the zone & for each get the network names List physicalNtwkList = _physicalNetworkDao.listByZone(dcId); for (PhysicalNetworkVO pNtwk : physicalNtwkList) { String publicName = _pNTrafficTypeDao.getNetworkTag(pNtwk.getId(), TrafficType.Public, hypervisorType); String privateName = _pNTrafficTypeDao.getNetworkTag(pNtwk.getId(), TrafficType.Management, hypervisorType); String guestName = _pNTrafficTypeDao.getNetworkTag(pNtwk.getId(), TrafficType.Guest, hypervisorType); String storageName = _pNTrafficTypeDao.getNetworkTag(pNtwk.getId(), TrafficType.Storage, hypervisorType); // String controlName = _pNTrafficTypeDao._networkModel.getNetworkTag(pNtwk.getId(), TrafficType.Control, hypervisorType); PhysicalNetworkSetupInfo info = new PhysicalNetworkSetupInfo(); info.setPhysicalNetworkId(pNtwk.getId()); info.setGuestNetworkName(guestName); info.setPrivateNetworkName(privateName); info.setPublicNetworkName(publicName); info.setStorageNetworkName(storageName); PhysicalNetworkTrafficTypeVO mgmtTraffic = _pNTrafficTypeDao.findBy(pNtwk.getId(), TrafficType.Management); if (mgmtTraffic != null) { String vlan = mgmtTraffic.getVlan(); info.setMgmtVlan(vlan); } networkInfoList.add(info); } // send the names to the agent if (s_logger.isDebugEnabled()) { s_logger.debug("Sending CheckNetworkCommand to check the Network is setup correctly on Agent"); } CheckNetworkCommand nwCmd = new CheckNetworkCommand(networkInfoList); CheckNetworkAnswer answer = (CheckNetworkAnswer) _agentMgr.easySend(hostId, nwCmd); if (answer == null) { s_logger.warn("Unable to get an answer to the CheckNetworkCommand from agent:" + host.getId()); throw new ConnectionException(true, "Unable to get an answer to the CheckNetworkCommand from agent: " + host.getId()); } if (!answer.getResult()) { s_logger.warn("Unable to setup agent " + hostId + " due to " + ((answer != null) ? answer.getDetails() : "return null")); String msg = "Incorrect Network setup on agent, Reinitialize agent after network names are setup, details : " + answer.getDetails(); _alertMgr.sendAlert(AlertManager.ALERT_TYPE_HOST, dcId, host.getPodId(), msg, msg); throw new ConnectionException(true, msg); } else { if (answer.needReconnect()) { throw new ConnectionException(false, "Reinitialize agent after network setup."); } if (s_logger.isDebugEnabled()) { s_logger.debug("Network setup is correct on Agent"); } return; } } @Override public boolean processDisconnect(long agentId, Status state) { return false; } @Override public boolean isRecurring() { return false; } @Override public int getTimeout() { return 0; } @Override public boolean processTimeout(long agentId, long seq) { return false; } @Override public Map finalizeServicesAndProvidersForNetwork(NetworkOffering offering, Long physicalNetworkId) { Map svcProviders = new HashMap(); Map> providerSvcs = new HashMap>(); List servicesMap = _ntwkOfferingSrvcDao.listByNetworkOfferingId(offering.getId()); boolean checkPhysicalNetwork = (physicalNetworkId != null) ? true : false; for (NetworkOfferingServiceMapVO serviceMap : servicesMap) { if (svcProviders.containsKey(serviceMap.getService())) { // FIXME - right now we pick up the first provider from the list, need to add more logic based on // provider load, etc continue; } String service = serviceMap.getService(); String provider = serviceMap.getProvider(); if (provider == null) { provider = _networkModel.getDefaultUniqueProviderForService(service).getName(); } // check that provider is supported if (checkPhysicalNetwork) { if (!_pNSPDao.isServiceProviderEnabled(physicalNetworkId, provider, service)) { throw new UnsupportedServiceException("Provider " + provider + " is either not enabled or doesn't " + "support service " + service + " in physical network id=" + physicalNetworkId); } } svcProviders.put(service, provider); List l = providerSvcs.get(provider); if (l == null) { providerSvcs.put(provider, l = new ArrayList()); } l.add(service); } return svcProviders; } private List getNetworkProviders(long networkId) { List providerNames = _ntwkSrvcDao.getDistinctProviders(networkId); List providers = new ArrayList(); for (String providerName : providerNames) { providers.add(Network.Provider.getProvider(providerName)); } return providers; } @Override public IpAddress assignSystemIp(long networkId, Account owner, boolean forElasticLb, boolean forElasticIp) throws InsufficientAddressCapacityException { Network guestNetwork = _networksDao.findById(networkId); NetworkOffering off = _configMgr.getNetworkOffering(guestNetwork.getNetworkOfferingId()); IpAddress ip = null; if ((off.getElasticLb() && forElasticLb) || (off.getElasticIp() && forElasticIp)) { try { s_logger.debug("Allocating system IP address for load balancer rule..."); // allocate ip ip = allocateIP(owner, true, guestNetwork.getDataCenterId()); // apply ip associations ip = associateIPToGuestNetwork(ip.getId(), networkId, true);; } catch (ResourceAllocationException ex) { throw new CloudRuntimeException("Failed to allocate system ip due to ", ex); } catch (ConcurrentOperationException ex) { throw new CloudRuntimeException("Failed to allocate system lb ip due to ", ex); } catch (ResourceUnavailableException ex) { throw new CloudRuntimeException("Failed to allocate system lb ip due to ", ex); } if (ip == null) { throw new CloudRuntimeException("Failed to allocate system ip"); } } return ip; } @Override public boolean handleSystemIpRelease(IpAddress ip) { boolean success = true; Long networkId = ip.getAssociatedWithNetworkId(); if (networkId != null) { if (ip.getSystem()) { UserContext ctx = UserContext.current(); if (!disassociatePublicIpAddress(ip.getId(), ctx.getCallerUserId(), ctx.getCaller())) { s_logger.warn("Unable to release system ip address id=" + ip.getId()); success = false; } else { s_logger.warn("Successfully released system ip address id=" + ip.getId()); } } } return success; } @Override @DB public void allocateDirectIp(NicProfile nic, DataCenter dc, VirtualMachineProfile vm, Network network, String requestedIpv4, String requestedIpv6) throws InsufficientVirtualNetworkCapcityException, InsufficientAddressCapacityException { //This method allocates direct ip for the Shared network in Advance zones boolean ipv4 = false, ipv6 = false; Transaction txn = Transaction.currentTxn(); txn.start(); if (network.getGateway() != null) { if (nic.getIp4Address() == null) { ipv4 = true; PublicIp ip = null; //Get ip address from the placeholder and don't allocate a new one if (requestedIpv4 != null && vm.getType() == VirtualMachine.Type.DomainRouter) { Nic placeholderNic = _networkModel.getPlaceholderNicForRouter(network, null); if (placeholderNic != null) { IPAddressVO userIp = _ipAddressDao.findByIpAndSourceNetworkId(network.getId(), placeholderNic.getIp4Address()); ip = PublicIp.createFromAddrAndVlan(userIp, _vlanDao.findById(userIp.getVlanId())); s_logger.debug("Nic got an ip address " + placeholderNic.getIp4Address() + " stored in placeholder nic for the network " + network); } } if (ip == null) { ip = assignPublicIpAddress(dc.getId(), null, vm.getOwner(), VlanType.DirectAttached, network.getId(), requestedIpv4, false); } nic.setIp4Address(ip.getAddress().toString()); nic.setGateway(ip.getGateway()); nic.setNetmask(ip.getNetmask()); nic.setIsolationUri(IsolationType.Vlan.toUri(ip.getVlanTag())); //nic.setBroadcastType(BroadcastDomainType.Vlan); //nic.setBroadcastUri(BroadcastDomainType.Vlan.toUri(ip.getVlanTag())); nic.setBroadcastType(network.getBroadcastDomainType()); nic.setBroadcastUri(network.getBroadcastUri()); nic.setFormat(AddressFormat.Ip4); nic.setReservationId(String.valueOf(ip.getVlanTag())); nic.setMacAddress(ip.getMacAddress()); } nic.setDns1(dc.getDns1()); nic.setDns2(dc.getDns2()); } //FIXME - get ipv6 address from the placeholder if it's stored there if (network.getIp6Gateway() != null) { if (nic.getIp6Address() == null) { ipv6 = true; UserIpv6Address ip = _ipv6Mgr.assignDirectIp6Address(dc.getId(), vm.getOwner(), network.getId(), requestedIpv6); Vlan vlan = _vlanDao.findById(ip.getVlanId()); nic.setIp6Address(ip.getAddress().toString()); nic.setIp6Gateway(vlan.getIp6Gateway()); nic.setIp6Cidr(vlan.getIp6Cidr()); if (ipv4) { nic.setFormat(AddressFormat.DualStack); } else { nic.setIsolationUri(IsolationType.Vlan.toUri(vlan.getVlanTag())); nic.setBroadcastType(BroadcastDomainType.Vlan); nic.setBroadcastUri(BroadcastDomainType.Vlan.toUri(vlan.getVlanTag())); nic.setFormat(AddressFormat.Ip6); nic.setReservationId(String.valueOf(vlan.getVlanTag())); nic.setMacAddress(ip.getMacAddress()); } } nic.setIp6Dns1(dc.getIp6Dns1()); nic.setIp6Dns2(dc.getIp6Dns2()); } txn.commit(); } @Override public boolean setupDns(Network network, Provider provider) { boolean dnsProvided = _networkModel.isProviderSupportServiceInNetwork(network.getId(), Service.Dns, provider ); boolean dhcpProvided =_networkModel.isProviderSupportServiceInNetwork(network.getId(), Service.Dhcp, provider); boolean setupDns = dnsProvided || dhcpProvided; return setupDns; } protected NicProfile getNicProfileForVm(Network network, NicProfile requested, VirtualMachine vm) { NicProfile nic = null; if (requested != null && requested.getBroadCastUri() != null) { String broadcastUri = requested.getBroadCastUri().toString(); String ipAddress = requested.getIp4Address(); NicVO nicVO = _nicDao.findByNetworkIdInstanceIdAndBroadcastUri(network.getId(), vm.getId(), broadcastUri); if (nicVO != null) { if (ipAddress == null || nicVO.getIp4Address().equals(ipAddress)) { nic = _networkModel.getNicProfile(vm, network.getId(), broadcastUri); } } } else { NicVO nicVO = _nicDao.findByNtwkIdAndInstanceId(network.getId(), vm.getId()); if (nicVO != null) { nic = _networkModel.getNicProfile(vm, network.getId(), null); } } return nic; } @Override public NicProfile createNicForVm(Network network, NicProfile requested, ReservationContext context, VirtualMachineProfile vmProfile, boolean prepare) throws InsufficientVirtualNetworkCapcityException, InsufficientAddressCapacityException, ConcurrentOperationException, InsufficientCapacityException, ResourceUnavailableException { VirtualMachine vm = vmProfile.getVirtualMachine(); DataCenter dc = _configMgr.getZone(network.getDataCenterId()); Host host = _hostDao.findById(vm.getHostId()); DeployDestination dest = new DeployDestination(dc, null, null, host); NicProfile nic = getNicProfileForVm(network, requested, vm); //1) allocate nic (if needed) Always allocate if it is a user vm if (nic == null || (vmProfile.getType() == VirtualMachine.Type.User)) { int deviceId = _nicDao.countNics(vm.getId()); nic = allocateNic(requested, network, false, deviceId, vmProfile).first(); if (nic == null) { throw new CloudRuntimeException("Failed to allocate nic for vm " + vm + " in network " + network); } s_logger.debug("Nic is allocated successfully for vm " + vm + " in network " + network); } //2) prepare nic if (prepare) { Pair implemented = implementNetwork(nic.getNetworkId(), dest, context); nic = prepareNic(vmProfile, dest, context, nic.getId(), implemented.second()); s_logger.debug("Nic is prepared successfully for vm " + vm + " in network " + network); } return nic; } @Override public List getNicProfiles(VirtualMachine vm) { List nics = _nicDao.listByVmId(vm.getId()); List profiles = new ArrayList(); if (nics != null) { for (Nic nic : nics) { NetworkVO network = _networksDao.findById(nic.getNetworkId()); Integer networkRate = _networkModel.getNetworkRate(network.getId(), vm.getId()); NetworkGuru guru = AdapterBase.getAdapterByName(_networkGurus, network.getGuruName()); NicProfile profile = new NicProfile(nic, network, nic.getBroadcastUri(), nic.getIsolationUri(), networkRate, _networkModel.isSecurityGroupSupportedInNetwork(network), _networkModel.getNetworkTag(vm.getHypervisorType(), network)); guru.updateNicProfile(profile, network); profiles.add(profile); } } return profiles; } @Override public int getNetworkLockTimeout() { return _networkLockTimeout; } protected boolean stateTransitTo(NetworkVO network, Network.Event e) throws NoTransitionException { return _stateMachine.transitTo(network, e, null, _networksDao); } private void setStateMachine() { _stateMachine = Network.State.getStateMachine(); } private Map> getServiceProvidersMap(long networkId) { Map> map = new HashMap>(); List nsms = _ntwkSrvcDao.getServicesInNetwork(networkId); for (NetworkServiceMapVO nsm : nsms) { Set providers = map.get(Service.getService(nsm.getService())); if (providers == null) { providers = new HashSet(); } providers.add(Provider.getProvider(nsm.getProvider())); map.put(Service.getService(nsm.getService()), providers); } return map; } @Override public List getProvidersForServiceInNetwork(Network network, Service service) { Map> service2ProviderMap = getServiceProvidersMap(network.getId()); if (service2ProviderMap.get(service) != null) { List providers = new ArrayList(service2ProviderMap.get(service)); return providers; } return null; } protected List getElementForServiceInNetwork(Network network, Service service) { List elements = new ArrayList(); List providers = getProvidersForServiceInNetwork(network, service); //Only support one provider now if (providers == null) { s_logger.error("Cannot find " + service.getName() + " provider for network " + network.getId()); return null; } if (providers.size() != 1 && service != Service.Lb) { //support more than one LB providers only s_logger.error("Found " + providers.size() + " " + service.getName() + " providers for network!" + network.getId()); return null; } for (Provider provider : providers) { NetworkElement element = _networkModel.getElementImplementingProvider(provider.getName()); s_logger.info("Let " + element.getName() + " handle " + service.getName() + " in network " + network.getId()); elements.add(element); } return elements; } @Override public StaticNatServiceProvider getStaticNatProviderForNetwork(Network network) { //only one provider per Static nat service is supoprted NetworkElement element = getElementForServiceInNetwork(network, Service.StaticNat).get(0); assert element instanceof StaticNatServiceProvider; return (StaticNatServiceProvider)element; } @Override public LoadBalancingServiceProvider getLoadBalancingProviderForNetwork(Network network, Scheme lbScheme) { List lbElements = getElementForServiceInNetwork(network, Service.Lb); NetworkElement lbElement = null; if (lbElements.size() > 1) { String providerName = null; //get network offering details NetworkOffering off = _configMgr.getNetworkOffering(network.getNetworkOfferingId()); if (lbScheme == Scheme.Public) { providerName = _ntwkOffDetailsDao.getDetail(off.getId(), NetworkOffering.Detail.PublicLbProvider); } else { providerName = _ntwkOffDetailsDao.getDetail(off.getId(), NetworkOffering.Detail.InternalLbProvider); } if (providerName == null) { throw new InvalidParameterValueException("Can't find Lb provider supporting scheme " + lbScheme.toString() + " in network " + network); } lbElement = _networkModel.getElementImplementingProvider(providerName); } else if (lbElements.size() == 1){ lbElement = lbElements.get(0); } assert lbElement != null; assert lbElement instanceof LoadBalancingServiceProvider; return (LoadBalancingServiceProvider)lbElement; } @Override public boolean isNetworkInlineMode(Network network) { NetworkOfferingVO offering = _networkOfferingDao.findById(network.getNetworkOfferingId()); return offering.isInline(); } @Override public int getRuleCountForIp(Long addressId, FirewallRule.Purpose purpose, FirewallRule.State state) { List rules = _firewallDao.listByIpAndPurposeWithState(addressId, purpose, state); if (rules == null) { return 0; } return rules.size(); } @Override public boolean isSecondaryIpSetForNic(long nicId) { NicVO nic = _nicDao.findById(nicId); return nic.getSecondaryIp(); } @Override public boolean removeVmSecondaryIpsOfNic(long nicId) { Transaction txn = Transaction.currentTxn(); txn.start(); List ipList = _nicSecondaryIpDao.listByNicId(nicId); if (ipList != null) { for (NicSecondaryIpVO ip: ipList) { _nicSecondaryIpDao.remove(ip.getId()); } s_logger.debug("Revoving nic secondary ip entry ..."); } txn.commit(); return true; } @Override public String allocatePublicIpForGuestNic(Long networkId, DataCenter dc, Pod pod,Account owner, String requestedIp) throws InsufficientAddressCapacityException { PublicIp ip = assignPublicIpAddress(dc.getId(), null, owner, VlanType.DirectAttached, networkId, requestedIp, false); if (ip == null) { s_logger.debug("There is no free public ip address"); return null; } Ip ipAddr = ip.getAddress(); return ipAddr.addr(); } @Override public NicVO savePlaceholderNic(Network network, String ip4Address, Type vmType) { NicVO nic = new NicVO(null, null, network.getId(), null); nic.setIp4Address(ip4Address); nic.setReservationStrategy(ReservationStrategy.PlaceHolder); nic.setState(Nic.State.Reserved); nic.setVmType(vmType); return _nicDao.persist(nic); } }