Package com.cloud.network.vpc

Source Code of com.cloud.network.vpc.VpcManagerImpl$VpcCleanupTask

// 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.Arrays;
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.acl.ControlledEntity.ACLType;
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.Resource.ResourceType;
import com.cloud.configuration.dao.ConfigurationDao;
import com.cloud.dc.DataCenter;
import com.cloud.dc.Vlan.VlanType;
import com.cloud.dc.VlanVO;
import com.cloud.dc.dao.VlanDao;
import com.cloud.deploy.DeployDestination;
import com.cloud.event.ActionEvent;
import com.cloud.event.EventTypes;
import com.cloud.exception.ConcurrentOperationException;
import com.cloud.exception.InsufficientAddressCapacityException;
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.hypervisor.Hypervisor.HypervisorType;
import com.cloud.network.IPAddressVO;
import com.cloud.network.IpAddress;
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.addr.PublicIp;
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.dao.Site2SiteVpnGatewayDao;
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.network.vpn.Site2SiteVpnManager;
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.server.ResourceTag.TaggedResourceType;
import com.cloud.tags.ResourceTagVO;
import com.cloud.tags.dao.ResourceTagDao;
import com.cloud.user.Account;
import com.cloud.user.AccountManager;
import com.cloud.user.ResourceLimitService;
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;
    @Inject
    Site2SiteVpnGatewayDao _vpnGatewayDao;
    @Inject
    Site2SiteVpnManager _s2sVpnMgr;
    @Inject
    VlanDao _vlanDao = null;
    @Inject
    ResourceLimitService _resourceLimitMgr;


    private final ScheduledExecutorService _executor = Executors.newScheduledThreadPool(1, new NamedThreadFactory("VpcChecker"));
    private VpcProvider vpcElement = null;
    private final List<Service> nonSupportedServices = Arrays.asList(Service.SecurityGroup, Service.Firewall);
    String _name;
    int _cleanupInterval;
    int _maxNetworks;
    SearchBuilder<IPAddressVO> IpAddressSearch;

    @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);
                    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

        String maxNtwks = configs.get(Config.VpcMaxNetworks.key());
        _maxNetworks = NumbersUtil.parseInt(maxNtwks, 3); // max=3 is default
       
       
        IpAddressSearch = _ipAddressDao.createSearchBuilder();
        IpAddressSearch.and("accountId", IpAddressSearch.entity().getAllocatedToAccountId(), Op.EQ);
        IpAddressSearch.and("dataCenterId", IpAddressSearch.entity().getDataCenterId(), Op.EQ);
        IpAddressSearch.and("vpcId", IpAddressSearch.entity().getVpcId(), Op.EQ);
        IpAddressSearch.and("associatedWithNetworkId", IpAddressSearch.entity().getAssociatedWithNetworkId(), Op.EQ);
        SearchBuilder<VlanVO> virtualNetworkVlanSB = _vlanDao.createSearchBuilder();
        virtualNetworkVlanSB.and("vlanType", virtualNetworkVlanSB.entity().getVlanType(), Op.EQ);
        IpAddressSearch.join("virtualNetworkVlanSB", virtualNetworkVlanSB, IpAddressSearch.entity().getVlanId(), virtualNetworkVlanSB.entity().getId(), JoinBuilder.JoinType.INNER);
        IpAddressSearch.done();
       
        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 || nonSupportedServices.contains(service)) {
                throw new InvalidParameterValueException("Service " + serviceName + " is not supported in 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);
              
        VpcOffering offering = createVpcOffering(name, displayText, svcProviderMap, false, null);
        UserContext.current().setEventDetails(" Id: " + offering.getId() + " Name: " + name);
       
        return offering;
    }

   
    @DB
    protected 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();

        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;
        }
    }


    protected 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) throws ResourceAllocationException {
        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);
       
        //check resource limit
        _resourceLimitMgr.checkResourceLimit(owner, ResourceType.vpc);

        // Validate vpc offering
        VpcOfferingVO vpcOff = _vpcOffDao.findById(vpcOffId);
        if (vpcOff == null || vpcOff.getState() != State.Enabled) {
            InvalidParameterValueException ex = new InvalidParameterValueException("Unable to find vpc offering in " + State.Enabled +
                    " state 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 boolean vpcProviderEnabledInZone(long zoneId)
    {
        //the provider has to be enabled at least in one network in the zone
        for (PhysicalNetwork pNtwk : _pNtwkDao.listByZone(zoneId)) {
            if (_ntwkMgr.isProviderEnabledInPhysicalNetwork(pNtwk.getId(), Provider.VPCVirtualRouter.getName())) {
                return true;
            }
        }
       
        return false;
    }

   
    @DB
    protected Vpc createVpc(long zoneId, long vpcOffId, Account vpcOwner, String vpcName, String displayText, String cidr,
            String networkDomain) {
       
        if (!vpcProviderEnabledInZone(zoneId)) {
            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);
        }
       
        //cidr has to be RFC 1918 complient
        if (!NetUtils.validateGuestCidr(cidr)) {
            throw new InvalidParameterValueException("Guest Cidr " + cidr + " is not RFC1918 compliant");
        }

        // 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 \"-\"");
        }

        Transaction txn = Transaction.currentTxn();
        txn.start();
        VpcVO vpc = new VpcVO (zoneId, vpcName, displayText, vpcOwner.getId(), vpcOwner.getDomainId(), vpcOffId, cidr,
                networkDomain);
        vpc = _vpcDao.persist(vpc);
        _resourceLimitMgr.incrementResourceCount(vpcOwner.getId(), ResourceType.vpc);
        txn.commit();

        s_logger.debug("Created VPC " + 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
    @DB
    public boolean destroyVpc(Vpc vpc) throws ConcurrentOperationException, ResourceUnavailableException {
        UserContext ctx = UserContext.current();
        s_logger.debug("Destroying vpc " + vpc);
       
        //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 inactive
        if (vpc.getState() != Vpc.State.Inactive) {
            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);
           
            Transaction txn = Transaction.currentTxn();
            txn.start();
            _vpcDao.update(vpc.getId(), vpcVO);
           
            //decrement resource count
            _resourceLimitMgr.decrementResourceCount(vpc.getAccountId(), ResourceType.vpc);
            txn.commit();
        }
       
        //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 destroyed succesfully");
            return true;
        } else {
            s_logger.warn("Vpc " + vpc + " failed to destroy");
            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, Map<String, String> tags, Long projectId) {
        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, projectId, 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);
       
        if (tags != null && !tags.isEmpty()) {
            SearchBuilder<ResourceTagVO> tagSearch = _resourceTagDao.createSearchBuilder();
            for (int count=0; count < tags.size(); count++) {
                tagSearch.or().op("key" + String.valueOf(count), tagSearch.entity().getKey(), SearchCriteria.Op.EQ);
                tagSearch.and("value" + String.valueOf(count), tagSearch.entity().getValue(), SearchCriteria.Op.EQ);
                tagSearch.cp();
            }
            tagSearch.and("resourceType", tagSearch.entity().getResourceType(), SearchCriteria.Op.EQ);
            sb.groupBy(sb.entity().getId());
            sb.join("tagSearch", tagSearch, sb.entity().getId(), tagSearch.entity().getResourceId(), JoinBuilder.JoinType.INNER);
        }
       
        // 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 (tags != null && !tags.isEmpty()) {
            int count = 0;
            sc.setJoinParameters("tagSearch", "resourceType", TaggedResourceType.Vpc.toString());
            for (String key : tags.keySet()) {
                sc.setJoinParameters("tagSearch", "key" + String.valueOf(count), key);
                sc.setJoinParameters("tagSearch", "value" + String.valueOf(count), tags.get(key));
                count++;
            }  
       }

        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;
        }
    }

   
    protected 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
        s_logger.debug("Shutting down vpc " + vpc);
        boolean success = getVpcElement().shutdownVpc(vpc);

        //TODO - shutdown all vpc resources here (ACLs, gateways, etc)
        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 validateNtkwOffForVpc(long ntwkOffId, String cidr, String networkDomain,
            Account networkOwner, Vpc vpc, Long networkId, String gateway) {
       
        NetworkOffering guestNtwkOff = _configMgr.getNetworkOffering(ntwkOffId);
       
        if (guestNtwkOff == null) {
            throw new InvalidParameterValueException("Can't find network offering by id specified");
        }

        if (networkId == null) {
            //1) Validate attributes that has to be passed in when create new guest network
            validateNewVpcGuestNetwork(cidr, gateway, networkOwner, vpc, networkDomain);
        }

        //2) validate network offering attributes
        List<Service> svcs = _ntwkMgr.listNetworkOfferingServices(guestNtwkOff.getId());
        validateNtwkOffForVpc(guestNtwkOff, svcs);

        //3) 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);
            }
        }

        //4) 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);
                    }
                }
            }
        }
    }

    @Override
    public void validateNtwkOffForVpc(NetworkOffering guestNtwkOff, List<Service> supportedSvcs) {
        //1) in current release, only vpc provider is supported by Vpc offering
        List<Provider> providers = _ntwkMgr.getNtwkOffDistinctProviders(guestNtwkOff.getId());
        for (Provider provider : providers) {
            if (provider != Provider.VPCVirtualRouter) {
                throw new InvalidParameterValueException("Only provider of type " + Provider.VPCVirtualRouter.getName()
                        + " is supported for network offering that can be used in VPC");
            }
        }
       
        //2) Only Isolated networks with Source nat service enabled can be added to vpc
        if (!(guestNtwkOff.getGuestType() == GuestType.Isolated
                && supportedSvcs.contains(Service.SourceNat))) {

            throw new InvalidParameterValueException("Only network offerings of type " + GuestType.Isolated + " with service "
                    + Service.SourceNat.getName() +
                    " are valid for 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");
        }
    }

    @DB
    protected void validateNewVpcGuestNetwork(String cidr, String gateway, Account networkOwner, Vpc vpc, String networkDomain) {
       
        Transaction txn = Transaction.currentTxn();
        txn.start();
        Vpc locked = _vpcDao.acquireInLockTable(vpc.getId());
        if (locked == null) {
            throw new CloudRuntimeException("Unable to acquire lock on " + vpc);
        }
       
        try {
            //check number of active networks in vpc
            if (_ntwkDao.countVpcNetworks(vpc.getId()) >= _maxNetworks) {
                throw new CloudRuntimeException("Number of networks per VPC can't extend "
                        + _maxNetworks + "; increase it using global config " + Config.VpcMaxNetworks);
            }
           
           
            //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(), cidr)
                        || NetUtils.isNetworkAWithinNetworkB(cidr, 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");
            }

            txn.commit();
        } finally {
            s_logger.debug("Releasing lock for " + locked);
            _vpcDao.releaseFromLockTable(locked.getId());
        }
    }


    protected VpcProvider getVpcElement() {
        if (vpcElement == null) {
            vpcElement = ((VpcProvider)_ntwkMgr.getElementImplementingProvider(Provider.VPCVirtualRouter.getName()));
        }

        if (vpcElement == null) {
            throw new CloudRuntimeException("Failed to initialize vpc element");
        }
       
        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) Remove VPN connections and VPN gateway
        s_logger.debug("Cleaning up existed site to site VPN connections");
        _s2sVpnMgr.cleanupVpnConnectionByVpc(vpcId);
        s_logger.debug("Cleaning up existed site to site VPN gateways");
        _s2sVpnMgr.cleanupVpnGatewayByVpc(vpcId);
       
        //2) 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
        }

        //3) 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;
        }

        //4) 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
    public PrivateGateway applyVpcPrivateGateway(long gatewayId, boolean destroyOnFailure) throws ConcurrentOperationException, ResourceUnavailableException {
        VpcGatewayVO vo = _vpcGatewayDao.findById(gatewayId);

        boolean success = false;
        try {
            PrivateGateway gateway = getVpcPrivateGateway(gatewayId);
            success = getVpcElement().createPrivateGateway(gateway);
            if (success) {
                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 {
            //do cleanup
            if (!success) {
                if (destroyOnFailure) {
                    s_logger.debug("Destroying private gateway " + vo + " that failed to start");
                    if (deleteVpcPrivateGateway(gatewayId)) {
                        s_logger.warn("Successfully destroyed vpc " + vo + " that failed to start");
                    } else {
                        s_logger.warn("Failed to destroy vpc " + vo + " that failed to start");
                    }
                }   
            }
        }     
    }

    @Override
    @ActionEvent(eventType = EventTypes.EVENT_PRIVATE_GATEWAY_DELETE, eventDescription = "deleting private gateway")
    @DB
    public boolean deleteVpcPrivateGateway(long gatewayId) throws ConcurrentOperationException, ResourceUnavailableException {
       
        Transaction txn = Transaction.currentTxn();
        txn.start();
        VpcGatewayVO gatewayVO = _vpcGatewayDao.acquireInLockTable(gatewayId);
        if (gatewayVO == null || gatewayVO.getType() != VpcGateway.Type.Private) {
            throw new ConcurrentOperationException("Unable to lock gateway " + gatewayId);
        }

        try {
            //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);
            _vpcGatewayDao.update(gatewayVO.getId(), gatewayVO);
            s_logger.debug("Marked gateway " + gatewayVO + " with state " + VpcGateway.State.Deleting);
           
            txn.commit();

            //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();
        Long projectId = cmd.getProjectId();

        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, id, accountName, projectId, 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);
        }
       
        //validate the cidr
        //1) CIDR should be outside of VPC cidr for guest networks
        if (NetUtils.isNetworksOverlap(vpc.getCidr(), cidr)) {
            throw new InvalidParameterValueException("CIDR should be outside of VPC cidr " + vpc.getCidr());
        }
       
        //2) CIDR should be outside of link-local cidr
        if (NetUtils.isNetworksOverlap(vpc.getCidr(), NetUtils.getLinkLocalCIDR())) {
            throw new InvalidParameterValueException("CIDR should be outside of link local cidr " + NetUtils.getLinkLocalCIDR());
        }

        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>();
        Map<String, String> tags = cmd.getTags();
        Long projectId = cmd.getProjectId();

        Ternary<Long, Boolean, ListProjectResourcesCriteria> domainIdRecursiveListProject = new Ternary<Long, Boolean,
                ListProjectResourcesCriteria>(domainId, isRecursive, null);
        _accountMgr.buildACLSearchParameters(caller, id, accountName, projectId, 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);
       
        if (tags != null && !tags.isEmpty()) {
            SearchBuilder<ResourceTagVO> tagSearch = _resourceTagDao.createSearchBuilder();
            for (int count=0; count < tags.size(); count++) {
                tagSearch.or().op("key" + String.valueOf(count), tagSearch.entity().getKey(), SearchCriteria.Op.EQ);
                tagSearch.and("value" + String.valueOf(count), tagSearch.entity().getValue(), SearchCriteria.Op.EQ);
                tagSearch.cp();
            }
            tagSearch.and("resourceType", tagSearch.entity().getResourceType(), SearchCriteria.Op.EQ);
            sb.groupBy(sb.entity().getId());
            sb.join("tagSearch", tagSearch, sb.entity().getId(), tagSearch.entity().getResourceId(), JoinBuilder.JoinType.INNER);
        }
       
        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);
        }
       
        if (tags != null && !tags.isEmpty()) {
            int count = 0;
            sc.setJoinParameters("tagSearch", "resourceType", TaggedResourceType.StaticRoute.toString());
            for (String key : tags.keySet()) {
                sc.setJoinParameters("tagSearch", "key" + String.valueOf(count), key);
                sc.setJoinParameters("tagSearch", "value" + String.valueOf(count), tags.get(key));
                count++;
            }  
        }
       
        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);
    }

   
    @DB
    @Override
    @ActionEvent(eventType = EventTypes.EVENT_NET_IP_ASSIGN, eventDescription = "associating Ip", async = true)
    public IpAddress associateIPToVpc(long ipId, long vpcId) throws ResourceAllocationException, ResourceUnavailableException,
    InsufficientAddressCapacityException, ConcurrentOperationException {
        Account caller = UserContext.current().getCaller();
        Account owner = null;

        IpAddress ipToAssoc = _ntwkMgr.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;
        }

        Vpc vpc = getVpc(vpcId);
        if (vpc == null) {
            throw new InvalidParameterValueException("Invalid VPC id provided");
        }

        // check permissions
        _accountMgr.checkAccess(caller, null, true, owner, vpc);

        boolean isSourceNat = false;
        if (getExistingSourceNatInVpc(owner.getId(), vpcId) == null) {
            isSourceNat = true;
        }

        s_logger.debug("Associating ip " + ipToAssoc + " to vpc " + vpc);

        Transaction txn = Transaction.currentTxn();
        txn.start();
        IPAddressVO ip = _ipAddressDao.findById(ipId);
        //update ip address with networkId
        ip.setVpcId(vpcId);
        ip.setSourceNat(isSourceNat);
        _ipAddressDao.update(ipId, ip);

        //mark ip as allocated
        _ntwkMgr.markPublicIpAsAllocated(ip);
        txn.commit();

        s_logger.debug("Successfully assigned ip " + ipToAssoc + " to vpc " + vpc);

        return _ipAddressDao.findById(ipId);
    }
   
   
    @Override
    public void unassignIPFromVpcNetwork(long ipId, long networkId) {
        IPAddressVO ip = _ipAddressDao.findById(ipId);
        if (ipUsedInVpc(ip)) {
            return;
        }

        if (ip == null || ip.getVpcId() == null) {
            return;
        }

        s_logger.debug("Releasing VPC ip address " + ip + " from vpc network id=" + networkId);

        long  vpcId = ip.getVpcId();
        boolean success = false;
        try {
            //unassign ip from the VPC router
            success = _ntwkMgr.applyIpAssociations(_ntwkMgr.getNetwork(networkId), true);
        } catch (ResourceUnavailableException ex) {
            throw new CloudRuntimeException("Failed to apply ip associations for network id=" + networkId +
                    " as a part of unassigning ip " + ipId + " from vpc", ex);
        }

        if (success) {
            ip.setAssociatedWithNetworkId(null);
            _ipAddressDao.update(ipId, ip);
            s_logger.debug("IP address " + ip + " is no longer associated with the network inside vpc id=" + vpcId);
        } else {
            throw new CloudRuntimeException("Failed to apply ip associations for network id=" + networkId +
                    " as a part of unassigning ip " + ipId + " from vpc");
        }
        s_logger.debug("Successfully released VPC ip address " + ip + " back to VPC pool ");
    }
   
    @Override
    public boolean ipUsedInVpc(IpAddress ip) {
        return (ip != null && ip.getVpcId() != null &&
                (ip.isOneToOneNat() || !_firewallDao.listByIp(ip.getId()).isEmpty()));
    }
   
    @DB
    @Override
    public Network createVpcGuestNetwork(long ntwkOffId, String name, String displayText, String gateway,
            String cidr, String vlanId, String networkDomain, Account owner, Long domainId,
            PhysicalNetwork pNtwk, long zoneId, ACLType aclType, Boolean subdomainAccess, long vpcId, Account caller)
                    throws ConcurrentOperationException, InsufficientCapacityException, ResourceAllocationException {

        Vpc vpc = getActiveVpc(vpcId);

        if (vpc == null) {
            InvalidParameterValueException ex = new InvalidParameterValueException("Unable to find Enabled VPC ");
            ex.addProxyObject("vpc", vpcId, "VPC");
            throw ex;
        }
        _accountMgr.checkAccess(caller, null, false, vpc);
       
        if (networkDomain == null) {
            networkDomain = vpc.getNetworkDomain();
        }
       
        if (vpc.getZoneId() != zoneId) {
            throw new InvalidParameterValueException("New network doesn't belong to vpc zone");
        }
       
        //1) Validate if network can be created for VPC
        validateNtkwOffForVpc(ntwkOffId, cidr, networkDomain, owner, vpc, null, gateway);

        //2) Create network
        Network guestNetwork = _ntwkMgr.createGuestNetwork(ntwkOffId, name, displayText, gateway, cidr, vlanId,
                networkDomain, owner, domainId, pNtwk, zoneId, aclType, subdomainAccess, vpcId);

        return guestNetwork;
    }
   
   
    protected IPAddressVO getExistingSourceNatInVpc(long ownerId, long vpcId) {

        List<IPAddressVO> addrs = listPublicIpsAssignedToVpc(ownerId, true, vpcId);
       
        IPAddressVO sourceNatIp = null;
        if (addrs.isEmpty()) {
            return null;
        } else {
            // Account already has ip addresses
            for (IPAddressVO addr : addrs) {
                if (addr.isSourceNat()) {
                    sourceNatIp = addr;
                    return sourceNatIp;
                }
            }

            assert (sourceNatIp != null) : "How do we get a bunch of ip addresses but none of them are source nat? " +
            "account=" + ownerId + "; vpcId=" + vpcId;
        }

        return sourceNatIp;
    }
   
    protected List<IPAddressVO> listPublicIpsAssignedToVpc(long accountId, Boolean sourceNat, long vpcId) {
        SearchCriteria<IPAddressVO> sc = IpAddressSearch.create();
        sc.setParameters("accountId", accountId);
        sc.setParameters("vpcId", vpcId);

        if (sourceNat != null) {
            sc.addAnd("sourceNat", SearchCriteria.Op.EQ, sourceNat);
        }
        sc.setJoinParameters("virtualNetworkVlanSB", "vlanType", VlanType.VirtualNetwork);

        return _ipAddressDao.search(sc, null);
    }
   
   
    @Override
    public PublicIp assignSourceNatIpAddressToVpc(Account owner, Vpc vpc) throws InsufficientAddressCapacityException, ConcurrentOperationException {
        long dcId = vpc.getZoneId();

        IPAddressVO sourceNatIp = getExistingSourceNatInVpc(owner.getId(), vpc.getId());

        PublicIp ipToReturn = null;

        if (sourceNatIp != null) {
            ipToReturn = new PublicIp(sourceNatIp, _vlanDao.findById(sourceNatIp.getVlanId()),
                    NetUtils.createSequenceBasedMacAddress(sourceNatIp.getMacAddress()));
        } else {
            ipToReturn = _ntwkMgr.assignDedicateIpAddress(owner, null, vpc.getId(), dcId, true);
        }

        return ipToReturn;
    }


    @Override
    public Network updateVpcGuestNetwork(long networkId, String name, String displayText, Account callerAccount,
            User callerUser, String domainSuffix, Long ntwkOffId, Boolean changeCidr) {
        NetworkVO network = _ntwkDao.findById(networkId);
        if (network == null) {
            throw new InvalidParameterValueException("Couldn't find network by id");
        }
        //perform below validation if the network is vpc network
        if (network.getVpcId() != null && ntwkOffId != null) {
            Vpc vpc = getVpc(network.getVpcId());
            validateNtkwOffForVpc(ntwkOffId, null, null, null, vpc, networkId, null);
        }
       
        return _ntwkMgr.updateGuestNetwork(networkId, name, displayText, callerAccount, callerUser, domainSuffix,
                ntwkOffId, changeCidr);
    }

    @Override
    public List<HypervisorType> getSupportedVpcHypervisors() {
        List<HypervisorType> hTypes = new ArrayList<HypervisorType>();
        hTypes.add(HypervisorType.XenServer);
        hTypes.add(HypervisorType.VMware);
        hTypes.add(HypervisorType.KVM);
        return hTypes;
    }
}
TOP

Related Classes of com.cloud.network.vpc.VpcManagerImpl$VpcCleanupTask

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.