cloudstack/server/src/com/cloud/network/vpc/VpcManagerImpl.java
Alena Prokharchyk 5a64d4fbb1 VPC: CS-15638: Plug nic for the public ip address if the ip address from the diff vlan range than sourceNat ip
Conflicts:

	server/src/com/cloud/network/NetworkManagerImpl.java
	server/src/com/cloud/network/firewall/FirewallManagerImpl.java
	server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java
	server/src/com/cloud/network/router/VpcVirtualNetworkApplianceManagerImpl.java
	server/src/com/cloud/network/rules/RulesManagerImpl.java
	server/src/com/cloud/network/vpc/VpcManagerImpl.java
	server/test/com/cloud/network/MockNetworkManagerImpl.java
2012-07-20 17:12:34 -07:00

1596 lines
66 KiB
Java

// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package com.cloud.network.vpc;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
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.api.commands.ListPrivateGatewaysCmd;
import com.cloud.api.commands.ListStaticRoutesCmd;
import com.cloud.configuration.Config;
import com.cloud.configuration.ConfigurationManager;
import com.cloud.configuration.dao.ConfigurationDao;
import com.cloud.dc.DataCenter;
import com.cloud.deploy.DeployDestination;
import com.cloud.event.ActionEvent;
import com.cloud.event.EventTypes;
import com.cloud.exception.ConcurrentOperationException;
import com.cloud.exception.InsufficientCapacityException;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.exception.NetworkRuleConflictException;
import com.cloud.exception.PermissionDeniedException;
import com.cloud.exception.ResourceAllocationException;
import com.cloud.exception.ResourceUnavailableException;
import com.cloud.exception.UnsupportedServiceException;
import com.cloud.network.IPAddressVO;
import com.cloud.network.Network;
import com.cloud.network.Network.GuestType;
import com.cloud.network.Network.Provider;
import com.cloud.network.Network.Service;
import com.cloud.network.NetworkManager;
import com.cloud.network.NetworkVO;
import com.cloud.network.Networks.BroadcastDomainType;
import com.cloud.network.Networks.TrafficType;
import com.cloud.network.PhysicalNetwork;
import com.cloud.network.dao.FirewallRulesDao;
import com.cloud.network.dao.IPAddressDao;
import com.cloud.network.dao.NetworkDao;
import com.cloud.network.dao.PhysicalNetworkDao;
import com.cloud.network.element.VpcProvider;
import com.cloud.network.vpc.VpcOffering.State;
import com.cloud.network.vpc.Dao.PrivateIpDao;
import com.cloud.network.vpc.Dao.StaticRouteDao;
import com.cloud.network.vpc.Dao.VpcDao;
import com.cloud.network.vpc.Dao.VpcGatewayDao;
import com.cloud.network.vpc.Dao.VpcOfferingDao;
import com.cloud.network.vpc.Dao.VpcOfferingServiceMapDao;
import com.cloud.offering.NetworkOffering;
import com.cloud.offerings.NetworkOfferingServiceMapVO;
import com.cloud.offerings.dao.NetworkOfferingServiceMapDao;
import com.cloud.org.Grouping;
import com.cloud.projects.Project.ListProjectResourcesCriteria;
import com.cloud.tags.dao.ResourceTagDao;
import com.cloud.user.Account;
import com.cloud.user.AccountManager;
import com.cloud.user.User;
import com.cloud.user.UserContext;
import com.cloud.utils.NumbersUtil;
import com.cloud.utils.Ternary;
import com.cloud.utils.component.ComponentLocator;
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.GlobalLock;
import com.cloud.utils.db.JoinBuilder;
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.NetUtils;
import com.cloud.vm.DomainRouterVO;
import com.cloud.vm.ReservationContext;
import com.cloud.vm.ReservationContextImpl;
import com.cloud.vm.dao.DomainRouterDao;
@Local(value = { VpcManager.class, VpcService.class })
public class VpcManagerImpl implements VpcManager, Manager{
private static final Logger s_logger = Logger.getLogger(VpcManagerImpl.class);
@Inject
VpcOfferingDao _vpcOffDao;
@Inject
VpcOfferingServiceMapDao _vpcOffSvcMapDao;
@Inject
VpcDao _vpcDao;
@Inject
ConfigurationDao _configDao;
@Inject
ConfigurationManager _configMgr;
@Inject
AccountManager _accountMgr;
@Inject
NetworkDao _ntwkDao;
@Inject
NetworkManager _ntwkMgr;
@Inject
IPAddressDao _ipAddressDao;
@Inject
DomainRouterDao _routerDao;
@Inject
VpcGatewayDao _vpcGatewayDao;
@Inject
PrivateIpDao _privateIpDao;
@Inject
StaticRouteDao _staticRouteDao;
@Inject
NetworkOfferingServiceMapDao _ntwkOffServiceDao ;
@Inject
VpcOfferingServiceMapDao _vpcOffServiceDao;
@Inject
PhysicalNetworkDao _pNtwkDao;
@Inject
ResourceTagDao _resourceTagDao;
@Inject
FirewallRulesDao _firewallDao;
private final ScheduledExecutorService _executor = Executors.newScheduledThreadPool(1, new NamedThreadFactory("VpcChecker"));
private VpcProvider vpcElement = null;
String _name;
int _cleanupInterval;
@Override
@DB
public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
_name = name;
//configure default vpc offering
Transaction txn = Transaction.currentTxn();
txn.start();
if (_vpcOffDao.findByUniqueName(VpcOffering.defaultVPCOfferingName) == null) {
s_logger.debug("Creating default VPC offering " + VpcOffering.defaultVPCOfferingName);
Map<Service, Set<Provider>> svcProviderMap = new HashMap<Service, Set<Provider>>();
Set<Provider> defaultProviders = new HashSet<Provider>();
defaultProviders.add(Provider.VPCVirtualRouter);
for (Service svc : getSupportedServices()) {
if (svc == Service.Lb) {
Set<Provider> lbProviders = new HashSet<Provider>();
lbProviders.add(Provider.VPCVirtualRouter);
lbProviders.add(Provider.Netscaler);
svcProviderMap.put(svc, lbProviders);
} else {
svcProviderMap.put(svc, defaultProviders);
}
}
createVpcOffering(VpcOffering.defaultVPCOfferingName, VpcOffering.defaultVPCOfferingName, svcProviderMap,
true, State.Enabled);
}
txn.commit();
ComponentLocator locator = ComponentLocator.getCurrentLocator();
ConfigurationDao configDao = locator.getDao(ConfigurationDao.class);
Map<String, String> configs = configDao.getConfiguration(params);
String value = configs.get(Config.VpcCleanupInterval.key());
_cleanupInterval = NumbersUtil.parseInt(value, 60 * 60); // 1 hour
return true;
}
@Override
public boolean start() {
_executor.scheduleAtFixedRate(new VpcCleanupTask(), _cleanupInterval, _cleanupInterval, TimeUnit.SECONDS);
return true;
}
@Override
public boolean stop() {
return true;
}
@Override
public String getName() {
return _name;
}
@Override
public List<? extends Network> getVpcNetworks(long vpcId) {
return _ntwkDao.listByVpc(vpcId);
}
@Override
public VpcOffering getVpcOffering(long vpcOffId) {
return _vpcOffDao.findById(vpcOffId);
}
@Override
@ActionEvent(eventType = EventTypes.EVENT_VPC_OFFERING_CREATE, eventDescription = "creating vpc offering", create=true)
public VpcOffering createVpcOffering(String name, String displayText, List<String> supportedServices) {
Map<Network.Service, Set<Network.Provider>> svcProviderMap = new HashMap<Network.Service, Set<Network.Provider>>();
Set<Network.Provider> defaultProviders = new HashSet<Network.Provider>();
defaultProviders.add(Provider.VPCVirtualRouter);
boolean sourceNatSvc = false;
boolean firewallSvs = false;
// populate the services first
for (String serviceName : supportedServices) {
// validate if the service is supported
Service service = Network.Service.getService(serviceName);
if (service == null || service == Service.Gateway) {
throw new InvalidParameterValueException("Invalid service " + serviceName);
}
//don't allow security group service for vpc
if (service == Service.SecurityGroup) {
throw new UnsupportedServiceException("Service " + Service.SecurityGroup.getName() + " is not supported by VPC");
}
svcProviderMap.put(service, defaultProviders);
if (service == Service.NetworkACL) {
firewallSvs = true;
}
if (service == Service.SourceNat) {
sourceNatSvc = true;
}
}
if (!sourceNatSvc) {
s_logger.debug("Automatically adding source nat service to the list of VPC services");
svcProviderMap.put(Service.SourceNat, defaultProviders);
}
if (!firewallSvs) {
s_logger.debug("Automatically adding network ACL service to the list of VPC services");
svcProviderMap.put(Service.NetworkACL, defaultProviders);
}
svcProviderMap.put(Service.Gateway, defaultProviders);
return createVpcOffering(name, displayText, svcProviderMap, false, null);
}
@Override
@DB
public VpcOffering createVpcOffering(String name, String displayText, Map<Network.Service,
Set<Network.Provider>> svcProviderMap, boolean isDefault, State state) {
Transaction txn = Transaction.currentTxn();
txn.start();
// create vpc offering object
VpcOfferingVO offering = new VpcOfferingVO(name, displayText, isDefault, null);
if (state != null) {
offering.setState(state);
}
s_logger.debug("Adding vpc offering " + offering);
offering = _vpcOffDao.persist(offering);
// populate services and providers
if (svcProviderMap != null) {
for (Network.Service service : svcProviderMap.keySet()) {
Set<Provider> providers = svcProviderMap.get(service);
if (providers != null && !providers.isEmpty()) {
for (Network.Provider provider : providers) {
VpcOfferingServiceMapVO offService = new VpcOfferingServiceMapVO(offering.getId(), service, provider);
_vpcOffSvcMapDao.persist(offService);
s_logger.trace("Added service for the vpc offering: " + offService + " with provider " + provider.getName());
}
} else {
throw new InvalidParameterValueException("Provider is missing for the VPC offering service " + service.getName());
}
}
}
txn.commit();
UserContext.current().setEventDetails(" Id: " + offering.getId() + " Name: " + name);
return offering;
}
@Override
public Vpc getVpc(long vpcId) {
return _vpcDao.findById(vpcId);
}
@Override
public Vpc getActiveVpc(long vpcId) {
return _vpcDao.getActiveVpcById(vpcId);
}
@Override
public Map<Service, Set<Provider>> getVpcOffSvcProvidersMap(long vpcOffId) {
Map<Service, Set<Provider>> serviceProviderMap = new HashMap<Service, Set<Provider>>();
List<VpcOfferingServiceMapVO> map = _vpcOffSvcMapDao.listByVpcOffId(vpcOffId);
for (VpcOfferingServiceMapVO instance : map) {
String service = instance.getService();
Set<Provider> providers;
providers = serviceProviderMap.get(service);
if (providers == null) {
providers = new HashSet<Provider>();
}
providers.add(Provider.getProvider(instance.getProvider()));
serviceProviderMap.put(Service.getService(service), providers);
}
return serviceProviderMap;
}
@Override
public List<? extends VpcOffering> listVpcOfferings(Long id, String name, String displayText, List<String> supportedServicesStr,
Boolean isDefault, String keyword, String state, Long startIndex, Long pageSizeVal) {
Filter searchFilter = new Filter(VpcOfferingVO.class, "created", false, startIndex, pageSizeVal);
SearchCriteria<VpcOfferingVO> sc = _vpcOffDao.createSearchCriteria();
if (keyword != null) {
SearchCriteria<VpcOfferingVO> ssc = _vpcOffDao.createSearchCriteria();
ssc.addOr("displayText", SearchCriteria.Op.LIKE, "%" + keyword + "%");
ssc.addOr("name", SearchCriteria.Op.LIKE, "%" + keyword + "%");
sc.addAnd("name", SearchCriteria.Op.SC, ssc);
}
if (name != null) {
sc.addAnd("name", SearchCriteria.Op.LIKE, "%" + name + "%");
}
if (displayText != null) {
sc.addAnd("displayText", SearchCriteria.Op.LIKE, "%" + displayText + "%");
}
if (isDefault != null) {
sc.addAnd("isDefault", SearchCriteria.Op.EQ, isDefault);
}
if (state != null) {
sc.addAnd("state", SearchCriteria.Op.EQ, state);
}
if (id != null) {
sc.addAnd("id", SearchCriteria.Op.EQ, id);
}
List<VpcOfferingVO> offerings = _vpcOffDao.search(sc, searchFilter);
// filter by supported services
boolean listBySupportedServices = (supportedServicesStr != null && !supportedServicesStr.isEmpty() && !offerings.isEmpty());
if (listBySupportedServices) {
List<VpcOfferingVO> supportedOfferings = new ArrayList<VpcOfferingVO>();
Service[] supportedServices = null;
if (listBySupportedServices) {
supportedServices = 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 {
supportedServices[i] = service;
}
i++;
}
}
for (VpcOfferingVO offering : offerings) {
if (areServicesSupportedByVpcOffering(offering.getId(), supportedServices)) {
supportedOfferings.add(offering);
}
}
return supportedOfferings;
} else {
return offerings;
}
}
@Override
public boolean areServicesSupportedByVpcOffering(long vpcOffId, Service... services) {
return (_vpcOffSvcMapDao.areServicesSupportedByNetworkOffering(vpcOffId, services));
}
@Override
@ActionEvent(eventType = EventTypes.EVENT_VPC_OFFERING_DELETE, eventDescription = "deleting vpc offering")
public boolean deleteVpcOffering(long offId) {
UserContext.current().setEventDetails(" Id: " + offId);
// Verify vpc offering id
VpcOfferingVO offering = _vpcOffDao.findById(offId);
if (offering == null) {
throw new InvalidParameterValueException("unable to find vpc offering " + offId);
}
// Don't allow to delete default vpc offerings
if (offering.isDefault() == true) {
throw new InvalidParameterValueException("Default network offering can't be deleted");
}
// don't allow to delete vpc offering if it's in use by existing vpcs (the offering can be disabled though)
int vpcCount = _vpcDao.getVpcCountByOfferingId(offId);
if (vpcCount > 0) {
throw new InvalidParameterValueException("Can't delete vpc offering " + offId + " as its used by " + vpcCount + " vpcs. " +
"To make the network offering unavaiable, disable it");
}
if (_vpcOffDao.remove(offId)) {
return true;
} else {
return false;
}
}
@Override
@ActionEvent(eventType = EventTypes.EVENT_VPC_OFFERING_UPDATE, eventDescription = "updating vpc offering")
public VpcOffering updateVpcOffering(long vpcOffId, String vpcOfferingName, String displayText, String state) {
UserContext.current().setEventDetails(" Id: " + vpcOffId);
// Verify input parameters
VpcOfferingVO offeringToUpdate = _vpcOffDao.findById(vpcOffId);
if (offeringToUpdate == null) {
throw new InvalidParameterValueException("Unable to find vpc offering " + vpcOffId);
}
VpcOfferingVO offering = _vpcOffDao.createForUpdate(vpcOffId);
if (vpcOfferingName != null) {
offering.setName(vpcOfferingName);
}
if (displayText != null) {
offering.setDisplayText(displayText);
}
if (state != null) {
boolean validState = false;
for (VpcOffering.State st : VpcOffering.State.values()) {
if (st.name().equalsIgnoreCase(state)) {
validState = true;
offering.setState(st);
}
}
if (!validState) {
throw new InvalidParameterValueException("Incorrect state value: " + state);
}
}
if (_vpcOffDao.update(vpcOffId, offering)) {
s_logger.debug("Updated VPC offeirng id=" + vpcOffId);
return _vpcOffDao.findById(vpcOffId);
} else {
return null;
}
}
@Override
@ActionEvent(eventType = EventTypes.EVENT_VPC_CREATE, eventDescription = "creating vpc", create=true)
public Vpc createVpc(long zoneId, long vpcOffId, long vpcOwnerId, String vpcName, String displayText, String cidr,
String networkDomain) {
Account caller = UserContext.current().getCaller();
Account owner = _accountMgr.getAccount(vpcOwnerId);
//Verify that caller can perform actions in behalf of vpc owner
_accountMgr.checkAccess(caller, null, false, owner);
// Validate vpc offering
VpcOfferingVO vpcOff = _vpcOffDao.findById(vpcOffId);
if (vpcOff == null) {
InvalidParameterValueException ex = new InvalidParameterValueException("Unable to find vpc offering by specified id");
ex.addProxyObject("vpc_offerings", vpcOffId, "vpcOfferingId");
throw ex;
}
//Validate zone
DataCenter zone = _configMgr.getZone(zoneId);
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("data_center", zone.getId(), "zoneId");
throw ex;
}
if (networkDomain == null) {
// 1) Get networkDomain from the corresponding account
networkDomain = _ntwkMgr.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()) + _ntwkMgr.getDefaultNetworkDomain();
}
}
return createVpc(zoneId, vpcOffId, owner, vpcName, displayText, cidr, networkDomain);
}
@Override
public Vpc createVpc(long zoneId, long vpcOffId, Account vpcOwner, String vpcName, String displayText, String cidr,
String networkDomain) {
//the provider has to be enabled at least in one network in the zone
boolean providerEnabled = false;
for (PhysicalNetwork pNtwk : _pNtwkDao.listByZone(zoneId)) {
if (_ntwkMgr.isProviderEnabledInPhysicalNetwork(pNtwk.getId(), Provider.VPCVirtualRouter.getName())) {
providerEnabled = true;
break;
}
}
if (!providerEnabled) {
throw new InvalidParameterValueException("Provider " + Provider.VPCVirtualRouter.getName() +
" should be enabled in at least one physical network of the zone specified");
}
//Validate CIDR
if (!NetUtils.isValidCIDR(cidr)) {
throw new InvalidParameterValueException("Invalid CIDR specified " + cidr);
}
// 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 \"-\"");
}
//don't allow overlapping CIDRS for the VPCs of the same account
List<? extends Vpc> vpcs = getVpcsForAccount(vpcOwner.getId());
for (Vpc vpc : vpcs) {
if (NetUtils.isNetworksOverlap(cidr, vpc.getCidr())) {
throw new InvalidParameterValueException("Account already has vpc with cidr " + vpc.getCidr() +
" that overlaps the cidr specified: " + cidr);
}
}
VpcVO vpc = new VpcVO (zoneId, vpcName, displayText, vpcOwner.getId(), vpcOwner.getDomainId(), vpcOffId, cidr,
networkDomain);
vpc = _vpcDao.persist(vpc);
if (vpc != null) {
s_logger.debug("Created VPC " + vpc);
} else {
s_logger.debug("Failed to create VPC");
}
return vpc;
}
@Override
@ActionEvent(eventType = EventTypes.EVENT_VPC_DELETE, eventDescription = "deleting VPC")
public boolean deleteVpc(long vpcId) throws ConcurrentOperationException, ResourceUnavailableException {
UserContext.current().setEventDetails(" Id: " + vpcId);
Account caller = UserContext.current().getCaller();
// Verify vpc id
Vpc vpc = getVpc(vpcId);
if (vpc == null) {
throw new InvalidParameterValueException("unable to find VPC id=" + vpcId);
}
//verify permissions
_accountMgr.checkAccess(caller, null, false, vpc);
return destroyVpc(vpc);
}
@Override
public boolean destroyVpc(Vpc vpc) throws ConcurrentOperationException, ResourceUnavailableException {
UserContext ctx = UserContext.current();
//don't allow to delete vpc if it's in use by existing networks
int networksCount = _ntwkDao.getNetworkCountByVpcId(vpc.getId());
if (networksCount > 0) {
throw new InvalidParameterValueException("Can't delete VPC " + vpc + " as its used by " + networksCount + " networks");
}
//mark VPC as disabled
s_logger.debug("Updating VPC " + vpc + " with state " + Vpc.State.Inactive + " as a part of vpc delete");
VpcVO vpcVO = _vpcDao.findById(vpc.getId());
vpcVO.setState(Vpc.State.Inactive);
_vpcDao.update(vpc.getId(), vpcVO);
//shutdown VPC
if (!shutdownVpc(vpc.getId())) {
s_logger.warn("Failed to shutdown vpc " + vpc + " as a part of vpc destroy process");
return false;
}
//cleanup vpc resources
if (!cleanupVpcResources(vpc.getId(), ctx.getCaller(), ctx.getCallerUserId())) {
s_logger.warn("Failed to cleanup resources for vpc " + vpc);
return false;
}
//update the instance with removed flag only when the cleanup is executed successfully
if (_vpcDao.remove(vpc.getId())) {
s_logger.debug("Vpc " + vpc + " is removed succesfully");
return true;
} else {
return false;
}
}
@Override
@ActionEvent(eventType = EventTypes.EVENT_VPC_UPDATE, eventDescription = "updating vpc")
public Vpc updateVpc(long vpcId, String vpcName, String displayText) {
UserContext.current().setEventDetails(" Id: " + vpcId);
Account caller = UserContext.current().getCaller();
// Verify input parameters
VpcVO vpcToUpdate = _vpcDao.findById(vpcId);
if (vpcToUpdate == null) {
throw new InvalidParameterValueException("Unable to find vpc offering " + vpcId);
}
_accountMgr.checkAccess(caller, null, false, vpcToUpdate);
VpcVO vpc = _vpcDao.createForUpdate(vpcId);
if (vpcName != null) {
vpc.setName(vpcName);
}
if (displayText != null) {
vpc.setDisplayText(displayText);
}
if (_vpcDao.update(vpcId, vpc)) {
s_logger.debug("Updated VPC id=" + vpcId);
return _vpcDao.findById(vpcId);
} else {
return null;
}
}
@Override
public List<? extends Vpc> listVpcs(Long id, String vpcName, String displayText, List<String> supportedServicesStr,
String cidr, Long vpcOffId, String state, String accountName, Long domainId, String keyword,
Long startIndex, Long pageSizeVal, Long zoneId, Boolean isRecursive, Boolean listAll, Boolean restartRequired) {
Account caller = UserContext.current().getCaller();
List<Long> permittedAccounts = new ArrayList<Long>();
Ternary<Long, Boolean, ListProjectResourcesCriteria> domainIdRecursiveListProject = new Ternary<Long, Boolean,
ListProjectResourcesCriteria>(domainId, isRecursive, null);
_accountMgr.buildACLSearchParameters(caller, id, accountName, null, permittedAccounts, domainIdRecursiveListProject,
listAll, false);
domainId = domainIdRecursiveListProject.first();
isRecursive = domainIdRecursiveListProject.second();
ListProjectResourcesCriteria listProjectResourcesCriteria = domainIdRecursiveListProject.third();
Filter searchFilter = new Filter(VpcVO.class, "created", false, startIndex, pageSizeVal);
SearchBuilder<VpcVO> sb = _vpcDao.createSearchBuilder();
_accountMgr.buildACLSearchBuilder(sb, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria);
sb.and("name", sb.entity().getName(), SearchCriteria.Op.LIKE);
sb.and("id", sb.entity().getId(), SearchCriteria.Op.EQ);
sb.and("displayText", sb.entity().getDisplayText(), SearchCriteria.Op.LIKE);
sb.and("vpcOfferingId", sb.entity().getVpcOfferingId(), SearchCriteria.Op.EQ);
sb.and("zoneId", sb.entity().getZoneId(), SearchCriteria.Op.EQ);
sb.and("state", sb.entity().getState(), SearchCriteria.Op.EQ);
sb.and("restartRequired", sb.entity().isRestartRequired(), SearchCriteria.Op.EQ);
sb.and("cidr", sb.entity().getCidr(), SearchCriteria.Op.EQ);
// now set the SC criteria...
SearchCriteria<VpcVO> sc = sb.create();
_accountMgr.buildACLSearchCriteria(sc, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria);
if (keyword != null) {
SearchCriteria<VpcVO> ssc = _vpcDao.createSearchCriteria();
ssc.addOr("displayText", SearchCriteria.Op.LIKE, "%" + keyword + "%");
ssc.addOr("name", SearchCriteria.Op.LIKE, "%" + keyword + "%");
sc.addAnd("name", SearchCriteria.Op.SC, ssc);
}
if (vpcName != null) {
sc.addAnd("name", SearchCriteria.Op.LIKE, "%" + vpcName + "%");
}
if (displayText != null) {
sc.addAnd("displayText", SearchCriteria.Op.LIKE, "%" + displayText + "%");
}
if (id != null) {
sc.addAnd("id", SearchCriteria.Op.EQ, id);
}
if (vpcOffId != null) {
sc.addAnd("vpcOfferingId", SearchCriteria.Op.EQ, vpcOffId);
}
if (zoneId != null) {
sc.addAnd("zoneId", SearchCriteria.Op.EQ, zoneId);
}
if (state != null) {
sc.addAnd("state", SearchCriteria.Op.EQ, state);
}
if (cidr != null) {
sc.addAnd("cidr", SearchCriteria.Op.EQ, cidr);
}
if (restartRequired != null) {
sc.addAnd("restartRequired", SearchCriteria.Op.EQ, restartRequired);
}
List<VpcVO> vpcs = _vpcDao.search(sc, searchFilter);
// filter by supported services
boolean listBySupportedServices = (supportedServicesStr != null && !supportedServicesStr.isEmpty() && !vpcs.isEmpty());
if (listBySupportedServices) {
List<VpcVO> supportedVpcs = new ArrayList<VpcVO>();
Service[] supportedServices = null;
if (listBySupportedServices) {
supportedServices = 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 {
supportedServices[i] = service;
}
i++;
}
}
for (VpcVO vpc : vpcs) {
if (areServicesSupportedByVpcOffering(vpc.getVpcOfferingId(), supportedServices)) {
supportedVpcs.add(vpc);
}
}
return supportedVpcs;
} else {
return vpcs;
}
}
@Override
public List<Service> getSupportedServices() {
List<Service> services = new ArrayList<Service>();
services.add(Network.Service.Dhcp);
services.add(Network.Service.Dns);
services.add(Network.Service.UserData);
services.add(Network.Service.NetworkACL);
services.add(Network.Service.PortForwarding);
services.add(Network.Service.Lb);
services.add(Network.Service.SourceNat);
services.add(Network.Service.StaticNat);
services.add(Network.Service.Gateway);
services.add(Network.Service.Vpn);
return services;
}
@Override
public boolean startVpc(long vpcId, boolean destroyOnFailure) throws ConcurrentOperationException, ResourceUnavailableException,
InsufficientCapacityException {
UserContext ctx = UserContext.current();
Account caller = ctx.getCaller();
User callerUser = _accountMgr.getActiveUser(ctx.getCallerUserId());
//check if vpc exists
Vpc vpc = getActiveVpc(vpcId);
if (vpc == null) {
InvalidParameterValueException ex = new InvalidParameterValueException("Unable to find Enabled VPC by id specified");
ex.addProxyObject("vpc", vpcId, "VPC");
throw ex;
}
//permission check
_accountMgr.checkAccess(caller, null, false, vpc);
DataCenter dc = _configMgr.getZone(vpc.getZoneId());
DeployDestination dest = new DeployDestination(dc, null, null, null);
ReservationContext context = new ReservationContextImpl(null, null, callerUser,
_accountMgr.getAccount(vpc.getAccountId()));
boolean result = true;
try {
if (!startVpc(vpc, dest, context)) {
s_logger.warn("Failed to start vpc " + vpc);
result = false;
}
} catch (Exception ex) {
s_logger.warn("Failed to start vpc " + vpc + " due to ", ex);
result = false;
} finally {
//do cleanup
if (!result && destroyOnFailure) {
s_logger.debug("Destroying vpc " + vpc + " that failed to start");
if (destroyVpc(vpc)) {
s_logger.warn("Successfully destroyed vpc " + vpc + " that failed to start");
} else {
s_logger.warn("Failed to destroy vpc " + vpc + " that failed to start");
}
}
}
return result;
}
protected boolean startVpc(Vpc vpc, DeployDestination dest, ReservationContext context)
throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException {
//deploy provider
if (getVpcElement().implementVpc(vpc, dest, context)) {
s_logger.debug("Vpc " + vpc + " has started succesfully");
return true;
} else {
s_logger.warn("Vpc " + vpc + " failed to start");
return false;
}
}
@Override
public boolean shutdownVpc(long vpcId) throws ConcurrentOperationException, ResourceUnavailableException {
UserContext ctx = UserContext.current();
Account caller = ctx.getCaller();
//check if vpc exists
Vpc vpc = getVpc(vpcId);
if (vpc == null) {
throw new InvalidParameterValueException("Unable to find vpc by id " + vpcId);
}
//permission check
_accountMgr.checkAccess(caller, null, false, vpc);
//shutdown provider
boolean success = getVpcElement().shutdownVpc(vpc);
//FIXME - once more features are added to vpc (gateway/firewall rules, etc - cleanup them here)
if (success) {
s_logger.debug("Vpc " + vpc + " has been shutdown succesfully");
} else {
s_logger.warn("Vpc " + vpc + " failed to shutdown");
}
return success;
}
@Override
@DB
public void validateGuestNtkwForVpc(NetworkOffering guestNtwkOff, String cidr, String networkDomain,
Account networkOwner, Vpc vpc, Long networkId, String gateway) {
if (networkId == null) {
//1) Validate attributes that has to be passed in when create new guest network
validateNewVpcGuestNetwork(cidr, gateway, networkOwner, vpc, networkDomain);
}
//2) Only Isolated networks with Source nat service enabled can be added to vpc
if (!(guestNtwkOff.getGuestType() == GuestType.Isolated
&& _ntwkMgr.areServicesSupportedByNetworkOffering(guestNtwkOff.getId(), Service.SourceNat))) {
throw new InvalidParameterValueException("Only networks of type " + GuestType.Isolated + " with service "
+ Service.SourceNat +
" can be added as a part of VPC");
}
//3) No redundant router support
if (guestNtwkOff.getRedundantRouter()) {
throw new InvalidParameterValueException("No redunant router support when network belnogs to VPC");
}
//4) Conserve mode should be off
if (guestNtwkOff.isConserveMode()) {
throw new InvalidParameterValueException("Only networks with conserve mode Off can belong to VPC");
}
//5) Check services/providers against VPC providers
List<NetworkOfferingServiceMapVO> networkProviders = _ntwkOffServiceDao.listByNetworkOfferingId(guestNtwkOff.getId());
for (NetworkOfferingServiceMapVO nSvcVO : networkProviders) {
String pr = nSvcVO.getProvider();
String service = nSvcVO.getService();
if (_vpcOffServiceDao.findByServiceProviderAndOfferingId(service, pr, vpc.getVpcOfferingId()) == null) {
throw new InvalidParameterValueException("Service/provider combination " + service + "/" +
pr + " is not supported by VPC " + vpc);
}
}
//6) Only one network in the VPC can support LB
if (_ntwkMgr.areServicesSupportedByNetworkOffering(guestNtwkOff.getId(), Service.Lb)) {
List<? extends Network> networks = getVpcNetworks(vpc.getId());
for (Network network : networks) {
if (networkId != null && network.getId() == networkId.longValue()) {
//skip my own network
continue;
} else {
if (_ntwkMgr.areServicesSupportedInNetwork(network.getId(), Service.Lb)) {
throw new InvalidParameterValueException("LB service is already supported " +
"by network " + network + " in VPC " + vpc);
}
}
}
}
}
protected void validateNewVpcGuestNetwork(String cidr, String gateway, Account networkOwner, Vpc vpc, String networkDomain) {
Vpc locked = _vpcDao.acquireInLockTable(vpc.getId());
if (locked == null) {
throw new CloudRuntimeException("Unable to acquire lock on " + vpc);
}
try {
//1) CIDR is required
if (cidr == null) {
throw new InvalidParameterValueException("Gateway/netmask are required when create network for VPC");
}
//2) Network cidr should be within vpcCidr
if (!NetUtils.isNetworkAWithinNetworkB(cidr, vpc.getCidr())) {
throw new InvalidParameterValueException("Network cidr " + cidr + " is not within vpc " + vpc + " cidr");
}
//3) Network cidr shouldn't cross the cidr of other vpc network cidrs
List<? extends Network> ntwks = _ntwkDao.listByVpc(vpc.getId());
for (Network ntwk : ntwks) {
assert (cidr != null) : "Why the network cidr is null when it belongs to vpc?";
if (NetUtils.isNetworkAWithinNetworkB(ntwk.getCidr(), vpc.getCidr())
|| NetUtils.isNetworkAWithinNetworkB(vpc.getCidr(), ntwk.getCidr())) {
throw new InvalidParameterValueException("Network cidr " + cidr + " crosses other network cidr " + ntwk +
" belonging to the same vpc " + vpc);
}
}
//4) vpc and network should belong to the same owner
if (vpc.getAccountId() != networkOwner.getId()) {
throw new InvalidParameterValueException("Vpc " + vpc + " owner is different from the network owner "
+ networkOwner);
}
//5) network domain should be the same as VPC's
if (!networkDomain.equalsIgnoreCase(vpc.getNetworkDomain())) {
throw new InvalidParameterValueException("Network domain of the new network should match network" +
" domain of vpc " + vpc);
}
//6) gateway should never be equal to the cidr subnet
if (NetUtils.getCidrSubNet(cidr).equalsIgnoreCase(gateway)) {
throw new InvalidParameterValueException("Invalid gateway specified. It should never be equal to the cidr subnet value");
}
} finally {
s_logger.debug("Releasing lock for " + locked);
_vpcDao.releaseFromLockTable(locked.getId());
}
}
@Override
public VpcProvider getVpcElement() {
if (vpcElement == null) {
vpcElement = ((VpcProvider)_ntwkMgr.getElementImplementingProvider(Provider.VPCVirtualRouter.getName()));
}
return vpcElement;
}
@Override
public List<? extends Vpc> getVpcsForAccount(long accountId) {
return _vpcDao.listByAccountId(accountId);
}
public boolean cleanupVpcResources(long vpcId, Account caller, long callerUserId)
throws ResourceUnavailableException, ConcurrentOperationException {
s_logger.debug("Cleaning up resources for vpc id=" + vpcId);
boolean success = true;
//1) release all ip addresses
List<IPAddressVO> ipsToRelease = _ipAddressDao.listByAssociatedVpc(vpcId, null);
s_logger.debug("Releasing ips for vpc id=" + vpcId + " as a part of vpc cleanup");
for (IPAddressVO ipToRelease : ipsToRelease) {
success = success && _ntwkMgr.disassociatePublicIpAddress(ipToRelease.getId(), callerUserId, caller);
if (!success) {
s_logger.warn("Failed to cleanup ip " + ipToRelease + " as a part of vpc id=" + vpcId + " cleanup");
}
}
if (success) {
s_logger.debug("Released ip addresses for vpc id=" + vpcId + " as a part of cleanup vpc process");
} else {
s_logger.warn("Failed to release ip addresses for vpc id=" + vpcId + " as a part of cleanup vpc process");
//although it failed, proceed to the next cleanup step as it doesn't depend on the public ip release
}
//2) Delete all static route rules
if (!revokeStaticRoutesForVpc(vpcId, caller)) {
s_logger.warn("Failed to revoke static routes for vpc " + vpcId + " as a part of cleanup vpc process");
return false;
}
//3) Delete private gateway
VpcGateway gateway = getPrivateGatewayForVpc(vpcId);
if (gateway != null) {
s_logger.debug("Deleting private gateway " + gateway + " as a part of vpc " + vpcId + " resources cleanup");
if (!deleteVpcPrivateGateway(gateway.getId())) {
success = false;
s_logger.debug("Failed to delete private gateway " + gateway + " as a part of vpc " + vpcId + " resources cleanup");
} else {
s_logger.debug("Deleted private gateway " + gateway + " as a part of vpc " + vpcId + " resources cleanup");
}
}
return success;
}
@Override
@ActionEvent(eventType = EventTypes.EVENT_VPC_RESTART, eventDescription = "restarting vpc")
public boolean restartVpc(long vpcId) throws ConcurrentOperationException, ResourceUnavailableException,
InsufficientCapacityException {
Account caller = UserContext.current().getCaller();
// Verify input parameters
Vpc vpc = getActiveVpc(vpcId);
if (vpc == null) {
InvalidParameterValueException ex = new InvalidParameterValueException("Unable to find Enabled VPC by id specified");
ex.addProxyObject("vpc", vpcId, "VPC");
throw ex;
}
_accountMgr.checkAccess(caller, null, false, vpc);
s_logger.debug("Restarting VPC " + vpc);
boolean restartRequired = false;
try {
s_logger.debug("Shutting down VPC " + vpc + " as a part of VPC restart process");
if (!shutdownVpc(vpcId)) {
s_logger.warn("Failed to shutdown vpc as a part of VPC " + vpc + " restart process");
restartRequired = true;
return false;
}
s_logger.debug("Starting VPC " + vpc + " as a part of VPC restart process");
if (!startVpc(vpcId, false)) {
s_logger.warn("Failed to start vpc as a part of VPC " + vpc + " restart process");
restartRequired = true;
return false;
}
s_logger.debug("VPC " + vpc + " was restarted successfully");
return true;
} finally {
s_logger.debug("Updating VPC " + vpc + " with restartRequired=" + restartRequired);
VpcVO vo = _vpcDao.findById(vpcId);
vo.setRestartRequired(restartRequired);
_vpcDao.update(vpc.getId(), vo);
}
}
@Override
public List<DomainRouterVO> getVpcRouters(long vpcId) {
return _routerDao.listByVpcId(vpcId);
}
@Override
public PrivateGateway getVpcPrivateGateway(long id) {
VpcGateway gateway = _vpcGatewayDao.findById(id);
if (gateway == null || gateway.getType() != VpcGateway.Type.Private) {
return null;
}
return getPrivateGatewayProfile(gateway);
}
@Override
public VpcGateway getVpcGateway(long id) {
return _vpcGatewayDao.findById(id);
}
protected PrivateGateway getPrivateGatewayProfile(VpcGateway gateway) {
Network network = _ntwkMgr.getNetwork(gateway.getNetworkId());
return new PrivateGatewayProfile(gateway, network.getPhysicalNetworkId());
}
@Override
@DB
@ActionEvent(eventType = EventTypes.EVENT_PRIVATE_GATEWAY_CREATE, eventDescription = "creating vpc private gateway", create=true)
public PrivateGateway createVpcPrivateGateway(long vpcId, Long physicalNetworkId, String vlan, String ipAddress,
String gateway, String netmask, long gatewayOwnerId) throws ResourceAllocationException,
ConcurrentOperationException, InsufficientCapacityException {
//Validate parameters
Vpc vpc = getActiveVpc(vpcId);
if (vpc == null) {
InvalidParameterValueException ex = new InvalidParameterValueException("Unable to find Enabled VPC by id specified");
ex.addProxyObject("vpc", vpcId, "VPC");
throw ex;
}
//allow only one private gateway per vpc
VpcGatewayVO gatewayVO = _vpcGatewayDao.getPrivateGatewayForVpc(vpcId);
if (gatewayVO != null) {
throw new InvalidParameterValueException("Private ip address already exists for vpc " + vpc);
}
//Validate physical network
if (physicalNetworkId == null) {
List<? extends PhysicalNetwork> pNtwks = _ntwkMgr.getPhysicalNtwksSupportingTrafficType(vpc.getZoneId(), TrafficType.Guest);
if (pNtwks.isEmpty() || pNtwks.size() != 1) {
throw new InvalidParameterValueException("Physical network can't be determined; pass physical network id");
}
physicalNetworkId = pNtwks.get(0).getId();
}
Transaction txn = Transaction.currentTxn();
txn.start();
s_logger.debug("Creating Private gateway for VPC " + vpc);
//1) create private network
String networkName = "vpc-" + vpc.getName() + "-privateNetwork";
Network privateNtwk = _ntwkMgr.createPrivateNetwork(networkName, networkName, physicalNetworkId,
vlan, ipAddress, null, gateway, netmask, gatewayOwnerId, vpcId);
//2) create gateway entry
gatewayVO = new VpcGatewayVO(ipAddress, VpcGateway.Type.Private, vpcId, privateNtwk.getDataCenterId(),
privateNtwk.getId(), vlan, gateway, netmask, vpc.getAccountId(), vpc.getDomainId());
_vpcGatewayDao.persist(gatewayVO);
s_logger.debug("Created vpc gateway entry " + gatewayVO);
txn.commit();
return getVpcPrivateGateway(gatewayVO.getId());
}
@Override
@DB
public PrivateGateway applyVpcPrivateGateway(Long gatewayId) throws ConcurrentOperationException, ResourceUnavailableException {
VpcGatewayVO vo = _vpcGatewayDao.acquireInLockTable(gatewayId);
if (vo == null) {
throw new ConcurrentOperationException("Unable to lock gateway " + gatewayId);
}
try {
PrivateGateway gateway = getVpcPrivateGateway(gatewayId);
if (getVpcElement().createPrivateGateway(gateway)) {
s_logger.debug("Private gateway " + gateway + " was applied succesfully on the backend");
if (vo.getState() != VpcGateway.State.Ready) {
vo.setState(VpcGateway.State.Ready);
_vpcGatewayDao.update(vo.getId(), vo);
s_logger.debug("Marke gateway " + gateway + " with state " + VpcGateway.State.Ready);
}
return getVpcPrivateGateway(gatewayId);
} else {
s_logger.warn("Private gateway " + gateway + " failed to apply on the backend");
return null;
}
} finally {
if (vo != null) {
_vpcGatewayDao.releaseFromLockTable(gatewayId);
}
}
}
@Override
@ActionEvent(eventType = EventTypes.EVENT_PRIVATE_GATEWAY_DELETE, eventDescription = "deleting private gateway")
@DB
public boolean deleteVpcPrivateGateway(Long gatewayId) throws ConcurrentOperationException, ResourceUnavailableException {
VpcGatewayVO gatewayVO = _vpcGatewayDao.acquireInLockTable(gatewayId);
if (gatewayVO == null || gatewayVO.getType() != VpcGateway.Type.Private) {
throw new ConcurrentOperationException("Unable to lock gateway " + gatewayId);
}
try {
_vpcGatewayDao.update(gatewayVO.getId(), gatewayVO);
s_logger.debug("Marked gateway " + gatewayVO + " with state " + VpcGateway.State.Deleting);
//don't allow to remove gateway when there are static routes associated with it
long routeCount = _staticRouteDao.countRoutesByGateway(gatewayVO.getId());
if (routeCount > 0) {
throw new CloudRuntimeException("Can't delete private gateway " + gatewayVO + " as it has " + routeCount +
" static routes applied. Remove the routes first");
}
gatewayVO.setState(VpcGateway.State.Deleting);
//1) delete the gateway on the backend
PrivateGateway gateway = getVpcPrivateGateway(gatewayId);
if (getVpcElement().deletePrivateGateway(gateway)) {
s_logger.debug("Private gateway " + gateway + " was applied succesfully on the backend");
} else {
s_logger.warn("Private gateway " + gateway + " failed to apply on the backend");
return false;
}
//2) Delete private gateway from the DB
return deletePrivateGatewayFromTheDB(gateway);
} finally {
if (gatewayVO != null) {
_vpcGatewayDao.releaseFromLockTable(gatewayId);
}
}
}
@DB
protected boolean deletePrivateGatewayFromTheDB(PrivateGateway gateway) {
//check if there are ips allocted in the network
long networkId = gateway.getNetworkId();
boolean deleteNetwork = true;
List<PrivateIpVO> privateIps = _privateIpDao.listByNetworkId(networkId);
if (privateIps.size() > 1 || !privateIps.get(0).getIpAddress().equalsIgnoreCase(gateway.getIp4Address())) {
s_logger.debug("Not removing network id=" + gateway.getNetworkId() + " as it has private ip addresses for other gateways");
deleteNetwork = false;
}
Transaction txn = Transaction.currentTxn();
txn.start();
PrivateIpVO ip = _privateIpDao.findByIpAndVpcId(gateway.getVpcId(), gateway.getIp4Address());
if (ip != null) {
_privateIpDao.remove(ip.getId());
s_logger.debug("Deleted private ip " + ip);
}
if (deleteNetwork) {
User callerUser = _accountMgr.getActiveUser(UserContext.current().getCallerUserId());
Account owner = _accountMgr.getAccount(Account.ACCOUNT_ID_SYSTEM);
ReservationContext context = new ReservationContextImpl(null, null, callerUser, owner);
_ntwkMgr.destroyNetwork(networkId, context);
s_logger.debug("Deleted private network id=" + networkId);
}
_vpcGatewayDao.remove(gateway.getId());
s_logger.debug("Deleted private gateway " + gateway);
txn.commit();
return true;
}
@Override
public List<PrivateGateway> listPrivateGateway(ListPrivateGatewaysCmd cmd) {
String ipAddress = cmd.getIpAddress();
String vlan = cmd.getVlan();
Long vpcId = cmd.getVpcId();
Long id = cmd.getId();
Boolean isRecursive = cmd.isRecursive();
Boolean listAll = cmd.listAll();
Long domainId = cmd.getDomainId();
String accountName = cmd.getAccountName();
Account caller = UserContext.current().getCaller();
List<Long> permittedAccounts = new ArrayList<Long>();
String state = cmd.getState();
Filter searchFilter = new Filter(VpcGatewayVO.class, "id", false, cmd.getStartIndex(), cmd.getPageSizeVal());
Ternary<Long, Boolean, ListProjectResourcesCriteria> domainIdRecursiveListProject = new Ternary<Long, Boolean,
ListProjectResourcesCriteria>(domainId, isRecursive, null);
_accountMgr.buildACLSearchParameters(caller, null, accountName, null, permittedAccounts, domainIdRecursiveListProject,
listAll, false);
domainId = domainIdRecursiveListProject.first();
isRecursive = domainIdRecursiveListProject.second();
ListProjectResourcesCriteria listProjectResourcesCriteria = domainIdRecursiveListProject.third();
SearchBuilder<VpcGatewayVO> sb = _vpcGatewayDao.createSearchBuilder();
_accountMgr.buildACLSearchBuilder(sb, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria);
if (vlan != null) {
SearchBuilder<NetworkVO> ntwkSearch = _ntwkDao.createSearchBuilder();
ntwkSearch.and("vlan", ntwkSearch.entity().getBroadcastUri(), SearchCriteria.Op.EQ);
sb.join("networkSearch", ntwkSearch, sb.entity().getNetworkId(), ntwkSearch.entity().getId(), JoinBuilder.JoinType.INNER);
}
SearchCriteria<VpcGatewayVO> sc = sb.create();
_accountMgr.buildACLSearchCriteria(sc, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria);
if (id != null) {
sc.addAnd("id", Op.EQ, id);
}
if (ipAddress != null) {
sc.addAnd("ip4Address", Op.EQ, ipAddress);
}
if (state != null) {
sc.addAnd("state", Op.EQ, state);
}
if (vpcId != null) {
sc.addAnd("vpcId", Op.EQ, vpcId);
}
if (vlan != null) {
sc.setJoinParameters("networkSearch", "vlan", BroadcastDomainType.Vlan.toUri(vlan));
}
List<VpcGatewayVO> vos = _vpcGatewayDao.search(sc, searchFilter);
List<PrivateGateway> privateGtws = new ArrayList<PrivateGateway>(vos.size());
for (VpcGateway vo : vos) {
privateGtws.add(getPrivateGatewayProfile(vo));
}
return privateGtws;
}
@Override
public StaticRoute getStaticRoute(long routeId) {
return _staticRouteDao.findById(routeId);
}
@Override
public boolean applyStaticRoutes(long vpcId) throws ResourceUnavailableException {
Account caller = UserContext.current().getCaller();
List<? extends StaticRoute> routes = _staticRouteDao.listByVpcId(vpcId);
return applyStaticRoutes(routes, caller, true);
}
protected boolean applyStaticRoutes(List<? extends StaticRoute> routes, Account caller, boolean updateRoutesInDB) throws ResourceUnavailableException {
boolean success = true;
List<StaticRouteProfile> staticRouteProfiles = new ArrayList<StaticRouteProfile>(routes.size());
Map<Long, VpcGateway> gatewayMap = new HashMap<Long, VpcGateway>();
for (StaticRoute route : routes) {
VpcGateway gateway = gatewayMap.get(route.getVpcGatewayId());
if (gateway == null) {
gateway = _vpcGatewayDao.findById(route.getVpcGatewayId());
gatewayMap.put(gateway.getId(), gateway);
}
staticRouteProfiles.add(new StaticRouteProfile(route, gateway));
}
if (!applyStaticRoutes(staticRouteProfiles)) {
s_logger.warn("Routes are not completely applied");
return false;
} else {
if (updateRoutesInDB) {
for (StaticRoute route : routes) {
if (route.getState() == StaticRoute.State.Revoke) {
_staticRouteDao.remove(route.getId());
s_logger.debug("Removed route " + route + " from the DB");
} else if (route.getState() == StaticRoute.State.Add) {
StaticRouteVO ruleVO = _staticRouteDao.findById(route.getId());
ruleVO.setState(StaticRoute.State.Active);
_staticRouteDao.update(ruleVO.getId(), ruleVO);
s_logger.debug("Marked route " + route + " with state " + StaticRoute.State.Active);
}
}
}
}
return success;
}
protected boolean applyStaticRoutes(List<StaticRouteProfile> routes) throws ResourceUnavailableException{
if (routes.isEmpty()) {
s_logger.debug("No static routes to apply");
return true;
}
Vpc vpc = getVpc(routes.get(0).getVpcId());
s_logger.debug("Applying static routes for vpc " + vpc);
if (getVpcElement().applyStaticRoutes(vpc, routes)) {
s_logger.debug("Applied static routes for vpc " + vpc);
} else {
s_logger.warn("Failed to apply static routes for vpc " + vpc);
return false;
}
return true;
}
@Override
@ActionEvent(eventType = EventTypes.EVENT_STATIC_ROUTE_DELETE, eventDescription = "deleting static route")
public boolean revokeStaticRoute(long routeId) throws ResourceUnavailableException {
Account caller = UserContext.current().getCaller();
StaticRouteVO route = _staticRouteDao.findById(routeId);
if (route == null) {
throw new InvalidParameterValueException("Unable to find static route by id");
}
_accountMgr.checkAccess(caller, null, false, route);
markStaticRouteForRevoke(route, caller);
return applyStaticRoutes(route.getVpcId());
}
@DB
protected boolean revokeStaticRoutesForVpc(long vpcId, Account caller) throws ResourceUnavailableException {
//get all static routes for the vpc
List<StaticRouteVO> routes = _staticRouteDao.listByVpcId(vpcId);
s_logger.debug("Found " + routes.size() + " to revoke for the vpc " + vpcId);
if (!routes.isEmpty()) {
//mark all of them as revoke
Transaction txn = Transaction.currentTxn();
txn.start();
for (StaticRouteVO route : routes) {
markStaticRouteForRevoke(route, caller);
}
txn.commit();
return applyStaticRoutes(vpcId);
}
return true;
}
@Override
@DB
@ActionEvent(eventType = EventTypes.EVENT_STATIC_ROUTE_CREATE, eventDescription = "creating static route", create=true)
public StaticRoute createStaticRoute(long gatewayId, String cidr) throws NetworkRuleConflictException {
Account caller = UserContext.current().getCaller();
//parameters validation
VpcGateway gateway = _vpcGatewayDao.findById(gatewayId);
if (gateway == null) {
throw new InvalidParameterValueException("Invalid gateway id is given");
}
if (gateway.getState() != VpcGateway.State.Ready) {
throw new InvalidParameterValueException("Gateway is not in the " + VpcGateway.State.Ready + " state: " + gateway.getState());
}
Vpc vpc = getActiveVpc(gateway.getVpcId());
if (vpc == null) {
throw new InvalidParameterValueException("Can't add static route to VPC that is being deleted");
}
_accountMgr.checkAccess(caller, null, false, vpc);
if (!NetUtils.isValidCIDR(cidr)){
throw new InvalidParameterValueException("Invalid format for cidr " + cidr);
}
//TODO - check cidr for the conflicts
Transaction txn = Transaction.currentTxn();
txn.start();
StaticRouteVO newRoute = new StaticRouteVO(gateway.getId(), cidr, vpc.getId(), vpc.getAccountId(), vpc.getDomainId());
s_logger.debug("Adding static route " + newRoute);
newRoute = _staticRouteDao.persist(newRoute);
detectRoutesConflict(newRoute);
if (!_staticRouteDao.setStateToAdd(newRoute)) {
throw new CloudRuntimeException("Unable to update the state to add for " + newRoute);
}
UserContext.current().setEventDetails("Static route Id: " + newRoute.getId());
txn.commit();
return newRoute;
}
@Override
public List<? extends StaticRoute> listStaticRoutes(ListStaticRoutesCmd cmd) {
Long id = cmd.getId();
Long gatewayId = cmd.getGatewayId();
Long vpcId = cmd.getVpcId();
Long domainId = cmd.getDomainId();
Boolean isRecursive = cmd.isRecursive();
Boolean listAll = cmd.listAll();
String accountName = cmd.getAccountName();
Account caller = UserContext.current().getCaller();
List<Long> permittedAccounts = new ArrayList<Long>();
Ternary<Long, Boolean, ListProjectResourcesCriteria> domainIdRecursiveListProject = new Ternary<Long, Boolean,
ListProjectResourcesCriteria>(domainId, isRecursive, null);
_accountMgr.buildACLSearchParameters(caller, id, accountName, null, permittedAccounts, domainIdRecursiveListProject,
listAll, false);
domainId = domainIdRecursiveListProject.first();
isRecursive = domainIdRecursiveListProject.second();
ListProjectResourcesCriteria listProjectResourcesCriteria = domainIdRecursiveListProject.third();
Filter searchFilter = new Filter(StaticRouteVO.class, "created", false, cmd.getStartIndex(), cmd.getPageSizeVal());
SearchBuilder<StaticRouteVO> sb = _staticRouteDao.createSearchBuilder();
_accountMgr.buildACLSearchBuilder(sb, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria);
sb.and("id", sb.entity().getId(), SearchCriteria.Op.EQ);
sb.and("vpcId", sb.entity().getVpcId(), SearchCriteria.Op.EQ);
sb.and("vpcGatewayId", sb.entity().getVpcGatewayId(), SearchCriteria.Op.EQ);
SearchCriteria<StaticRouteVO> sc = sb.create();
_accountMgr.buildACLSearchCriteria(sc, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria);
if (id != null) {
sc.addAnd("id", Op.EQ, id);
}
if (vpcId != null) {
sc.addAnd("vpcId", Op.EQ, vpcId);
}
if (gatewayId != null) {
sc.addAnd("vpcGatewayId", Op.EQ, gatewayId);
}
return _staticRouteDao.search(sc, searchFilter);
}
protected void detectRoutesConflict(StaticRoute newRoute) throws NetworkRuleConflictException {
List<? extends StaticRoute> routes = _staticRouteDao.listByGatewayIdAndNotRevoked(newRoute.getVpcGatewayId());
assert (routes.size() >= 1) : "For static routes, we now always first persist the route and then check for " +
"network conflicts so we should at least have one rule at this point.";
for (StaticRoute route : routes) {
if (route.getId() == newRoute.getId()) {
continue; // Skips my own route.
}
if (NetUtils.isNetworksOverlap(route.getCidr(), newRoute.getCidr())) {
throw new NetworkRuleConflictException("New static route cidr conflicts with existing route " + route);
}
}
}
protected void markStaticRouteForRevoke(StaticRouteVO route, Account caller) {
s_logger.debug("Revoking static route " + route);
if (caller != null) {
_accountMgr.checkAccess(caller, null, false, route);
}
if (route.getState() == StaticRoute.State.Staged) {
if (s_logger.isDebugEnabled()) {
s_logger.debug("Found a static route that is still in stage state so just removing it: " + route);
}
_staticRouteDao.remove(route.getId());
} else if (route.getState() == StaticRoute.State.Add || route.getState() == StaticRoute.State.Active) {
route.setState(StaticRoute.State.Revoke);
_staticRouteDao.update(route.getId(), route);
s_logger.debug("Marked static route " + route + " with state " + StaticRoute.State.Revoke);
}
}
protected class VpcCleanupTask implements Runnable {
@Override
public void run() {
try {
GlobalLock lock = GlobalLock.getInternLock("VpcCleanup");
if (lock == null) {
s_logger.debug("Couldn't get the global lock");
return;
}
if (!lock.lock(30)) {
s_logger.debug("Couldn't lock the db");
return;
}
Transaction txn = null;
try {
txn = Transaction.open(Transaction.CLOUD_DB);
// Cleanup inactive VPCs
List<VpcVO> inactiveVpcs = _vpcDao.listInactiveVpcs();
s_logger.info("Found " + inactiveVpcs.size() + " removed VPCs to cleanup");
for (VpcVO vpc : inactiveVpcs) {
s_logger.debug("Cleaning up " + vpc);
destroyVpc(vpc);
}
} catch (Exception e) {
s_logger.error("Exception ", e);
} finally {
if (txn != null) {
txn.close();
}
lock.unlock();
}
} catch (Exception e) {
s_logger.error("Exception ", e);
}
}
}
@Override
public VpcGateway getPrivateGatewayForVpc(long vpcId) {
return _vpcGatewayDao.getPrivateGatewayForVpc(vpcId);
}
}