/**
* Copyright (C) 2010 Cloud.com, Inc. All rights reserved.
*
* This software is licensed under the GNU General Public License v3 or later.
*
* It is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
package com.cloud.network;
import java.net.URI;
import java.security.InvalidParameterException;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import javax.ejb.Local;
import javax.naming.ConfigurationException;
import org.apache.log4j.Logger;
import com.cloud.acl.ControlledEntity.ACLType;
import com.cloud.acl.SecurityChecker.AccessType;
import com.cloud.agent.AgentManager;
import com.cloud.agent.Listener;
import com.cloud.agent.api.AgentControlAnswer;
import com.cloud.agent.api.AgentControlCommand;
import com.cloud.agent.api.Answer;
import com.cloud.agent.api.CheckNetworkAnswer;
import com.cloud.agent.api.CheckNetworkCommand;
import com.cloud.agent.api.Command;
import com.cloud.agent.api.StartupCommand;
import com.cloud.agent.api.StartupRoutingCommand;
import com.cloud.agent.api.to.NicTO;
import com.cloud.alert.AlertManager;
import com.cloud.api.commands.CreateNetworkCmd;
import com.cloud.api.commands.ListNetworksCmd;
import com.cloud.api.commands.ListTrafficTypeImplementorsCmd;
import com.cloud.api.commands.RestartNetworkCmd;
import com.cloud.capacity.dao.CapacityDao;
import com.cloud.configuration.Config;
import com.cloud.configuration.ConfigurationManager;
import com.cloud.configuration.Resource.ResourceType;
import com.cloud.configuration.dao.ConfigurationDao;
import com.cloud.configuration.dao.ResourceLimitDao;
import com.cloud.dc.AccountVlanMapVO;
import com.cloud.dc.DataCenter;
import com.cloud.dc.DataCenter.NetworkType;
import com.cloud.dc.DataCenterVO;
import com.cloud.dc.Pod;
import com.cloud.dc.PodVlanMapVO;
import com.cloud.dc.Vlan;
import com.cloud.dc.Vlan.VlanType;
import com.cloud.dc.VlanVO;
import com.cloud.dc.dao.AccountVlanMapDao;
import com.cloud.dc.dao.DataCenterDao;
import com.cloud.dc.dao.PodVlanMapDao;
import com.cloud.dc.dao.VlanDao;
import com.cloud.deploy.DataCenterDeployment;
import com.cloud.deploy.DeployDestination;
import com.cloud.deploy.DeploymentPlan;
import com.cloud.domain.Domain;
import com.cloud.domain.DomainVO;
import com.cloud.domain.dao.DomainDao;
import com.cloud.event.ActionEvent;
import com.cloud.event.EventTypes;
import com.cloud.event.UsageEventVO;
import com.cloud.event.dao.EventDao;
import com.cloud.event.dao.UsageEventDao;
import com.cloud.exception.AccountLimitException;
import com.cloud.exception.ConcurrentOperationException;
import com.cloud.exception.ConnectionException;
import com.cloud.exception.InsufficientAddressCapacityException;
import com.cloud.exception.InsufficientCapacityException;
import com.cloud.exception.InsufficientVirtualNetworkCapcityException;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.exception.PermissionDeniedException;
import com.cloud.exception.ResourceAllocationException;
import com.cloud.exception.ResourceUnavailableException;
import com.cloud.exception.UnsupportedServiceException;
import com.cloud.host.HostVO;
import com.cloud.host.Status;
import com.cloud.host.dao.HostDao;
import com.cloud.hypervisor.Hypervisor.HypervisorType;
import com.cloud.network.IpAddress.State;
import com.cloud.network.Network.Capability;
import com.cloud.network.Network.GuestType;
import com.cloud.network.Network.Provider;
import com.cloud.network.Network.Service;
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.PhysicalNetwork.BroadcastDomainRange;
import com.cloud.network.addr.PublicIp;
import com.cloud.network.dao.FirewallRulesDao;
import com.cloud.network.dao.IPAddressDao;
import com.cloud.network.dao.LoadBalancerDao;
import com.cloud.network.dao.NetworkDao;
import com.cloud.network.dao.NetworkDomainDao;
import com.cloud.network.dao.NetworkServiceMapDao;
import com.cloud.network.dao.PhysicalNetworkDao;
import com.cloud.network.dao.PhysicalNetworkServiceProviderDao;
import com.cloud.network.dao.PhysicalNetworkServiceProviderVO;
import com.cloud.network.dao.PhysicalNetworkTrafficTypeDao;
import com.cloud.network.dao.PhysicalNetworkTrafficTypeVO;
import com.cloud.network.element.DhcpServiceProvider;
import com.cloud.network.element.FirewallServiceProvider;
import com.cloud.network.element.IpDeployer;
import com.cloud.network.element.LoadBalancingServiceProvider;
import com.cloud.network.element.NetworkElement;
import com.cloud.network.element.PortForwardingServiceProvider;
import com.cloud.network.element.RemoteAccessVPNServiceProvider;
import com.cloud.network.element.SourceNatServiceProvider;
import com.cloud.network.element.StaticNatServiceProvider;
import com.cloud.network.element.UserDataServiceProvider;
import com.cloud.network.element.VirtualRouterElement;
import com.cloud.network.guru.NetworkGuru;
import com.cloud.network.lb.LoadBalancingRule;
import com.cloud.network.lb.LoadBalancingRule.LbDestination;
import com.cloud.network.lb.LoadBalancingRule.LbStickinessPolicy;
import com.cloud.network.lb.LoadBalancingRulesManager;
import com.cloud.network.rules.FirewallManager;
import com.cloud.network.rules.FirewallRule;
import com.cloud.network.rules.FirewallRule.Purpose;
import com.cloud.network.rules.FirewallRuleVO;
import com.cloud.network.rules.PortForwardingRule;
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.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.NetworkOfferingServiceMapDao;
import com.cloud.org.Grouping;
import com.cloud.projects.Project;
import com.cloud.projects.ProjectManager;
import com.cloud.user.Account;
import com.cloud.user.AccountManager;
import com.cloud.user.AccountVO;
import com.cloud.user.DomainManager;
import com.cloud.user.ResourceLimitService;
import com.cloud.user.User;
import com.cloud.user.UserContext;
import com.cloud.user.dao.AccountDao;
import com.cloud.user.dao.UserStatisticsDao;
import com.cloud.utils.AnnotationHelper;
import com.cloud.utils.NumbersUtil;
import com.cloud.utils.Pair;
import com.cloud.utils.component.Adapters;
import com.cloud.utils.component.Inject;
import com.cloud.utils.component.Manager;
import com.cloud.utils.concurrency.NamedThreadFactory;
import com.cloud.utils.db.DB;
import com.cloud.utils.db.Filter;
import com.cloud.utils.db.JoinBuilder;
import com.cloud.utils.db.JoinBuilder.JoinType;
import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria;
import com.cloud.utils.db.SearchCriteria.Op;
import com.cloud.utils.db.Transaction;
import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.utils.net.Ip;
import com.cloud.utils.net.NetUtils;
import com.cloud.vm.Nic;
import com.cloud.vm.NicProfile;
import com.cloud.vm.NicVO;
import com.cloud.vm.ReservationContext;
import com.cloud.vm.ReservationContextImpl;
import com.cloud.vm.SecondaryStorageVmVO;
import com.cloud.vm.UserVmVO;
import com.cloud.vm.VMInstanceVO;
import com.cloud.vm.VirtualMachine;
import com.cloud.vm.VirtualMachine.Type;
import com.cloud.vm.VirtualMachineProfile;
import com.cloud.vm.dao.DomainRouterDao;
import com.cloud.vm.dao.NicDao;
import com.cloud.vm.dao.UserVmDao;
import com.cloud.vm.dao.VMInstanceDao;
import edu.emory.mathcs.backport.java.util.Collections;
/**
* NetworkManagerImpl implements NetworkManager.
*/
@Local(value = { NetworkManager.class, NetworkService.class })
public class NetworkManagerImpl implements NetworkManager, NetworkService, Manager, Listener {
private static final Logger s_logger = Logger.getLogger(NetworkManagerImpl.class);
String _name;
@Inject
DataCenterDao _dcDao = null;
@Inject
VlanDao _vlanDao = null;
@Inject
IPAddressDao _ipAddressDao = null;
@Inject
AccountDao _accountDao = null;
@Inject
DomainDao _domainDao = null;
@Inject
UserStatisticsDao _userStatsDao = null;
@Inject
EventDao _eventDao = null;
@Inject
ConfigurationDao _configDao;
@Inject
UserVmDao _userVmDao = null;
@Inject
ResourceLimitDao _limitDao = null;
@Inject
CapacityDao _capacityDao = null;
@Inject
AlertManager _alertMgr;
@Inject
AccountManager _accountMgr;
@Inject
ConfigurationManager _configMgr;
@Inject
AccountVlanMapDao _accountVlanMapDao;
@Inject
NetworkOfferingDao _networkOfferingDao = null;
@Inject
NetworkDao _networksDao = null;
@Inject
NicDao _nicDao = null;
@Inject
FirewallRulesDao _fwRulesDao = null;
@Inject
RulesManager _rulesMgr;
@Inject
LoadBalancingRulesManager _lbMgr;
@Inject
UsageEventDao _usageEventDao;
@Inject
RemoteAccessVpnService _vpnMgr;
@Inject
PodVlanMapDao _podVlanMapDao;
@Inject(adapter = NetworkGuru.class)
Adapters _networkGurus;
@Inject(adapter = NetworkElement.class)
Adapters _networkElements;
@Inject
NetworkDomainDao _networkDomainDao;
@Inject
VMInstanceDao _vmDao;
@Inject
FirewallManager _firewallMgr;
@Inject
FirewallRulesDao _firewallDao;
@Inject
PortForwardingRulesDao _portForwardingDao;
@Inject
ResourceLimitService _resourceLimitMgr;
@Inject
DomainRouterDao _routerDao;
@Inject
DomainManager _domainMgr;
@Inject
ProjectManager _projectMgr;
@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;
private final HashMap _systemNetworks = new HashMap(5);
ScheduledExecutorService _executor;
SearchBuilder AccountsUsingNetworkSearch;
SearchBuilder AssignIpAddressSearch;
SearchBuilder AssignIpAddressFromPodVlanSearch;
SearchBuilder IpAddressSearch;
SearchBuilder NicForTrafficTypeSearch;
int _networkGcWait;
int _networkGcInterval;
String _networkDomain;
int _cidrLimit;
boolean _allowSubdomainNetworkAccess;
int _networkLockTimeout;
private Map _configs;
HashMap _lastNetworkIdsToFree = new HashMap();
private static HashMap> s_serviceToImplementedProvidersMap = new HashMap>();
private static HashMap s_providerToNetworkElementMap = new HashMap();
public NetworkElement getElementImplementingProvider(String providerName) {
String elementName = s_providerToNetworkElementMap.get(providerName);
NetworkElement element = _networkElements.get(elementName);
return element;
}
@Override
public List getElementServices(Provider provider) {
NetworkElement element = getElementImplementingProvider(provider.getName());
if (element == null) {
throw new InvalidParameterValueException("Unable to find the Network Element implementing the Service Provider '" + provider.getName() + "'");
}
return new ArrayList(element.getCapabilities().keySet());
}
@Override
public boolean canElementEnableIndividualServices(Provider provider) {
NetworkElement element = getElementImplementingProvider(provider.getName());
if (element == null) {
throw new InvalidParameterValueException("Unable to find the Network Element implementing the Service Provider '" + provider.getName() + "'");
}
return element.canEnableIndividualServices();
}
@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);
}
@DB
public PublicIp fetchNewPublicIp(long dcId, Long podId, Long vlanDbId, Account owner, VlanType vlanUse, Long networkId, boolean sourceNat, boolean assign, String requestedIp, boolean isSystem)
throws InsufficientAddressCapacityException {
StringBuilder errorMessage = new StringBuilder("Unable to get ip adress in ");
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 (vlanDbId != null) {
sc.addAnd("vlanId", SearchCriteria.Op.EQ, vlanDbId);
errorMessage.append(", vlanId id=" + vlanDbId);
}
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", networkId);
errorMessage.append(", network id=" + networkId);
}
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 (addrs.size() == 0) {
if (podId != null) {
throw new InsufficientAddressCapacityException("Insufficient address capacity", Pod.class, podId);
}
s_logger.warn(errorMessage.toString());
throw new InsufficientAddressCapacityException("Insufficient address capacity", DataCenter.class, dcId);
}
assert (addrs.size() == 1) : "Return size is incorrect: " + addrs.size();
IPAddressVO addr = addrs.get(0);
addr.setSourceNat(sourceNat);
addr.setAllocatedTime(new Date());
addr.setAllocatedInDomainId(owner.getDomainId());
addr.setAllocatedToAccountId(owner.getId());
addr.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(networkId);
}
_ipAddressDao.update(addr.getId(), addr);
txn.commit();
if (vlanUse == VlanType.VirtualNetwork) {
_firewallMgr.addSystemFirewallRules(addr, owner);
}
long macAddress = NetUtils.createSequenceBasedMacAddress(addr.getMacAddress());
return new PublicIp(addr, _vlanDao.findById(addr.getVlanId()), macAddress);
}
@DB
protected void markPublicIpAsAllocated(IPAddressVO addr) {
assert (addr.getState() == IpAddress.State.Allocating || addr.getState() == IpAddress.State.Free) : "Unable to transition from state " + addr.getState() + " to " + IpAddress.State.Allocated;
Transaction txn = Transaction.currentTxn();
Account owner = _accountMgr.getAccount(addr.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();
UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_NET_IP_ASSIGN, owner.getId(), addr.getDataCenterId(), addr.getId(), addr.getAddress().toString(), addr.isSourceNat(), guestType, addr.getSystem());
_usageEventDao.persist(usageEvent);
// don't increment resource count for direct ip addresses
if (addr.getAssociatedWithNetworkId() != null) {
_resourceLimitMgr.incrementResourceCount(owner.getId(), ResourceType.public_ip);
}
}
txn.commit();
}
@Override
@DB
public PublicIp assignSourceNatIpAddress(Account owner, Network network, long callerId) throws ConcurrentOperationException, InsufficientAddressCapacityException {
assert (network.getTrafficType() != null) : "You're asking for a source nat but your network can't participate in source nat. What do you have to say for yourself?";
long dcId = network.getDataCenterId();
long ownerId = owner.getId();
PublicIp ip = null;
Transaction txn = Transaction.currentTxn();
try {
txn.start();
owner = _accountDao.acquireInLockTable(ownerId);
if (owner == null) {
// 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");
}
IPAddressVO sourceNat = null;
List addrs = listPublicIpAddressesInVirtualNetwork(ownerId, dcId, null, network.getId());
if (addrs.size() == 0) {
// 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.");
}
if (s_logger.isDebugEnabled()) {
s_logger.debug("assigning a new ip address in " + dcId + " to " + owner);
}
// If account has Account specific ip ranges, try to allocate ip from there
Long vlanId = null;
List maps = _accountVlanMapDao.listAccountVlanMapsByAccount(ownerId);
if (maps != null && !maps.isEmpty()) {
vlanId = maps.get(0).getVlanDbId();
}
ip = fetchNewPublicIp(dcId, null, vlanId, owner, VlanType.VirtualNetwork, network.getId(), true, false, null, false);
sourceNat = ip.ip();
markPublicIpAsAllocated(sourceNat);
_ipAddressDao.update(sourceNat.getId(), sourceNat);
} else {
// Account already has ip addresses
for (IPAddressVO addr : addrs) {
if (addr.isSourceNat()) {
sourceNat = addr;
break;
}
}
assert (sourceNat != null) : "How do we get a bunch of ip addresses but none of them are source nat? account=" + ownerId + "; dc=" + dcId;
ip = new PublicIp(sourceNat, _vlanDao.findById(sourceNat.getVlanId()), NetUtils.createSequenceBasedMacAddress(sourceNat.getMacAddress()));
}
txn.commit();
return ip;
} finally {
if (owner != null) {
if (s_logger.isDebugEnabled()) {
s_logger.debug("Releasing lock account " + ownerId);
}
_accountDao.releaseFromLockTable(ownerId);
}
if (ip == null) {
txn.rollback();
s_logger.error("Unable to get source nat ip address for account " + ownerId);
}
}
}
/**
* Returns the target account for an api command
*
* @param accountName
* - non-null if the account name was passed in in the command
* @param domainId
* - non-null if the domainId was passed in in the command.
* @return
*/
protected Account getAccountForApiCommand(String accountName, Long domainId) {
Account account = UserContext.current().getCaller();
if (_accountMgr.isAdmin(account.getType())) {
// The admin is making the call, determine if it is for someone else or for himself
if (domainId != null) {
if ((account != null) && !_domainDao.isChildDomain(account.getDomainId(), domainId)) {
// TBD: Check if call to addProxyObject() needs correction.
PermissionDeniedException ex = new PermissionDeniedException("Invalid domain id given, permission denied");
ex.addProxyObject("domain", domainId, "domainId");
throw ex;
}
if (accountName != null) {
Account userAccount = _accountMgr.getActiveAccountByName(accountName, domainId);
if (userAccount != null) {
account = userAccount;
} else {
// TBD: Check if call to addProxyObject() needs correction.
PermissionDeniedException ex = new PermissionDeniedException("Unable to find account " + accountName + " in specified domain, permission denied");
ex.addProxyObject("domain", domainId, "domainId");
throw ex;
}
}
} else {
// the admin is calling the api on his own behalf
return account;
}
}
return account;
}
@Override
public boolean applyIpAssociations(Network network, boolean continueOnError) throws ResourceUnavailableException {
List userIps = _ipAddressDao.listByAssociatedNetwork(network.getId(), null);
List publicIps = new ArrayList();
if (userIps != null && !userIps.isEmpty()) {
for (IPAddressVO userIp : userIps) {
PublicIp publicIp = new PublicIp(userIp, _vlanDao.findById(userIp.getVlanId()), NetUtils.createSequenceBasedMacAddress(userIp.getMacAddress()));
publicIps.add(publicIp);
}
}
boolean success = applyIpAssociations(network, false, continueOnError, publicIps);
if (success) {
for (IPAddressVO addr : userIps) {
if (addr.getState() == IpAddress.State.Allocating) {
addr.setAssociatedWithNetworkId(network.getId());
markPublicIpAsAllocated(addr);
} else if (addr.getState() == IpAddress.State.Releasing) {
// 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())) {
_ipAddressDao.unassignIpAddress(addr.getId());
} else {
success = false;
s_logger.warn("Failed to release resources for ip address id=" + addr.getId());
}
}
}
}
return success;
}
private Map> getProviderServicesMap(long networkId) {
Map> map = new HashMap>();
List nsms = _ntwkSrvcDao.getServicesInNetwork(networkId);
for (NetworkServiceMapVO nsm : nsms) {
Set services = map.get(Provider.getProvider(nsm.getProvider()));
if (services == null) {
services = new HashSet();
}
services.add(Service.getService(nsm.getService()));
map.put(Provider.getProvider(nsm.getProvider()), services);
}
return map;
}
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;
}
/* Get a list of IPs, classify them by service */
@Override
public Map> getIpToServices(List publicIps, boolean rulesRevoked, boolean includingFirewall) {
Map> ipToServices = new HashMap>();
if (publicIps != null && !publicIps.isEmpty()) {
Set networkSNAT = new HashSet();
for (PublicIp ip : publicIps) {
Set services = ipToServices.get(ip);
if (services == null) {
services = new HashSet();
}
if (ip.isSourceNat()) {
if (!networkSNAT.contains(ip.getAssociatedWithNetworkId())) {
services.add(Service.SourceNat);
networkSNAT.add(ip.getAssociatedWithNetworkId());
} else {
CloudRuntimeException ex = new CloudRuntimeException("Multiple generic soure NAT IPs provided for network");
// see the IPAddressVO.java class.
ex.addProxyObject("user_ip_address", ip.getAssociatedWithNetworkId(), "networkId");
throw ex;
}
}
ipToServices.put(ip, services);
// if IP in allocating state then it will not have any rules attached so skip IPAssoc to network service
// provider
if (ip.getState() == State.Allocating) {
continue;
}
// check if any active rules are applied on the public IP
Set purposes = getPublicIpPurposeInRules(ip, false, includingFirewall);
// Firewall rules didn't cover static NAT
if (ip.isOneToOneNat() && ip.getAssociatedWithVmId() != null) {
if (purposes == null) {
purposes = new HashSet();
}
purposes.add(Purpose.StaticNat);
}
if (purposes == null || purposes.isEmpty()) {
// since no active rules are there check if any rules are applied on the public IP but are in
// revoking state
purposes = getPublicIpPurposeInRules(ip, true, includingFirewall);
if (ip.isOneToOneNat()) {
if (purposes == null) {
purposes = new HashSet();
}
purposes.add(Purpose.StaticNat);
}
if (purposes == null || purposes.isEmpty()) {
// IP is not being used for any purpose so skip IPAssoc to network service provider
continue;
} else {
if (rulesRevoked) {
// no active rules/revoked rules are associated with this public IP, so remove the
// association with the provider
ip.setState(State.Releasing);
} else {
if (ip.getState() == State.Releasing) {
// rules are not revoked yet, so don't let the network service provider revoke the IP
// association
// mark IP is allocated so that IP association will not be removed from the provider
ip.setState(State.Allocated);
}
}
}
}
if (purposes.contains(Purpose.StaticNat)) {
services.add(Service.StaticNat);
}
if (purposes.contains(Purpose.LoadBalancing)) {
services.add(Service.Lb);
}
if (purposes.contains(Purpose.PortForwarding)) {
services.add(Service.PortForwarding);
}
if (purposes.contains(Purpose.Vpn)) {
services.add(Service.Vpn);
}
if (purposes.contains(Purpose.Firewall)) {
services.add(Service.Firewall);
}
if (services.isEmpty()) {
continue;
}
ipToServices.put(ip, services);
}
}
return ipToServices;
}
public boolean canIpUsedForNonConserveService(PublicIp ip, Service service) {
// If it's non-conserve mode, then the new ip should not be used by any other services
List ipList = new ArrayList();
ipList.add(ip);
Map> ipToServices = getIpToServices(ipList, false, false);
Set services = ipToServices.get(ip);
// Not used currently, safe
if (services == null || services.isEmpty()) {
return true;
}
// Since it's non-conserve mode, only one service should used for IP
if (services.size() != 1) {
throw new InvalidParameterException("There are multiple services used ip " + ip.getAddress() + ".");
}
if (service != null && !((Service) services.toArray()[0] == service || service.equals(Service.Firewall))) {
throw new InvalidParameterException("The IP " + ip.getAddress() + " is already used as " + ((Service) services.toArray()[0]).getName() + " rather than " + service.getName());
}
return true;
}
protected boolean canIpsUsedForNonConserve(List publicIps) {
boolean result = true;
for (PublicIp ip : publicIps) {
result = canIpUsedForNonConserveService(ip, null);
if (!result) {
break;
}
}
return result;
}
public boolean canIpsUseOffering(List publicIps, long offeringId) {
Map> ipToServices = getIpToServices(publicIps, false, true);
Map> serviceToProviders = getNetworkOfferingServiceProvidersMap(offeringId);
for (PublicIp ip : ipToServices.keySet()) {
Set services = ipToServices.get(ip);
Provider provider = null;
for (Service service : services) {
Set curProviders = serviceToProviders.get(service);
if (curProviders == null || curProviders.isEmpty()) {
continue;
}
Provider curProvider = (Provider) curProviders.toArray()[0];
if (provider == null) {
provider = curProvider;
continue;
}
// We don't support multiple providers for one service now
if (!provider.equals(curProvider)) {
throw new InvalidParameterException("There would be multiple providers for IP " + ip.getAddress() + " with the new network offering!");
}
}
}
return true;
}
public boolean canIpUsedForService(PublicIp publicIp, Service service) {
List ipList = new ArrayList();
ipList.add(publicIp);
Map> ipToServices = getIpToServices(ipList, false, true);
Set services = ipToServices.get(publicIp);
if (services == null || services.isEmpty()) {
return true;
}
// We only support one provider for one service now
Map> serviceToProviders = getServiceProvidersMap(publicIp.getAssociatedWithNetworkId());
Set oldProviders = serviceToProviders.get((Service) services.toArray()[0]);
Provider oldProvider = (Provider) oldProviders.toArray()[0];
// Since IP already has service to bind with, the oldProvider can't be null
Set newProviders = serviceToProviders.get(service);
if (newProviders == null || newProviders.isEmpty()) {
throw new InvalidParameterException("There is no new provider for IP " + publicIp.getAddress() + " of service " + service.getName() + "!");
}
Provider newProvider = (Provider) newProviders.toArray()[0];
if (!oldProvider.equals(newProvider)) {
throw new InvalidParameterException("There would be multiple providers for IP " + publicIp.getAddress() + "!");
}
return true;
}
/* Return a mapping between provider in the network and the IP they should applied */
@Override
public Map> getProviderToIpList(Network network, Map> ipToServices) {
NetworkOffering offering = _networkOfferingDao.findById(network.getNetworkOfferingId());
if (!offering.isConserveMode()) {
for (PublicIp ip : ipToServices.keySet()) {
Set services = ipToServices.get(ip);
if (services != null && services.size() > 1) {
throw new CloudRuntimeException("Ip " + ip.getAddress() + " is used by multiple services!");
}
}
}
Map> serviceToIps = new HashMap>();
for (PublicIp ip : ipToServices.keySet()) {
for (Service service : ipToServices.get(ip)) {
Set ips = serviceToIps.get(service);
if (ips == null) {
ips = new HashSet();
}
ips.add(ip);
serviceToIps.put(service, ips);
}
}
// TODO Check different provider for same IP
Map> providerToServices = getProviderServicesMap(network.getId());
Map> providerToIpList = new HashMap>();
for (Provider provider : providerToServices.keySet()) {
Set services = providerToServices.get(provider);
ArrayList ipList = new ArrayList();
Set ipSet = new HashSet();
for (Service service : services) {
Set serviceIps = serviceToIps.get(service);
if (serviceIps == null || serviceIps.isEmpty()) {
continue;
}
ipSet.addAll(serviceIps);
}
Set sourceNatIps = serviceToIps.get(Service.SourceNat);
if (sourceNatIps != null && !sourceNatIps.isEmpty()) {
ipList.addAll(0, sourceNatIps);
ipSet.removeAll(sourceNatIps);
}
ipList.addAll(ipSet);
providerToIpList.put(provider, ipList);
}
return providerToIpList;
}
protected boolean applyIpAssociations(Network network, boolean rulesRevoked, boolean continueOnError, List publicIps) throws ResourceUnavailableException {
boolean success = true;
Map> ipToServices = getIpToServices(publicIps, rulesRevoked, false);
Map> providerToIpList = 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 = getElementImplementingProvider(provider.getName());
if (element instanceof SourceNatServiceProvider) {
deployer = ((SourceNatServiceProvider) element).getIpDeployer(network);
} else if (element instanceof StaticNatServiceProvider) {
deployer = ((StaticNatServiceProvider) element).getIpDeployer(network);
} else if (element instanceof LoadBalancingServiceProvider) {
deployer = ((LoadBalancingServiceProvider) element).getIpDeployer(network);
} else if (element instanceof PortForwardingServiceProvider) {
deployer = ((PortForwardingServiceProvider) element).getIpDeployer(network);
} else if (element instanceof RemoteAccessVPNServiceProvider) {
deployer = ((RemoteAccessVPNServiceProvider) element).getIpDeployer(network);
} else {
throw new CloudRuntimeException("Fail to get ip deployer for element: " + element);
}
//We would apply all the existed firewall rules for this IP, since the rule maybe discard by revoke PF/LB rules
List firewallRules = new ArrayList();
boolean applyFirewallRules = false;
if (element instanceof FirewallServiceProvider &&
isProviderSupportServiceInNetwork(network.getId(), Service.Firewall, provider)) {
applyFirewallRules = true;
}
Set services = new HashSet();
for (PublicIp ip : ips) {
if (!ipToServices.containsKey(ip)) {
continue;
}
services.addAll(ipToServices.get(ip));
if (applyFirewallRules) {
firewallRules.addAll(_fwRulesDao.listByIpAndPurpose(ip.getId(), Purpose.Firewall));
}
}
deployer.applyIps(network, ips, services);
if (applyFirewallRules && !firewallRules.isEmpty()) {
((FirewallServiceProvider) element).applyFWRules(network, firewallRules);
}
} catch (ResourceUnavailableException e) {
success = false;
if (!continueOnError) {
throw e;
} else {
s_logger.debug("Resource is not available: " + provider.getName(), e);
}
}
}
return success;
}
Set getPublicIpPurposeInRules(PublicIp ip, boolean includeRevoked, boolean includingFirewall) {
Set result = new HashSet();
List rules = null;
if (includeRevoked) {
rules = _firewallDao.listByIp(ip.getId());
} else {
rules = _firewallDao.listByIpAndNotRevoked(ip.getId());
}
if (rules == null || rules.isEmpty()) {
return null;
}
for (FirewallRuleVO rule : rules) {
if (rule.getPurpose() != Purpose.Firewall || includingFirewall) {
result.add(rule.getPurpose());
}
}
return result;
}
@Override
public List extends Network> getIsolatedNetworksOwnedByAccountInZone(long zoneId, Account owner) {
return _networksDao.listBy(owner.getId(), zoneId, Network.GuestType.Isolated);
}
@Override
public List extends Network> getIsolatedNetworksWithSourceNATOwnedByAccountInZone(long zoneId, Account owner) {
return _networksDao.listSourceNATEnabledNetworks(owner.getId(), zoneId, Network.GuestType.Isolated);
}
@Override
@DB
@ActionEvent(eventType = EventTypes.EVENT_NET_IP_ASSIGN, eventDescription = "allocating Ip", create = true)
public IpAddress allocateIP(long networkId, Account ipOwner, boolean isSystem) throws ResourceAllocationException, InsufficientAddressCapacityException, ConcurrentOperationException {
Account caller = UserContext.current().getCaller();
long userId = UserContext.current().getCallerUserId();
long ownerId = ipOwner.getId();
Network network = _networksDao.findById(networkId);
if (network == null) {
InvalidParameterValueException ex = new InvalidParameterValueException("Network id is invalid");
ex.addProxyObject(network, networkId, "networkId");
throw ex;
}
// check permissions
_accountMgr.checkAccess(caller, null, false, ipOwner);
_accountMgr.checkAccess(ipOwner, AccessType.UseNetwork, false, network);
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);
}
// In Advance zone only allow to do IP assoc for Isolated networks with source nat service enabled
if (zone.getNetworkType() == NetworkType.Advanced && !(network.getGuestType() == GuestType.Isolated && 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");
}
// Check that network belongs to IP owner - skip this check for Basic zone as there is just one guest network,
// and it
// belongs to the system
if (zone.getNetworkType() != NetworkType.Basic && network.getAccountId() != ipOwner.getId()) {
throw new InvalidParameterValueException("The owner of the network is not the same as owner of the IP");
}
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 with specified id is currently disabled");
ex.addProxyObject(zone, 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 for user " + userId + " account " + ownerId);
}
accountToLock = _accountDao.acquireInLockTable(ownerId);
if (accountToLock == null) {
s_logger.warn("Unable to lock account: " + ownerId);
throw new ConcurrentOperationException("Unable to acquire account lock");
}
if (s_logger.isDebugEnabled()) {
s_logger.debug("Associate IP address lock acquired");
}
// Check that the maximum number of public IPs for the given
// accountId will not be exceeded
_resourceLimitMgr.checkResourceLimit(accountToLock, ResourceType.public_ip);
boolean isSourceNat = false;
txn.start();
NetworkOffering offering = _networkOfferingDao.findById(network.getNetworkOfferingId());
boolean sharedSourceNat = offering.getSharedSourceNat();
if (!sharedSourceNat) {
// First IP address should be source nat when it's being associated with Guest Virtual network
List addrs = listPublicIpAddressesInVirtualNetwork(ownerId, zone.getId(), true, networkId);
if (addrs.isEmpty() && network.getGuestType() == Network.GuestType.Isolated) {
isSourceNat = true;
}
}
ip = fetchNewPublicIp(zone.getId(), null, null, ipOwner, vlanType, network.getId(), isSourceNat, assign, null, isSystem);
if (ip == null) {
InsufficientAddressCapacityException ex = new InsufficientAddressCapacityException("Unable to find available public IP addresses", DataCenter.class, zone.getId());
}
UserContext.current().setEventDetails("Ip Id: " + ip.getId());
Ip ipAddress = ip.getAddress();
s_logger.debug("Got " + ipAddress + " to assign for account " + ipOwner.getId() + " in zone " + network.getDataCenterId());
txn.commit();
} finally {
if (accountToLock != null) {
_accountDao.releaseFromLockTable(ownerId);
s_logger.debug("Associate IP address lock released");
}
}
return ip;
}
@Override
@DB
@ActionEvent(eventType = EventTypes.EVENT_NET_IP_ASSIGN, eventDescription = "associating Ip", async = true)
public IpAddress associateIP(long ipId) throws ResourceAllocationException, ResourceUnavailableException, InsufficientAddressCapacityException, ConcurrentOperationException {
Account caller = UserContext.current().getCaller();
Account owner = null;
IpAddress ipToAssoc = getIp(ipId);
if (ipToAssoc != null) {
_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;
}
Network network = _networksDao.findById(ipToAssoc.getAssociatedWithNetworkId());
IPAddressVO ip = _ipAddressDao.findById(ipId);
boolean success = false;
try {
success = applyIpAssociations(network, false);
if (success) {
s_logger.debug("Successfully associated ip address " + ip.getAddress().addr() + " for account " + owner.getId() + " in zone " + network.getDataCenterId());
} else {
s_logger.warn("Failed to associate ip address " + ip.getAddress().addr() + " for account " + owner.getId() + " in zone " + network.getDataCenterId());
}
return ip;
} catch (ResourceUnavailableException e) {
s_logger.error("Unable to associate ip address due to resource unavailable exception", e);
return null;
} finally {
if (!success) {
if (ip != null) {
try {
s_logger.warn("Failed to associate ip address " + ip);
_ipAddressDao.markAsUnavailable(ip.getId());
if (!applyIpAssociations(network, true)) {
// if fail to apply ip assciations again, unassign ip address without updating resource
// count and
// generating usage event as there is no need to keep it in the db
_ipAddressDao.unassignIpAddress(ip.getId());
}
} catch (Exception e) {
s_logger.warn("Unable to disassociate ip address for recovery", e);
}
}
}
}
}
@Override
@DB
public boolean releasePublicIpAddress(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);
}
}
if (success) {
s_logger.debug("released a public ip id=" + addrId);
}
return success;
}
@Override
@DB
public boolean configure(final String name, final Map params) throws ConfigurationException {
_name = name;
_configs = _configDao.getConfiguration("AgentManager", params);
_networkGcWait = NumbersUtil.parseInt(_configs.get(Config.NetworkGcWait.key()), 600);
_networkGcInterval = NumbersUtil.parseInt(_configs.get(Config.NetworkGcInterval.key()), 600);
_configs = _configDao.getConfiguration("Network", params);
_networkDomain = _configs.get(Config.GuestDomainSuffix.key());
_cidrLimit = NumbersUtil.parseInt(_configs.get(Config.NetworkGuestCidrLimit.key()), 22);
_networkLockTimeout = NumbersUtil.parseInt(_configs.get(Config.NetworkLockTimeout.key()), 600);
NetworkOfferingVO publicNetworkOffering = new NetworkOfferingVO(NetworkOfferingVO.SystemPublicNetwork, TrafficType.Public, true);
publicNetworkOffering = _networkOfferingDao.persistDefaultNetworkOffering(publicNetworkOffering);
_systemNetworks.put(NetworkOfferingVO.SystemPublicNetwork, publicNetworkOffering);
NetworkOfferingVO managementNetworkOffering = new NetworkOfferingVO(NetworkOfferingVO.SystemManagementNetwork, TrafficType.Management, false);
managementNetworkOffering = _networkOfferingDao.persistDefaultNetworkOffering(managementNetworkOffering);
_systemNetworks.put(NetworkOfferingVO.SystemManagementNetwork, managementNetworkOffering);
NetworkOfferingVO controlNetworkOffering = new NetworkOfferingVO(NetworkOfferingVO.SystemControlNetwork, TrafficType.Control, false);
controlNetworkOffering = _networkOfferingDao.persistDefaultNetworkOffering(controlNetworkOffering);
_systemNetworks.put(NetworkOfferingVO.SystemControlNetwork, controlNetworkOffering);
NetworkOfferingVO storageNetworkOffering = new NetworkOfferingVO(NetworkOfferingVO.SystemStorageNetwork, TrafficType.Storage, true);
storageNetworkOffering = _networkOfferingDao.persistDefaultNetworkOffering(storageNetworkOffering);
_systemNetworks.put(NetworkOfferingVO.SystemStorageNetwork, storageNetworkOffering);
// 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);
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.DefaultSharedNetworkOfferingWithSGService) == null) {
offering = _configMgr.createNetworkOffering(Account.ACCOUNT_ID_SYSTEM, 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);
offering.setState(NetworkOffering.State.Enabled);
_networkOfferingDao.update(offering.getId(), offering);
}
if (_networkOfferingDao.findByUniqueName(NetworkOffering.DefaultSharedNetworkOffering) == null) {
offering = _configMgr.createNetworkOffering(Account.ACCOUNT_ID_SYSTEM, NetworkOffering.DefaultSharedNetworkOffering, "Offering for Shared networks", TrafficType.Guest, null, true, Availability.Optional,
null, defaultSharedNetworkOfferingProviders, true, Network.GuestType.Shared, false, null, true, null, true);
offering.setState(NetworkOffering.State.Enabled);
_networkOfferingDao.update(offering.getId(), offering);
}
if (_networkOfferingDao.findByUniqueName(NetworkOffering.DefaultIsolatedNetworkOfferingWithSourceNatService) == null) {
offering = _configMgr.createNetworkOffering(Account.ACCOUNT_ID_SYSTEM, NetworkOffering.DefaultIsolatedNetworkOfferingWithSourceNatService, "Offering for Isolated networks with Source Nat service enabled",
TrafficType.Guest, null, false, Availability.Required, null, defaultIsolatedSourceNatEnabledNetworkOfferingProviders, true, Network.GuestType.Isolated, false, null, true, null, false);
offering.setState(NetworkOffering.State.Enabled);
_networkOfferingDao.update(offering.getId(), offering);
}
if (_networkOfferingDao.findByUniqueName(NetworkOffering.DefaultIsolatedNetworkOffering) == null) {
offering = _configMgr.createNetworkOffering(Account.ACCOUNT_ID_SYSTEM, 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);
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(Account.ACCOUNT_ID_SYSTEM, 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);
offering.setState(NetworkOffering.State.Enabled);
offering.setDedicatedLB(false);
_networkOfferingDao.update(offering.getId(), offering);
}
txn.commit();
AccountsUsingNetworkSearch = _accountDao.createSearchBuilder();
SearchBuilder networkAccountSearch = _networksDao.createSearchBuilderForAccount();
AccountsUsingNetworkSearch.join("nc", networkAccountSearch, AccountsUsingNetworkSearch.entity().getId(), networkAccountSearch.entity().getAccountId(), JoinType.INNER);
networkAccountSearch.and("config", networkAccountSearch.entity().getNetworkId(), SearchCriteria.Op.EQ);
networkAccountSearch.and("owner", networkAccountSearch.entity().isOwner(), SearchCriteria.Op.EQ);
AccountsUsingNetworkSearch.done();
AssignIpAddressSearch = _ipAddressDao.createSearchBuilder();
AssignIpAddressSearch.and("dc", AssignIpAddressSearch.entity().getDataCenterId(), Op.EQ);
AssignIpAddressSearch.and("allocated", AssignIpAddressSearch.entity().getAllocatedTime(), Op.NULL);
AssignIpAddressSearch.and("vlanId", AssignIpAddressSearch.entity().getVlanId(), Op.EQ);
SearchBuilder 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();
IpAddressSearch = _ipAddressDao.createSearchBuilder();
IpAddressSearch.and("accountId", IpAddressSearch.entity().getAllocatedToAccountId(), Op.EQ);
IpAddressSearch.and("dataCenterId", IpAddressSearch.entity().getDataCenterId(), Op.EQ);
IpAddressSearch.and("associatedWithNetworkId", IpAddressSearch.entity().getAssociatedWithNetworkId(), Op.EQ);
SearchBuilder virtualNetworkVlanSB = _vlanDao.createSearchBuilder();
virtualNetworkVlanSB.and("vlanType", virtualNetworkVlanSB.entity().getVlanType(), Op.EQ);
IpAddressSearch.join("virtualNetworkVlanSB", virtualNetworkVlanSB, IpAddressSearch.entity().getVlanId(), virtualNetworkVlanSB.entity().getId(), JoinBuilder.JoinType.INNER);
IpAddressSearch.done();
NicForTrafficTypeSearch = _nicDao.createSearchBuilder();
SearchBuilder networkSearch = _networksDao.createSearchBuilder();
NicForTrafficTypeSearch.join("network", networkSearch, networkSearch.entity().getId(), NicForTrafficTypeSearch.entity().getNetworkId(), JoinType.INNER);
NicForTrafficTypeSearch.and("instance", NicForTrafficTypeSearch.entity().getInstanceId(), Op.EQ);
networkSearch.and("traffictype", networkSearch.entity().getTrafficType(), Op.EQ);
NicForTrafficTypeSearch.done();
_executor = Executors.newScheduledThreadPool(1, new NamedThreadFactory("Network-Scavenger"));
_allowSubdomainNetworkAccess = Boolean.valueOf(_configs.get(Config.SubDomainNetworkAccess.key()));
_agentMgr.registerForHostEvents(this, true, false, true);
s_logger.info("Network Manager is configured.");
return true;
}
@Override
public String getName() {
return _name;
}
@Override
public boolean start() {
// populate s_serviceToImplementedProvidersMap & s_providerToNetworkElementMap with current _networkElements
// Need to do this in start() since _networkElements are not completely configured until then.
for (NetworkElement element : _networkElements) {
Map> capabilities = element.getCapabilities();
Provider implementedProvider = element.getProvider();
if (implementedProvider != null) {
if (s_providerToNetworkElementMap.containsKey(implementedProvider.getName())) {
s_logger.error("Cannot start NetworkManager: Provider <-> NetworkElement must be a one-to-one map, multiple NetworkElements found for Provider: " + implementedProvider.getName());
return false;
}
s_providerToNetworkElementMap.put(implementedProvider.getName(), element.getName());
}
if (capabilities != null && implementedProvider != null) {
for (Service service : capabilities.keySet()) {
if (s_serviceToImplementedProvidersMap.containsKey(service)) {
List providers = s_serviceToImplementedProvidersMap.get(service);
providers.add(implementedProvider);
} else {
List providers = new ArrayList();
providers.add(implementedProvider);
s_serviceToImplementedProvidersMap.put(service, providers);
}
}
}
}
_executor.scheduleWithFixedDelay(new NetworkGarbageCollector(), _networkGcInterval, _networkGcInterval, TimeUnit.SECONDS);
return true;
}
@Override
public boolean stop() {
return true;
}
protected NetworkManagerImpl() {
}
@Override
public List listPublicIpAddressesInVirtualNetwork(long accountId, long dcId, Boolean sourceNat, Long associatedNetworkId) {
SearchCriteria sc = IpAddressSearch.create();
sc.setParameters("accountId", accountId);
sc.setParameters("dataCenterId", dcId);
if (associatedNetworkId != null) {
sc.setParameters("associatedWithNetworkId", associatedNetworkId);
}
if (sourceNat != null) {
sc.addAnd("sourceNat", SearchCriteria.Op.EQ, sourceNat);
}
sc.setJoinParameters("virtualNetworkVlanSB", "vlanType", VlanType.VirtualNetwork);
return _ipAddressDao.search(sc, null);
}
@Override
public List setupNetwork(Account owner, NetworkOfferingVO offering, DeploymentPlan plan, String name, String displayText, boolean isDefault)
throws ConcurrentOperationException {
return setupNetwork(owner, offering, null, plan, name, displayText, false, null, null, null);
}
@Override
@DB
public List setupNetwork(Account owner, NetworkOfferingVO offering, Network predefined, DeploymentPlan plan, String name, String displayText, boolean errorIfAlreadySetup, Long domainId,
ACLType aclType, Boolean subdomainAccess) 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)) {
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) {
// 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());
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());
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
public List getSystemAccountNetworkOfferings(String... offeringNames) {
List offerings = new ArrayList(offeringNames.length);
for (String offeringName : offeringNames) {
NetworkOfferingVO network = _systemNetworks.get(offeringName);
if (network == null) {
throw new CloudRuntimeException("Unable to find system network profile for " + offeringName);
}
offerings.add(network);
}
return offerings;
}
@Override
@DB
public void allocate(VirtualMachineProfile extends VMInstanceVO> vm, List> 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());
NicVO defaultNic = null;
for (Pair network : networks) {
NetworkVO config = network.first();
NetworkGuru guru = _networkGurus.get(config.getGuruName());
NicProfile requested = network.second();
if (requested != null && requested.getMode() == null) {
requested.setMode(config.getMode());
}
NicProfile profile = guru.allocate(config, requested, vm);
if (vm != null && vm.getVirtualMachine().getType() == Type.User && (requested != null && requested.isDefaultNic())) {
profile.setDefaultNic(true);
}
if (profile == null) {
continue;
}
if (requested != null && requested.getMode() == null) {
profile.setMode(requested.getMode());
} else {
profile.setMode(config.getMode());
}
NicVO vo = new NicVO(guru.getName(), vm.getId(), config.getId(), vm.getType());
while (deviceIds[deviceId] && deviceId < deviceIds.length) {
deviceId++;
}
deviceId = applyProfileToNic(vo, profile, deviceId);
vo = _nicDao.persist(vo);
if (vo.isDefaultNic()) {
if (defaultNic != null) {
throw new IllegalArgumentException("You cannot specify two nics as default nics: nic 1 = " + defaultNic + "; nic 2 = " + vo);
}
defaultNic = vo;
}
int devId = vo.getDeviceId();
if (devId > deviceIds.length) {
throw new IllegalArgumentException("Device id for nic is too large: " + vo);
}
if (deviceIds[devId]) {
throw new IllegalArgumentException("Conflicting device id for two different nics: " + devId);
}
deviceIds[devId] = true;
nics.add(vo);
Integer networkRate = getNetworkRate(config.getId(), vm.getId());
vm.addNic(new NicProfile(vo, network.first(), vo.getBroadcastUri(), vo.getIsolationUri(), networkRate, isSecurityGroupSupportedInNetwork(network.first()), getNetworkTag(vm.getHypervisorType(),
network.first())));
}
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();
}
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());
if (profile.getIp4Address() != null) {
vo.setIp4Address(profile.getIp4Address());
vo.setAddressFormat(AddressFormat.Ip4);
}
if (profile.getMacAddress() != null) {
vo.setMacAddress(profile.getMacAddress());
}
vo.setMode(profile.getMode());
vo.setNetmask(profile.getNetmask());
vo.setGateway(profile.getGateway());
if (profile.getBroadCastUri() != null) {
vo.setBroadcastUri(profile.getBroadCastUri());
}
if (profile.getIsolationUri() != null) {
vo.setIsolationUri(profile.getIsolationUri());
}
vo.setState(Nic.State.Allocated);
return deviceId;
}
protected void applyProfileToNicForRelease(NicVO vo, NicProfile profile) {
vo.setGateway(profile.getGateway());
vo.setAddressFormat(profile.getFormat());
vo.setIp4Address(profile.getIp4Address());
vo.setIp6Address(profile.getIp6Address());
vo.setMacAddress(profile.getMacAddress());
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 = getNetworkRate(config.getId(), null);
to.setNetworkRateMbps(networkRate);
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("networks", networkId, "networkId");
throw ex;
}
try {
NetworkGuru guru = _networkGurus.get(network.getGuruName());
Network.State state = network.getState();
if (state == Network.State.Implemented || state == Network.State.Setup || state == Network.State.Implementing) {
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());
network.setState(Network.State.Implementing);
_networksDao.update(networkId, network);
Network result = guru.implement(network, offering, dest, context);
network.setCidr(result.getCidr());
network.setBroadcastUri(result.getBroadcastUri());
network.setGateway(result.getGateway());
network.setMode(result.getMode());
network.setPhysicalNetworkId(result.getPhysicalNetworkId());
_networksDao.update(networkId, network);
// implement network elements and re-apply all the network rules
implementNetworkElementsAndResources(dest, context, network, offering);
network.setState(Network.State.Implemented);
network.setRestartRequired(false);
_networksDao.update(network.getId(), network);
implemented.set(guru, network);
return implemented;
} finally {
if (implemented.first() == null) {
s_logger.debug("Cleaning up because we're unable to implement the network " + network);
network.setState(Network.State.Shutdown);
_networksDao.update(networkId, network);
shutdownNetwork(networkId, context, false);
}
_networksDao.releaseFromLockTable(networkId);
}
}
private void implementNetworkElementsAndResources(DeployDestination dest, ReservationContext context, NetworkVO network, NetworkOfferingVO offering)
throws ConcurrentOperationException, InsufficientAddressCapacityException, ResourceUnavailableException, InsufficientCapacityException {
// If this is a 1) guest virtual network 2) network has sourceNat service 3) network offering does not support a
// Shared source NAT rule,
// associate a source NAT IP (if one isn't already associated with the network)
boolean sharedSourceNat = offering.getSharedSourceNat();
if (network.getGuestType() == Network.GuestType.Isolated && areServicesSupportedInNetwork(network.getId(), Service.SourceNat) && !sharedSourceNat) {
List ips = _ipAddressDao.listByAssociatedNetwork(network.getId(), true);
if (ips.isEmpty()) {
s_logger.debug("Creating a source nat ip for " + network);
Account owner = _accountMgr.getAccount(network.getAccountId());
assignSourceNatIpAddress(owner, network, context.getCaller().getId());
}
}
// get providers to implement
List providersToImplement = getNetworkProviders(network.getId());
for (NetworkElement element : _networkElements) {
if (providersToImplement.contains(element.getProvider())) {
if (!isProviderEnabledInPhysicalNetwork(getPhysicalNetworkId(network), "VirtualRouter")) {
// 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("data_center", network.getDataCenterId(), "dataCenterId");
throw ex;
}
}
protected void prepareElement(NetworkElement element, NetworkVO network, NicProfile profile, VirtualMachineProfile extends VMInstanceVO> vmProfile,
DeployDestination dest, ReservationContext context) throws InsufficientCapacityException,
ConcurrentOperationException, ResourceUnavailableException {
element.prepare(network, profile, vmProfile, dest, context);
if (vmProfile.getType() == Type.User && vmProfile.getHypervisorType() != HypervisorType.BareMetal && element.getProvider() != null) {
if (areServicesSupportedInNetwork(network.getId(), Service.Dhcp) &&
isProviderSupportServiceInNetwork(network.getId(), Service.Dhcp, element.getProvider()) &&
(element instanceof DhcpServiceProvider)) {
DhcpServiceProvider sp = (DhcpServiceProvider) element;
sp.addDhcpEntry(network, profile, vmProfile, dest, context);
}
if (areServicesSupportedInNetwork(network.getId(), Service.UserData) &&
isProviderSupportServiceInNetwork(network.getId(), Service.UserData, element.getProvider()) &&
(element instanceof UserDataServiceProvider)) {
UserDataServiceProvider sp = (UserDataServiceProvider) element;
sp.addPasswordAndUserdata(network, profile, vmProfile, dest, context);
}
}
}
@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 && getNetwork(networkId).getTrafficType() == TrafficType.Guest)) {
_networksDao.setCheckForGc(networkId);
}
txn.commit();
}
@Override
public void prepare(VirtualMachineProfile extends VMInstanceVO> 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);
NetworkGuru guru = implemented.first();
NetworkVO network = implemented.second();
Integer networkRate = getNetworkRate(network.getId(), vmProfile.getId());
NicProfile profile = null;
if (nic.getReservationStrategy() == Nic.ReservationStrategy.Start) {
nic.setState(Nic.State.Reserving);
nic.setReservationId(context.getReservationId());
_nicDao.update(nic.getId(), nic);
URI broadcastUri = nic.getBroadcastUri();
if (broadcastUri == null) {
broadcastUri = network.getBroadcastUri();
}
URI isolationUri = nic.getIsolationUri();
profile = new NicProfile(nic, network, broadcastUri, isolationUri, networkRate, isSecurityGroupSupportedInNetwork(network), 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, isSecurityGroupSupportedInNetwork(network), 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);
}
prepareElement(element, network, profile, vmProfile, dest, context);
}
profile.setSecurityGroupEnabled(isSecurityGroupSupportedInNetwork(network));
guru.updateNicProfile(profile, network);
vmProfile.addNic(profile);
}
}
@Override
public void prepareNicForMigration(VirtualMachineProfile vm, DeployDestination dest) {
List nics = _nicDao.listByVmId(vm.getId());
for (NicVO nic : nics) {
NetworkVO network = _networksDao.findById(nic.getNetworkId());
Integer networkRate = getNetworkRate(network.getId(), vm.getId());
NetworkGuru guru = _networkGurus.get(network.getGuruName());
NicProfile profile = new NicProfile(nic, network, nic.getBroadcastUri(), nic.getIsolationUri(), networkRate, isSecurityGroupSupportedInNetwork(network), getNetworkTag(vm.getHypervisorType(), network));
guru.updateNicProfile(profile, network);
vm.addNic(profile);
}
}
@Override
public void release(VirtualMachineProfile extends VMInstanceVO> vmProfile, boolean forced) {
List nics = _nicDao.listByVmId(vmProfile.getId());
for (NicVO nic : nics) {
NetworkVO network = _networksDao.findById(nic.getNetworkId());
if (nic.getState() == Nic.State.Reserved || nic.getState() == Nic.State.Reserving) {
Nic.State originalState = nic.getState();
if (nic.getReservationStrategy() == Nic.ReservationStrategy.Start) {
NetworkGuru guru = _networkGurus.get(network.getGuruName());
nic.setState(Nic.State.Releasing);
_nicDao.update(nic.getId(), nic);
NicProfile profile = new NicProfile(nic, network, nic.getBroadcastUri(), nic.getIsolationUri(), null, isSecurityGroupSupportedInNetwork(network), 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);
}
}
} else {
nic.setState(Nic.State.Allocated);
updateNic(nic, network.getId(), -1);
}
}
}
}
@Override
public List extends Nic> getNics(long vmId) {
return _nicDao.listByVmId(vmId);
}
@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 = getNetworkRate(network.getId(), vm.getId());
NetworkGuru guru = _networkGurus.get(network.getGuruName());
NicProfile profile = new NicProfile(nic, network, nic.getBroadcastUri(), nic.getIsolationUri(), networkRate, isSecurityGroupSupportedInNetwork(network), getNetworkTag(vm.getHypervisorType(), network));
guru.updateNicProfile(profile, network);
profiles.add(profile);
}
}
return profiles;
}
@Override
@DB
@ActionEvent(eventType = EventTypes.EVENT_NET_IP_RELEASE, eventDescription = "disassociating Ip", async = true)
public boolean disassociateIpAddress(long ipAddressId) throws InsufficientAddressCapacityException {
Long userId = UserContext.current().getCallerUserId();
Account caller = UserContext.current().getCaller();
// Verify input parameters
IPAddressVO ipVO = _ipAddressDao.findById(ipAddressId);
if (ipVO == null) {
throw new InvalidParameterValueException("Unable to find ip address by id");
}
if (ipVO.getAllocatedTime() == null) {
s_logger.debug("Ip Address id= " + ipAddressId + " is not allocated, so do nothing.");
return true;
}
// verify permissions
if (ipVO.getAllocatedToAccountId() != null) {
_accountMgr.checkAccess(caller, null, true, ipVO);
}
Network associatedNetwork = getNetwork(ipVO.getAssociatedWithNetworkId());
if (ipVO.isSourceNat() && areServicesSupportedInNetwork(associatedNetwork.getId(), Service.SourceNat)) {
throw new IllegalArgumentException("ip address is used for source nat purposes and can not be disassociated.");
}
VlanVO vlan = _vlanDao.findById(ipVO.getVlanId());
if (!vlan.getVlanType().equals(VlanType.VirtualNetwork)) {
throw new IllegalArgumentException("only ip addresses that belong to a virtual network may be disassociated.");
}
// Check for account wide pool. It will have an entry for account_vlan_map.
if (_accountVlanMapDao.findAccountVlanMap(ipVO.getAllocatedToAccountId(), ipVO.getVlanId()) != null) {
//see IPaddressVO.java
InvalidParameterValueException ex = new InvalidParameterValueException("Sepcified IP address uuid belongs to Account wide IP pool and cannot be disassociated");
ex.addProxyObject(ipVO, ipVO.getId(), "systemIpAddrId");
throw ex;
}
// don't allow releasing system ip address
if (ipVO.getSystem()) {
InvalidParameterValueException ex = new InvalidParameterValueException("Can't release system IP address with specified id");
ex.addProxyObject(ipVO, ipVO.getId(), "systemIpAddrId");
throw ex;
}
boolean success = releasePublicIpAddress(ipAddressId, userId, caller);
if (success) {
Network guestNetwork = getNetwork(ipVO.getAssociatedWithNetworkId());
NetworkOffering offering = _configMgr.getNetworkOffering(guestNetwork.getNetworkOfferingId());
Long vmId = ipVO.getAssociatedWithVmId();
if (offering.getElasticIp() && vmId != null) {
_rulesMgr.getSystemIpAndEnableStaticNatForVm(_userVmDao.findById(vmId), true);
return true;
}
return true;
} else {
s_logger.warn("Failed to release public ip address id=" + ipAddressId);
return false;
}
}
@Deprecated
// No one is using this method.
public AccountVO getNetworkOwner(long networkId) {
SearchCriteria sc = AccountsUsingNetworkSearch.create();
sc.setJoinParameters("nc", "config", networkId);
sc.setJoinParameters("nc", "owner", true);
List accounts = _accountDao.search(sc, null);
return accounts.size() != 0 ? accounts.get(0) : null;
}
@Deprecated
// No one is using this method.
public List getNetworksforOffering(long offeringId, long dataCenterId, long accountId) {
return _networksDao.getNetworksForOffering(offeringId, dataCenterId, accountId);
}
@Override
public String getNextAvailableMacAddressInNetwork(long networkId) throws InsufficientAddressCapacityException {
String mac = _networksDao.getNextAvailableMacAddress(networkId);
if (mac == null) {
throw new InsufficientAddressCapacityException("Unable to create another mac address", Network.class, networkId);
}
return mac;
}
@Override
@DB
public Network getNetwork(long id) {
return _networksDao.findById(id);
}
@Override
public List extends RemoteAccessVPNServiceProvider> getRemoteAccessVpnElements() {
List elements = new ArrayList();
for (NetworkElement element : _networkElements) {
if (element instanceof RemoteAccessVPNServiceProvider) {
RemoteAccessVPNServiceProvider e = (RemoteAccessVPNServiceProvider) element;
elements.add(e);
}
}
return elements;
}
@Override
public void cleanupNics(VirtualMachineProfile extends VMInstanceVO> vm) {
if (s_logger.isDebugEnabled()) {
s_logger.debug("Cleaning network for vm: " + vm.getId());
}
List nics = _nicDao.listByVmId(vm.getId());
for (NicVO nic : nics) {
nic.setState(Nic.State.Deallocating);
_nicDao.update(nic.getId(), nic);
NetworkVO network = _networksDao.findById(nic.getNetworkId());
NicProfile profile = new NicProfile(nic, network, null, null, null, isSecurityGroupSupportedInNetwork(network), getNetworkTag(vm.getHypervisorType(), network));
NetworkGuru guru = _networkGurus.get(network.getGuruName());
guru.deallocate(network, profile, vm);
_nicDao.remove(nic.getId());
}
}
@Override
public void expungeNics(VirtualMachineProfile extends VMInstanceVO> vm) {
List nics = _nicDao.listByVmIdIncludingRemoved(vm.getId());
for (NicVO nic : nics) {
_nicDao.expunge(nic.getId());
}
}
private String getCidrAddress(String cidr) {
String[] cidrPair = cidr.split("\\/");
return cidrPair[0];
}
private int getCidrSize(String cidr) {
String[] cidrPair = cidr.split("\\/");
return Integer.parseInt(cidrPair[1]);
}
@Override
public void checkVirtualNetworkCidrOverlap(Long zoneId, String cidr) {
if (zoneId == null) {
return;
}
if (cidr == null) {
return;
}
List networks = _networksDao.listByZone((long) zoneId);
Map networkToCidr = new HashMap();
for (NetworkVO network : networks) {
if (network.getGuestType() != GuestType.Isolated) {
continue;
}
if (network.getCidr() != null) {
networkToCidr.put(network.getId(), network.getCidr());
}
}
if (networkToCidr == null || networkToCidr.isEmpty()) {
return;
}
String currCidrAddress = getCidrAddress(cidr);
int currCidrSize = getCidrSize(cidr);
for (long networkId : networkToCidr.keySet()) {
String ntwkCidr = networkToCidr.get(networkId);
String ntwkCidrAddress = getCidrAddress(ntwkCidr);
int ntwkCidrSize = getCidrSize(ntwkCidr);
long cidrSizeToUse = currCidrSize < ntwkCidrSize ? currCidrSize : ntwkCidrSize;
String ntwkCidrSubnet = NetUtils.getCidrSubNet(ntwkCidrAddress, cidrSizeToUse);
String cidrSubnet = NetUtils.getCidrSubNet(currCidrAddress, cidrSizeToUse);
if (cidrSubnet.equals(ntwkCidrSubnet)) {
InvalidParameterValueException ex = new InvalidParameterValueException("Warning: The specified existing network has conflict CIDR subnets with new network!");
ex.addProxyObject("networks", networkId, "networkId");
throw ex;
}
}
}
@Override
@DB
@ActionEvent(eventType = EventTypes.EVENT_NETWORK_CREATE, eventDescription = "creating network")
public Network createNetwork(CreateNetworkCmd cmd) throws InsufficientCapacityException, ConcurrentOperationException, ResourceAllocationException {
Long networkOfferingId = cmd.getNetworkOfferingId();
String gateway = cmd.getGateway();
String startIP = cmd.getStartIp();
String endIP = cmd.getEndIp();
String netmask = cmd.getNetmask();
String networkDomain = cmd.getNetworkDomain();
String vlanId = cmd.getVlan();
String name = cmd.getNetworkName();
String displayText = cmd.getDisplayText();
Long userId = UserContext.current().getCallerUserId();
Account caller = UserContext.current().getCaller();
Long physicalNetworkId = cmd.getPhysicalNetworkId();
Long zoneId = cmd.getZoneId();
String aclTypeStr = cmd.getAclType();
Long domainId = cmd.getDomainId();
boolean isDomainSpecific = false;
Boolean subdomainAccess = cmd.getSubdomainAccess();
// Validate network offering
NetworkOfferingVO ntwkOff = _networkOfferingDao.findById(networkOfferingId);
if (ntwkOff == null || ntwkOff.isSystemOnly()) {
InvalidParameterValueException ex = new InvalidParameterValueException("Unable to find network offering by specified id");
if (ntwkOff != null) {
ex.addProxyObject(ntwkOff, networkOfferingId, "networkOfferingId");
throw ex;
}
throw ex;
}
// validate physical network and zone
// Check if physical network exists
PhysicalNetwork pNtwk = null;
if (physicalNetworkId != null) {
pNtwk = _physicalNetworkDao.findById(physicalNetworkId);
if (pNtwk == null) {
throw new InvalidParameterValueException("Unable to find a physical network having the specified physical network id");
}
}
if (zoneId == null) {
zoneId = pNtwk.getDataCenterId();
}
DataCenter zone = _dcDao.findById(zoneId);
if (zone == null) {
throw new InvalidParameterValueException("Specified zone id was not found");
}
if (Grouping.AllocationState.Disabled == zone.getAllocationState() && !_accountMgr.isRootAdmin(caller.getType())) {
// See DataCenterVO.java
PermissionDeniedException ex = new PermissionDeniedException("Cannot perform this operation since specified Zone is currently disabled");
ex.addProxyObject(zone, zoneId, "zoneId");
throw ex;
}
// Only domain and account ACL types are supported in Acton.
ACLType aclType = null;
if (aclTypeStr != null) {
if (aclTypeStr.equalsIgnoreCase(ACLType.Account.toString())) {
aclType = ACLType.Account;
} else if (aclTypeStr.equalsIgnoreCase(ACLType.Domain.toString())) {
aclType = ACLType.Domain;
} else {
throw new InvalidParameterValueException("Incorrect aclType specified. Check the API documentation for supported types");
}
// In 3.0 all Shared networks should have aclType == Domain, all Isolated networks aclType==Account
if (ntwkOff.getGuestType() == GuestType.Isolated) {
if (aclType != ACLType.Account) {
throw new InvalidParameterValueException("AclType should be " + ACLType.Account + " for network of type " + Network.GuestType.Isolated);
}
} else if (ntwkOff.getGuestType() == GuestType.Shared) {
if (!(aclType == ACLType.Domain || aclType == ACLType.Account)) {
throw new InvalidParameterValueException("AclType should be " + ACLType.Domain + " or " + ACLType.Account + " for network of type " + Network.GuestType.Shared);
}
}
} else {
if (ntwkOff.getGuestType() == GuestType.Isolated) {
aclType = ACLType.Account;
} else if (ntwkOff.getGuestType() == GuestType.Shared) {
aclType = ACLType.Domain;
}
}
// Only Admin can create Shared networks
if (ntwkOff.getGuestType() == GuestType.Shared && !_accountMgr.isAdmin(caller.getType())) {
throw new InvalidParameterValueException("Only Admins can create network with guest type " + GuestType.Shared);
}
// Check if the network is domain specific
if (aclType == ACLType.Domain) {
// only Admin can create domain with aclType=Domain
if (!_accountMgr.isAdmin(caller.getType())) {
throw new PermissionDeniedException("Only admin can create networks with aclType=Domain");
}
// only shared networks can be Domain specific
if (ntwkOff.getGuestType() != GuestType.Shared) {
throw new InvalidParameterValueException("Only " + GuestType.Shared + " networks can have aclType=" + ACLType.Domain);
}
if (domainId != null) {
if (ntwkOff.getTrafficType() != TrafficType.Guest || ntwkOff.getGuestType() != Network.GuestType.Shared) {
throw new InvalidParameterValueException("Domain level networks are supported just for traffic type " + TrafficType.Guest + " and guest type " + Network.GuestType.Shared);
}
DomainVO domain = _domainDao.findById(domainId);
if (domain == null) {
throw new InvalidParameterValueException("Unable to find domain by specified id");
}
_accountMgr.checkAccess(caller, domain);
}
isDomainSpecific = true;
} else if (subdomainAccess != null) {
throw new InvalidParameterValueException("Parameter subDomainAccess can be specified only with aclType=Domain");
}
Account owner = null;
if ((cmd.getAccountName() != null && domainId != null) || cmd.getProjectId() != null) {
owner = _accountMgr.finalizeOwner(caller, cmd.getAccountName(), domainId, cmd.getProjectId());
} else {
owner = caller;
}
UserContext.current().setAccountId(owner.getAccountId());
// VALIDATE IP INFO
// if end ip is not specified, default it to startIp
if (startIP != null) {
if (!NetUtils.isValidIp(startIP)) {
throw new InvalidParameterValueException("Invalid format for the startIp parameter");
}
if (endIP == null) {
endIP = startIP;
} else if (!NetUtils.isValidIp(endIP)) {
throw new InvalidParameterValueException("Invalid format for the endIp parameter");
}
}
if (startIP != null && endIP != null) {
if (!(gateway != null && netmask != null)) {
throw new InvalidParameterValueException("gateway and netmask should be defined when startIP/endIP are passed in");
}
}
String cidr = null;
if (gateway != null && netmask != null) {
if (!NetUtils.isValidIp(gateway)) {
throw new InvalidParameterValueException("Invalid gateway");
}
if (!NetUtils.isValidNetmask(netmask)) {
throw new InvalidParameterValueException("Invalid netmask");
}
cidr = NetUtils.ipAndNetMaskToCidr(gateway, netmask);
}
// Regular user can create Guest Isolated Source Nat enabled network only
if (caller.getType() == Account.ACCOUNT_TYPE_NORMAL
&& (ntwkOff.getTrafficType() != TrafficType.Guest || ntwkOff.getGuestType() != Network.GuestType.Isolated
&& areServicesSupportedByNetworkOffering(ntwkOff.getId(), Service.SourceNat))) {
throw new InvalidParameterValueException("Regular user can create a network only from the network offering having traffic type " + TrafficType.Guest + " and network type "
+ Network.GuestType.Isolated + " with a service " + Service.SourceNat.getName() + " enabled");
}
// Don't allow to specify vlan if the caller is a regular user
if (caller.getType() == Account.ACCOUNT_TYPE_NORMAL && (ntwkOff.getSpecifyVlan() || vlanId != null)) {
throw new InvalidParameterValueException("Regular user is not allowed to specify vlanId");
}
// For non-root admins check cidr limit - if it's allowed by global config value
if (caller.getType() != Account.ACCOUNT_TYPE_ADMIN && cidr != null) {
String[] cidrPair = cidr.split("\\/");
int cidrSize = Integer.valueOf(cidrPair[1]);
if (cidrSize < _cidrLimit) {
throw new InvalidParameterValueException("Cidr size can't be less than " + _cidrLimit);
}
}
if (cidr != null && networkOfferingIsConfiguredForExternalNetworking(networkOfferingId)) {
throw new InvalidParameterValueException("Cannot specify CIDR when using network offering with external devices!");
}
if (cidr != null) {
checkVirtualNetworkCidrOverlap(zoneId, cidr);
}
// Vlan is created in 2 cases - works in Advance zone only:
// 1) GuestType is Shared
// 2) GuestType is Isolated, but SourceNat service is disabled
boolean createVlan = (startIP != null && endIP != null && zone.getNetworkType() == NetworkType.Advanced
&& ((ntwkOff.getGuestType() == Network.GuestType.Shared)
|| (ntwkOff.getGuestType() == GuestType.Isolated && !areServicesSupportedByNetworkOffering(ntwkOff.getId(), Service.SourceNat))));
// Can add vlan range only to the network which allows it
if (createVlan && !ntwkOff.getSpecifyIpRanges()) {
InvalidParameterValueException ex = new InvalidParameterValueException("Network offering with specified id doesn't support adding multiple ip ranges");
ex.addProxyObject(ntwkOff, ntwkOff.getId(), "networkOfferingId");
throw ex;
}
Transaction txn = Transaction.currentTxn();
txn.start();
Long sharedDomainId = null;
if (isDomainSpecific) {
if (domainId != null) {
sharedDomainId = domainId;
} else {
sharedDomainId = _domainMgr.getDomain(Domain.ROOT_DOMAIN).getId();
subdomainAccess = true;
}
}
// default owner to system if network has aclType=Domain
if (aclType == ACLType.Domain) {
owner = _accountMgr.getAccount(Account.ACCOUNT_ID_SYSTEM);
}
Network network = createGuestNetwork(networkOfferingId, name, displayText, gateway, cidr, vlanId, networkDomain, owner, false, sharedDomainId, pNtwk, zoneId, aclType, subdomainAccess);
if (caller.getType() == Account.ACCOUNT_TYPE_ADMIN && createVlan) {
// Create vlan ip range
_configMgr.createVlanAndPublicIpRange(userId, pNtwk.getDataCenterId(), null, startIP, endIP, gateway, netmask, false, vlanId, null, network.getId(), physicalNetworkId);
}
txn.commit();
return network;
}
@Override
@DB
public Network createGuestNetwork(long networkOfferingId, String name, String displayText, String gateway, String cidr, String vlanId, String networkDomain, Account owner, boolean isSecurityGroupEnabled,
Long domainId, PhysicalNetwork pNtwk, long zoneId, ACLType aclType, Boolean subdomainAccess) 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 = (!ntwkOff.getSpecifyVlan() && aclType == ACLType.Account);
//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;
}
// Validate zone
DataCenterVO zone = _dcDao.findById(zoneId);
if (zone.getNetworkType() == NetworkType.Basic) {
// 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 && !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()) {
// Only Account specific Isolated network with sourceNat service disabled are allowed in security group
// enabled zone
boolean allowCreation = (ntwkOff.getGuestType() == GuestType.Isolated && !areServicesSupportedByNetworkOffering(ntwkOff.getId(), Service.SourceNat));
if (!allowCreation) {
throw new InvalidParameterValueException("Only Account specific Isolated network with sourceNat service disabled are allowed in security group enabled zone");
}
}
}
// 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");
}
}
// Don't allow to create network with vlan that already exists in the system
if (vlanId != null) {
String uri = "vlan://" + vlanId;
List networks = _networksDao.listBy(zoneId, uri);
if ((networks != null && !networks.isEmpty())) {
// TBD: If zoneId and vlanId are being passed in as params, how to get the VO object or class? Hard code
// the tablename in a call to addProxyObject().
throw new InvalidParameterValueException("Network with vlan " + vlanId + " already exists in zone " + zoneId);
}
}
// If networkDomain is not specified, take it from the global configuration
if (areServicesSupportedByNetworkOffering(networkOfferingId, Service.Dns)) {
Map dnsCapabilities = 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 = getDomainNetworkDomain(domainId, zoneId);
} else if (aclType == ACLType.Account) {
networkDomain = 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()) + _networkDomain;
}
} 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 && !areServicesSupportedByNetworkOffering(ntwkOff.getId(), Service.SourceNat)));
if (cidr == 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
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 (vlanId != null) {
userNetwork.setBroadcastUri(URI.create("vlan://" + vlanId));
userNetwork.setBroadcastDomainType(BroadcastDomainType.Vlan);
if (!vlanId.equalsIgnoreCase(Vlan.UNTAGGED)) {
userNetwork.setBroadcastDomainType(BroadcastDomainType.Vlan);
} else {
userNetwork.setBroadcastDomainType(BroadcastDomainType.Native);
}
}
}
List networks = setupNetwork(owner, ntwkOff, userNetwork, plan, name, displayText, true, domainId, aclType, subdomainAccess);
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
public List extends Network> searchForNetworks(ListNetworksCmd cmd) {
Long id = cmd.getId();
String keyword = cmd.getKeyword();
Long zoneId = cmd.getZoneId();
Account caller = UserContext.current().getCaller();
Long domainId = cmd.getDomainId();
String accountName = cmd.getAccountName();
String guestIpType = cmd.getGuestIpType();
String trafficType = cmd.getTrafficType();
Boolean isSystem = cmd.getIsSystem();
String aclType = cmd.getAclType();
Long projectId = cmd.getProjectId();
List permittedAccounts = new ArrayList();
String path = null;
Long physicalNetworkId = cmd.getPhysicalNetworkId();
List supportedServicesStr = cmd.getSupportedServices();
Boolean restartRequired = cmd.getRestartRequired();
boolean listAll = cmd.listAll();
boolean isRecursive = cmd.isRecursive();
Boolean specifyIpRanges = cmd.getSpecifyIpRanges();
// 1) default is system to false if not specified
// 2) reset parameter to false if it's specified by the regular user
if ((isSystem == null || caller.getType() == Account.ACCOUNT_TYPE_NORMAL) && id == null) {
isSystem = false;
}
// Account/domainId parameters and isSystem are mutually exclusive
if (isSystem != null && isSystem && (accountName != null || domainId != null)) {
throw new InvalidParameterValueException("System network belongs to system, account and domainId parameters can't be specified");
}
if (domainId != null) {
DomainVO domain = _domainDao.findById(domainId);
if (domain == null) {
// see DomainVO.java
throw new InvalidParameterValueException("Specified domain id doesn't exist in the system");
}
_accountMgr.checkAccess(caller, domain);
if (accountName != null) {
Account owner = _accountMgr.getActiveAccountByName(accountName, domainId);
if (owner == null) {
// see DomainVO.java
throw new InvalidParameterValueException("Unable to find account " + accountName + " in specified domain");
}
_accountMgr.checkAccess(caller, null, true, owner);
permittedAccounts.add(owner.getId());
}
}
if (!_accountMgr.isAdmin(caller.getType()) || !listAll) {
permittedAccounts.add(caller.getId());
domainId = caller.getDomainId();
}
if (caller.getType() == Account.ACCOUNT_TYPE_DOMAIN_ADMIN) {
domainId = caller.getDomainId();
}
// set project information
boolean skipProjectNetworks = true;
if (projectId != null) {
if (projectId == -1) {
permittedAccounts.addAll(_projectMgr.listPermittedProjectAccounts(caller.getId()));
} else {
permittedAccounts.clear();
Project project = _projectMgr.getProject(projectId);
if (project == null) {
throw new InvalidParameterValueException("Unable to find project by specified id");
}
if (!_projectMgr.canAccessProjectAccount(caller, project.getProjectAccountId())) {
// getProject() returns type ProjectVO.
InvalidParameterValueException ex = new InvalidParameterValueException("Account " + caller + " cannot access specified project id");
ex.addProxyObject(project, projectId, "projectId");
throw ex;
}
permittedAccounts.add(project.getProjectAccountId());
}
skipProjectNetworks = false;
}
path = _domainDao.findById(caller.getDomainId()).getPath();
if (listAll) {
isRecursive = true;
}
Filter searchFilter = new Filter(NetworkVO.class, "id", false, cmd.getStartIndex(), cmd.getPageSizeVal());
SearchBuilder sb = _networksDao.createSearchBuilder();
// Don't display networks created of system network offerings
SearchBuilder networkOfferingSearch = _networkOfferingDao.createSearchBuilder();
networkOfferingSearch.and("systemOnly", networkOfferingSearch.entity().isSystemOnly(), SearchCriteria.Op.EQ);
if (isSystem != null && isSystem) {
networkOfferingSearch.and("trafficType", networkOfferingSearch.entity().getTrafficType(), SearchCriteria.Op.EQ);
}
sb.join("networkOfferingSearch", networkOfferingSearch, sb.entity().getNetworkOfferingId(), networkOfferingSearch.entity().getId(), JoinBuilder.JoinType.INNER);
SearchBuilder zoneSearch = _dcDao.createSearchBuilder();
zoneSearch.and("networkType", zoneSearch.entity().getNetworkType(), SearchCriteria.Op.EQ);
sb.join("zoneSearch", zoneSearch, sb.entity().getDataCenterId(), zoneSearch.entity().getId(), JoinBuilder.JoinType.INNER);
sb.and("removed", sb.entity().getRemoved(), Op.NULL);
if (permittedAccounts.isEmpty()) {
SearchBuilder domainSearch = _domainDao.createSearchBuilder();
domainSearch.and("path", domainSearch.entity().getPath(), SearchCriteria.Op.LIKE);
sb.join("domainSearch", domainSearch, sb.entity().getDomainId(), domainSearch.entity().getId(), JoinBuilder.JoinType.INNER);
}
if (skipProjectNetworks) {
SearchBuilder accountSearch = _accountDao.createSearchBuilder();
accountSearch.and("type", accountSearch.entity().getType(), SearchCriteria.Op.NEQ);
sb.join("accountSearch", accountSearch, sb.entity().getAccountId(), accountSearch.entity().getId(), JoinBuilder.JoinType.INNER);
}
List networksToReturn = new ArrayList();
if (isSystem == null || !isSystem) {
// Get domain level networks
if (domainId != null) {
networksToReturn
.addAll(listDomainLevelNetworks(
buildNetworkSearchCriteria(sb, keyword, id, isSystem, zoneId, guestIpType, trafficType, physicalNetworkId, aclType, skipProjectNetworks, restartRequired, specifyIpRanges), searchFilter,
domainId));
}
if (!permittedAccounts.isEmpty()) {
networksToReturn.addAll(listAccountSpecificNetworks(
buildNetworkSearchCriteria(sb, keyword, id, isSystem, zoneId, guestIpType, trafficType, physicalNetworkId, aclType, skipProjectNetworks, restartRequired, specifyIpRanges), searchFilter,
permittedAccounts));
} else if (domainId == null || listAll) {
networksToReturn.addAll(listAccountSpecificNetworksByDomainPath(
buildNetworkSearchCriteria(sb, keyword, id, isSystem, zoneId, guestIpType, trafficType, physicalNetworkId, aclType, skipProjectNetworks, restartRequired, specifyIpRanges), searchFilter, path,
isRecursive));
}
} else {
networksToReturn = _networksDao.search(buildNetworkSearchCriteria(sb, keyword, id, isSystem, zoneId, guestIpType, trafficType, physicalNetworkId, null, skipProjectNetworks, restartRequired, specifyIpRanges),
searchFilter);
}
if (supportedServicesStr != null && !supportedServicesStr.isEmpty() && !networksToReturn.isEmpty()) {
List supportedNetworks = new ArrayList();
Service[] suppportedServices = new Service[supportedServicesStr.size()];
int i = 0;
for (String supportedServiceStr : supportedServicesStr) {
Service service = Service.getService(supportedServiceStr);
if (service == null) {
throw new InvalidParameterValueException("Invalid service specified " + supportedServiceStr);
} else {
suppportedServices[i] = service;
}
i++;
}
for (NetworkVO network : networksToReturn) {
if (areServicesSupportedInNetwork(network.getId(), suppportedServices)) {
supportedNetworks.add(network);
}
}
return supportedNetworks;
} else {
return networksToReturn;
}
}
private SearchCriteria buildNetworkSearchCriteria(SearchBuilder sb, String keyword, Long id, Boolean isSystem, Long zoneId, String guestIpType, String trafficType, Long physicalNetworkId,
String aclType, boolean skipProjectNetworks, Boolean restartRequired, Boolean specifyIpRanges) {
SearchCriteria sc = sb.create();
if (isSystem != null) {
sc.setJoinParameters("networkOfferingSearch", "systemOnly", isSystem);
}
if (keyword != null) {
SearchCriteria ssc = _networksDao.createSearchCriteria();
ssc.addOr("name", SearchCriteria.Op.LIKE, "%" + keyword + "%");
sc.addAnd("name", SearchCriteria.Op.SC, ssc);
}
if (id != null) {
sc.addAnd("id", SearchCriteria.Op.EQ, id);
}
if (zoneId != null) {
sc.addAnd("dataCenterId", SearchCriteria.Op.EQ, zoneId);
}
if (guestIpType != null) {
sc.addAnd("guestType", SearchCriteria.Op.EQ, guestIpType);
}
if (trafficType != null) {
sc.addAnd("trafficType", SearchCriteria.Op.EQ, trafficType);
}
if (aclType != null) {
sc.addAnd("aclType", SearchCriteria.Op.EQ, aclType.toString());
}
if (physicalNetworkId != null) {
sc.addAnd("physicalNetworkId", SearchCriteria.Op.EQ, physicalNetworkId);
}
if (skipProjectNetworks) {
sc.setJoinParameters("accountSearch", "type", Account.ACCOUNT_TYPE_PROJECT);
}
if (restartRequired != null) {
sc.addAnd("restartRequired", SearchCriteria.Op.EQ, restartRequired);
}
if (specifyIpRanges != null) {
sc.addAnd("specifyIpRanges", SearchCriteria.Op.EQ, specifyIpRanges);
}
return sc;
}
private List listDomainLevelNetworks(SearchCriteria sc, Filter searchFilter, long domainId) {
List networkIds = new ArrayList();
Set allowedDomains = _domainMgr.getDomainParentIds(domainId);
List maps = _networkDomainDao.listDomainNetworkMapByDomain(allowedDomains.toArray());
for (NetworkDomainVO map : maps) {
boolean subdomainAccess = (map.isSubdomainAccess() != null) ? map.isSubdomainAccess() : getAllowSubdomainAccessGlobal();
if (map.getDomainId() == domainId || subdomainAccess) {
networkIds.add(map.getNetworkId());
}
}
if (!networkIds.isEmpty()) {
SearchCriteria domainSC = _networksDao.createSearchCriteria();
domainSC.addAnd("id", SearchCriteria.Op.IN, networkIds.toArray());
domainSC.addAnd("aclType", SearchCriteria.Op.EQ, ACLType.Domain.toString());
sc.addAnd("id", SearchCriteria.Op.SC, domainSC);
return _networksDao.search(sc, searchFilter);
} else {
return new ArrayList();
}
}
private List listAccountSpecificNetworks(SearchCriteria sc, Filter searchFilter, List permittedAccounts) {
SearchCriteria accountSC = _networksDao.createSearchCriteria();
if (!permittedAccounts.isEmpty()) {
accountSC.addAnd("accountId", SearchCriteria.Op.IN, permittedAccounts.toArray());
}
accountSC.addAnd("aclType", SearchCriteria.Op.EQ, ACLType.Account.toString());
sc.addAnd("id", SearchCriteria.Op.SC, accountSC);
return _networksDao.search(sc, searchFilter);
}
private List listAccountSpecificNetworksByDomainPath(SearchCriteria sc, Filter searchFilter, String path, boolean isRecursive) {
SearchCriteria accountSC = _networksDao.createSearchCriteria();
accountSC.addAnd("aclType", SearchCriteria.Op.EQ, ACLType.Account.toString());
if (path != null) {
if (isRecursive) {
sc.setJoinParameters("domainSearch", "path", path + "%");
} else {
sc.setJoinParameters("domainSearch", "path", path);
}
}
return _networksDao.search(sc, searchFilter);
}
@Override
@ActionEvent(eventType = EventTypes.EVENT_NETWORK_DELETE, eventDescription = "deleting network", async = true)
public boolean deleteNetwork(long networkId) {
Account caller = UserContext.current().getCaller();
// Verify network id
NetworkVO network = _networksDao.findById(networkId);
if (network == null) {
// see NetworkVO.java
InvalidParameterValueException ex = new InvalidParameterValueException("unable to find network with specified id");
ex.addProxyObject(network, networkId, "networkId");
throw ex;
}
// don't allow to delete system network
if (isNetworkSystem(network)) {
InvalidParameterValueException ex = new InvalidParameterValueException("Network with specified id is system and can't be removed");
ex.addProxyObject(network, network.getId(), "networkId");
throw ex;
}
Account owner = _accountMgr.getAccount(network.getAccountId());
// Perform permission check
_accountMgr.checkAccess(caller, null, true, network);
User callerUser = _accountMgr.getActiveUser(UserContext.current().getCallerUserId());
ReservationContext context = new ReservationContextImpl(null, null, callerUser, owner);
return destroyNetwork(networkId, context);
}
@Override
@DB
public boolean shutdownNetwork(long networkId, ReservationContext context, boolean cleanupElements) {
boolean result = false;
Transaction txn = Transaction.currentTxn();
txn.start();
NetworkVO network = _networksDao.lockRow(networkId, true);
if (network == null) {
s_logger.debug("Unable to find network with id: " + networkId);
return false;
}
if (network.getState() != Network.State.Implemented && network.getState() != Network.State.Shutdown) {
s_logger.debug("Network is not implemented: " + network);
return false;
}
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 = _networkGurus.get(network.getGuruName());
NetworkProfile profile = convertNetworkToNetworkProfile(network.getId());
guru.shutdown(profile, _networkOfferingDao.findById(network.getNetworkOfferingId()));
applyProfileToNetwork(network, profile);
network.setState(Network.State.Allocated);
network.setRestartRequired(false);
_networksDao.update(network.getId(), network);
_networksDao.clearCheckForGc(networkId);
result = true;
} else {
network.setState(Network.State.Implemented);
_networksDao.update(network.getId(), network);
result = false;
}
txn.commit();
return result;
}
private 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 (!isProviderEnabledInPhysicalNetwork(getPhysicalNetworkId(network), "VirtualRouter")) {
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 "
+ 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;
}
}
// 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 (!isProviderEnabledInPhysicalNetwork(getPhysicalNetworkId(network), "VirtualRouter")) {
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 "
+ getPhysicalNetworkId(network));
success = false;
}
if (s_logger.isDebugEnabled()) {
s_logger.debug("Sending destroy to " + element);
}
element.destroy(network);
} catch (ResourceUnavailableException e) {
s_logger.warn("Unable to complete destroy of the network due to element: " + element.getName(), e);
success = false;
} catch (ConcurrentOperationException e) {
s_logger.warn("Unable to complete destroy of the network due to element: " + element.getName(), e);
success = false;
} catch (Exception e) {
s_logger.warn("Unable to complete destroy of the network due to element: " + element.getName(), e);
success = false;
}
}
}
if (success) {
if (s_logger.isDebugEnabled()) {
s_logger.debug("Network id=" + networkId + " is destroyed successfully, cleaning up corresponding resources now.");
}
NetworkGuru guru = _networkGurus.get(network.getGuruName());
Account owner = _accountMgr.getAccount(network.getAccountId());
Transaction txn = Transaction.currentTxn();
txn.start();
guru.trash(network, _networkOfferingDao.findById(network.getNetworkOfferingId()), owner);
if (!deleteVlansInNetwork(network.getId(), context.getCaller().getId())) {
success = false;
s_logger.warn("Failed to delete network " + network + "; was unable to cleanup corresponding ip ranges");
} else {
// commit transaction only when ips and vlans for the network are released successfully
network.setState(Network.State.Destroy);
_networksDao.update(network.getId(), network);
_networksDao.remove(network.getId());
txn.commit();
}
}
return success;
}
private boolean deleteVlansInNetwork(long networkId, long userId) {
List vlans = _vlanDao.listVlansByNetworkId(networkId);
boolean result = true;
for (VlanVO vlan : vlans) {
if (!_configMgr.deleteVlanAndPublicIpRange(_accountMgr.getSystemUser().getId(), vlan.getId())) {
s_logger.warn("Failed to delete vlan " + vlan.getId() + ");");
result = false;
}
}
return result;
}
@Override
public boolean validateRule(FirewallRule rule) {
Network network = _networksDao.findById(rule.getNetworkId());
Purpose purpose = rule.getPurpose();
for (NetworkElement ne : _networkElements) {
boolean validated;
switch (purpose) {
case LoadBalancing:
if (!(ne instanceof LoadBalancingServiceProvider)) {
continue;
}
validated = ((LoadBalancingServiceProvider) ne).validateLBRule(network, (LoadBalancingRule) rule);
if (!validated)
return false;
break;
default:
s_logger.debug("Unable to validate network rules for purpose: " + purpose.toString());
validated = false;
}
}
return true;
}
@Override
/* The rules here is only the same kind of rule, e.g. all load balancing rules or all port forwarding rules */
public boolean applyRules(List extends FirewallRule> rules, boolean continueOnError) throws ResourceUnavailableException {
if (rules == null || rules.size() == 0) {
s_logger.debug("There are no rules to forward to the network elements");
return true;
}
boolean success = true;
Network network = _networksDao.findById(rules.get(0).getNetworkId());
Purpose purpose = rules.get(0).getPurpose();
// 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 = new PublicIp(userIp, _vlanDao.findById(userIp.getVlanId()), NetUtils.createSequenceBasedMacAddress(userIp.getMacAddress()));
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);
for (NetworkElement ne : _networkElements) {
Provider provider = Network.Provider.getProvider(ne.getName());
if (provider == null) {
if (ne.getName().equalsIgnoreCase("Ovs") || ne.getName().equalsIgnoreCase("BareMetal")) {
continue;
}
throw new CloudRuntimeException("Unable to identify the provider by name " + ne.getName());
}
try {
boolean handled;
switch (purpose) {
case LoadBalancing:
boolean isLbProvider = isProviderSupportServiceInNetwork(network.getId(), Service.Lb, provider);
if (!(ne instanceof LoadBalancingServiceProvider && isLbProvider)) {
continue;
}
handled = ((LoadBalancingServiceProvider) ne).applyLBRules(network, (List) rules);
break;
case PortForwarding:
boolean isPfProvider = isProviderSupportServiceInNetwork(network.getId(), Service.PortForwarding, provider);
if (!(ne instanceof PortForwardingServiceProvider && isPfProvider)) {
continue;
}
handled = ((PortForwardingServiceProvider) ne).applyPFRules(network, (List) rules);
break;
case StaticNat:
/* It's firewall rule for static nat, not static nat rule */
/* Fall through */
case Firewall:
boolean isFirewallProvider = isProviderSupportServiceInNetwork(network.getId(), Service.Firewall, provider);
if (!(ne instanceof FirewallServiceProvider && isFirewallProvider)) {
continue;
}
handled = ((FirewallServiceProvider) ne).applyFWRules(network, rules);
break;
default:
s_logger.debug("Unable to handle network rules for purpose: " + purpose.toString());
handled = false;
}
s_logger.debug("Network Rules for network " + network.getId() + " were " + (handled ? "" : " not") + " handled by " + ne.getName());
} catch (ResourceUnavailableException e) {
if (!continueOnError) {
throw e;
}
s_logger.warn("Problems with " + ne.getName() + " but pushing on", e);
success = false;
}
}
// 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 (getNetwork(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(getNetwork(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
@ActionEvent(eventType = EventTypes.EVENT_NETWORK_RESTART, eventDescription = "restarting network", async = true)
public boolean restartNetwork(RestartNetworkCmd cmd, boolean cleanup) throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException {
// This method restarts all network elements belonging to the network and re-applies all the rules
Long networkId = cmd.getNetworkId();
User callerUser = _accountMgr.getActiveUser(UserContext.current().getCallerUserId());
Account callerAccount = _accountMgr.getActiveAccountById(callerUser.getAccountId());
// 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("networks", networkId, "networkId");
throw ex;
}
// Don't allow to restart network if it's not in Implemented/Setup state
if (!(network.getState() == Network.State.Implemented || network.getState() == Network.State.Setup)) {
throw new InvalidParameterValueException("Network is not in the right state to be restarted. Correct states are: " + Network.State.Implemented + ", " + Network.State.Setup);
}
// don't allow clenaup=true for the network in Basic zone
DataCenter zone = _configMgr.getZone(network.getDataCenterId());
if (zone.getNetworkType() == NetworkType.Basic && cleanup) {
throw new InvalidParameterValueException("Cleanup can't be true when restart network in Basic zone");
}
_accountMgr.checkAccess(callerAccount, null, true, network);
boolean success = restartNetwork(networkId, callerAccount, callerUser, cleanup);
if (success) {
s_logger.debug("Network id=" + networkId + " is restarted successfully.");
} else {
s_logger.warn("Network id=" + networkId + " failed to restart.");
}
return success;
}
@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;
}
}
private 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) {
if (network.getGuestType() != GuestType.Isolated) {
s_logger.warn("Only support clean up network for isolated network!");
return false;
}
// 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 firewallRulesToApply = _firewallDao.listByNetworkAndPurpose(networkId, Purpose.Firewall);
if (!_firewallMgr.applyFirewallRules(firewallRulesToApply, false, caller)) {
s_logger.warn("Failed to reapply firewall 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 load balancer rules
if (!_lbMgr.applyLoadBalancersForNetwork(networkId)) {
s_logger.warn("Failed to reapply load balancer rules as a part of network id=" + networkId + " restart");
success = false;
}
// apply vpn rules
List extends RemoteAccessVpn> 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;
}
}
}
return success;
}
@Override
public int getActiveNicsInNetwork(long networkId) {
return _networksDao.getActiveNicsIn(networkId);
}
@Override
public Map> getNetworkCapabilities(long networkId) {
Map> networkCapabilities = new HashMap>();
// list all services of this networkOffering
List servicesMap = _ntwkSrvcDao.getServicesInNetwork(networkId);
for (NetworkServiceMapVO instance : servicesMap) {
Service service = Service.getService(instance.getService());
NetworkElement element = getElementImplementingProvider(instance.getProvider());
if (element != null) {
Map> elementCapabilities = element.getCapabilities();
;
if (elementCapabilities != null) {
networkCapabilities.put(service, elementCapabilities.get(service));
}
}
}
return networkCapabilities;
}
@Override
public Map getNetworkServiceCapabilities(long networkId, Service service) {
if (!areServicesSupportedInNetwork(networkId, service)) {
// TBD: networkId to uuid. No VO object being passed. So we will need to call
// addProxyObject with hardcoded tablename. Or we should probably look up the correct dao proxy object.
throw new UnsupportedServiceException("Service " + service.getName() + " is not supported in the network id=" + networkId);
}
Map serviceCapabilities = new HashMap();
// get the Provider for this Service for this offering
String provider = _ntwkSrvcDao.getProviderForServiceInNetwork(networkId, service);
NetworkElement element = getElementImplementingProvider(provider);
if (element != null) {
Map> elementCapabilities = element.getCapabilities();
;
if (elementCapabilities == null || !elementCapabilities.containsKey(service)) {
throw new UnsupportedServiceException("Service " + service.getName() + " is not supported by the element=" + element.getName() + " implementing Provider=" + provider);
}
serviceCapabilities = elementCapabilities.get(service);
}
return serviceCapabilities;
}
@Override
public Map getNetworkOfferingServiceCapabilities(NetworkOffering offering, Service service) {
if (!areServicesSupportedByNetworkOffering(offering.getId(), service)) {
// TBD: We should be sending networkOfferingId and not the offering object itself.
throw new UnsupportedServiceException("Service " + service.getName() + " is not supported by the network offering " + offering);
}
Map serviceCapabilities = new HashMap();
// get the Provider for this Service for this offering
List providers = _ntwkOfferingSrvcDao.listProvidersForServiceForNetworkOffering(offering.getId(), service);
if (providers.isEmpty()) {
// TBD: We should be sending networkOfferingId and not the offering object itself.
throw new InvalidParameterValueException("Service " + service.getName() + " is not supported by the network offering " + offering);
}
// FIXME - in post 3.0 we are going to support multiple providers for the same service per network offering, so
// we have to calculate capabilities for all of them
String provider = providers.get(0);
// FIXME we return the capabilities of the first provider of the service - what if we have multiple providers
// for same Service?
NetworkElement element = getElementImplementingProvider(provider);
if (element != null) {
Map> elementCapabilities = element.getCapabilities();
;
if (elementCapabilities == null || !elementCapabilities.containsKey(service)) {
// TBD: We should be sending providerId and not the offering object itself.
throw new UnsupportedServiceException("Service " + service.getName() + " is not supported by the element=" + element.getName() + " implementing Provider=" + provider);
}
serviceCapabilities = elementCapabilities.get(service);
}
return serviceCapabilities;
}
@Override
public NetworkVO getSystemNetworkByZoneAndTrafficType(long zoneId, TrafficType trafficType) {
// find system public network offering
Long networkOfferingId = null;
List offerings = _networkOfferingDao.listSystemNetworkOfferings();
for (NetworkOfferingVO offering : offerings) {
if (offering.getTrafficType() == trafficType) {
networkOfferingId = offering.getId();
break;
}
}
if (networkOfferingId == null) {
throw new InvalidParameterValueException("Unable to find system network offering with traffic type " + trafficType);
}
List networks = _networksDao.listBy(Account.ACCOUNT_ID_SYSTEM, networkOfferingId, zoneId);
if (networks == null || networks.isEmpty()) {
// TBD: send uuid instead of zoneId. Hardcode tablename in call to addProxyObject().
throw new InvalidParameterValueException("Unable to find network with traffic type " + trafficType + " in zone " + zoneId);
}
return networks.get(0);
}
@Override
public NetworkVO getNetworkWithSecurityGroupEnabled(Long zoneId) {
List networks = _networksDao.listByZoneSecurityGroup(zoneId);
if (networks == null || networks.isEmpty()) {
return null;
}
if (networks.size() > 1) {
s_logger.debug("There are multiple network with security group enabled? select one of them...");
}
return networks.get(0);
}
@Override
public PublicIpAddress getPublicIpAddress(long ipAddressId) {
IPAddressVO addr = _ipAddressDao.findById(ipAddressId);
if (addr == null) {
return null;
}
return new PublicIp(addr, _vlanDao.findById(addr.getVlanId()), NetUtils.createSequenceBasedMacAddress(addr.getMacAddress()));
}
@Override
public List listPodVlans(long podId) {
List vlans = _vlanDao.listVlansForPodByType(podId, VlanType.DirectAttached);
return vlans;
}
@Override
public List listNetworksUsedByVm(long vmId, boolean isSystem) {
List networks = new ArrayList();
List nics = _nicDao.listByVmId(vmId);
if (nics != null) {
for (Nic nic : nics) {
NetworkVO network = _networksDao.findByIdIncludingRemoved(nic.getNetworkId());
if (isNetworkSystem(network) == isSystem) {
networks.add(network);
}
}
}
return networks;
}
@Override
public Nic getNicInNetwork(long vmId, long networkId) {
return _nicDao.findByInstanceIdAndNetworkId(networkId, vmId);
}
@Override
public String getIpInNetwork(long vmId, long networkId) {
Nic guestNic = getNicInNetwork(vmId, networkId);
assert (guestNic != null && guestNic.getIp4Address() != null) : "Vm doesn't belong to network associated with ipAddress or ip4 address is null";
return guestNic.getIp4Address();
}
@Override
public String getIpInNetworkIncludingRemoved(long vmId, long networkId) {
Nic guestNic = getNicInNetworkIncludingRemoved(vmId, networkId);
assert (guestNic != null && guestNic.getIp4Address() != null) : "Vm doesn't belong to network associated with ipAddress or ip4 address is null";
return guestNic.getIp4Address();
}
private Nic getNicInNetworkIncludingRemoved(long vmId, long networkId) {
return _nicDao.findByInstanceIdAndNetworkIdIncludingRemoved(networkId, vmId);
}
@Override
@DB
public boolean associateIpAddressListToAccount(long userId, long accountId, long zoneId, Long vlanId, Network network) throws InsufficientCapacityException, ConcurrentOperationException,
ResourceUnavailableException, ResourceAllocationException {
Account owner = _accountMgr.getActiveAccountById(accountId);
boolean createNetwork = false;
Transaction txn = Transaction.currentTxn();
txn.start();
if (network == null) {
List extends Network> networks = getIsolatedNetworksWithSourceNATOwnedByAccountInZone(zoneId, owner);
if (networks.size() == 0) {
createNetwork = true;
} else if (networks.size() == 1) {
network = 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
if (createNetwork) {
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");
}
PhysicalNetwork physicalNetwork = translateZoneIdToPhysicalNetwork(zoneId);
if (requiredOfferings.get(0).getState() == NetworkOffering.State.Enabled) {
s_logger.debug("Creating network for account " + owner + " from the network offering id=" + requiredOfferings.get(0).getId() + " as a part of createVlanIpRange process");
network = createGuestNetwork(requiredOfferings.get(0).getId(), owner.getAccountName() + "-network", owner.getAccountName() + "-network", null, null, null, null, owner, false, null, physicalNetwork, zoneId,
ACLType.Account, null);
if (network == 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(network.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(network.getId());
addr.setAllocatedTime(new Date());
addr.setAllocatedInDomainId(owner.getDomainId());
addr.setAllocatedToAccountId(owner.getId());
addr.setSystem(false);
addr.setState(IpAddress.State.Allocating);
markPublicIpAsAllocated(addr);
}
}
txn.commit();
return true;
}
@Override
public List getNicsForTraffic(long vmId, TrafficType type) {
SearchCriteria sc = NicForTrafficTypeSearch.create();
sc.setParameters("instance", vmId);
sc.setJoinParameters("network", "traffictype", type);
return _nicDao.search(sc, null);
}
@Override
public IpAddress getIp(long ipAddressId) {
return _ipAddressDao.findById(ipAddressId);
}
@Override
public NetworkProfile convertNetworkToNetworkProfile(long networkId) {
NetworkVO network = _networksDao.findById(networkId);
NetworkGuru guru = _networkGurus.get(network.getGuruName());
NetworkProfile profile = new NetworkProfile(network);
guru.updateNetworkProfile(profile);
return profile;
}
@Override
public Network getDefaultNetworkForVm(long vmId) {
Nic defaultNic = getDefaultNic(vmId);
if (defaultNic == null) {
return null;
} else {
return _networksDao.findById(defaultNic.getNetworkId());
}
}
@Override
public Nic getDefaultNic(long vmId) {
List nics = _nicDao.listByVmId(vmId);
Nic defaultNic = null;
if (nics != null) {
for (Nic nic : nics) {
if (nic.isDefaultNic()) {
defaultNic = nic;
break;
}
}
} else {
s_logger.debug("Unable to find default network for the vm; vm doesn't have any nics");
return null;
}
if (defaultNic == null) {
s_logger.debug("Unable to find default network for the vm; vm doesn't have default nic");
}
return defaultNic;
}
@Override
public List extends UserDataServiceProvider> getPasswordResetElements() {
List elements = new ArrayList();
for (NetworkElement element : _networkElements) {
if (element instanceof UserDataServiceProvider) {
UserDataServiceProvider e = (UserDataServiceProvider) element;
elements.add(e);
}
}
return elements;
}
@Override
public boolean networkIsConfiguredForExternalNetworking(long zoneId, long networkId) {
boolean netscalerInNetwork = isProviderForNetwork(Network.Provider.Netscaler, networkId);
boolean juniperInNetwork = isProviderForNetwork(Network.Provider.JuniperSRX, networkId);
boolean f5InNetwork = isProviderForNetwork(Network.Provider.F5BigIp, networkId);
if (netscalerInNetwork || juniperInNetwork || f5InNetwork) {
return true;
} else {
return false;
}
}
public boolean networkOfferingIsConfiguredForExternalNetworking(long networkOfferingId) {
boolean netscalerInNetworkOffering = isProviderForNetworkOffering(Network.Provider.Netscaler, networkOfferingId);
boolean juniperInNetworkOffering = isProviderForNetworkOffering(Network.Provider.JuniperSRX, networkOfferingId);
boolean f5InNetworkOffering = isProviderForNetworkOffering(Network.Provider.F5BigIp, networkOfferingId);
if (netscalerInNetworkOffering || juniperInNetworkOffering || f5InNetworkOffering) {
return true;
} else {
return false;
}
}
@Override
public boolean areServicesSupportedByNetworkOffering(long networkOfferingId, Service... services) {
return (_ntwkOfferingSrvcDao.areServicesSupportedByNetworkOffering(networkOfferingId, services));
}
@Override
public boolean areServicesSupportedInNetwork(long networkId, Service... services) {
return (_ntwkSrvcDao.areServicesSupportedInNetwork(networkId, services));
}
private 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.destroyRemoteAccessVpn(ipId);
} 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;
}
@Override
public String getIpOfNetworkElementInVirtualNetwork(long accountId, long dataCenterId) {
List