| // 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.vpn; |
| |
| import java.util.ArrayList; |
| import java.util.List; |
| import java.util.Map; |
| |
| import javax.inject.Inject; |
| import javax.naming.ConfigurationException; |
| |
| import org.apache.cloudstack.annotation.AnnotationService; |
| import org.apache.cloudstack.annotation.dao.AnnotationDao; |
| import org.apache.log4j.Logger; |
| import org.springframework.stereotype.Component; |
| |
| import org.apache.cloudstack.api.command.user.vpn.CreateVpnConnectionCmd; |
| import org.apache.cloudstack.api.command.user.vpn.CreateVpnCustomerGatewayCmd; |
| import org.apache.cloudstack.api.command.user.vpn.CreateVpnGatewayCmd; |
| import org.apache.cloudstack.api.command.user.vpn.DeleteVpnConnectionCmd; |
| import org.apache.cloudstack.api.command.user.vpn.DeleteVpnCustomerGatewayCmd; |
| import org.apache.cloudstack.api.command.user.vpn.DeleteVpnGatewayCmd; |
| import org.apache.cloudstack.api.command.user.vpn.ListVpnConnectionsCmd; |
| import org.apache.cloudstack.api.command.user.vpn.ListVpnCustomerGatewaysCmd; |
| import org.apache.cloudstack.api.command.user.vpn.ListVpnGatewaysCmd; |
| import org.apache.cloudstack.api.command.user.vpn.ResetVpnConnectionCmd; |
| import org.apache.cloudstack.api.command.user.vpn.UpdateVpnCustomerGatewayCmd; |
| import org.apache.cloudstack.context.CallContext; |
| import org.apache.cloudstack.framework.config.dao.ConfigurationDao; |
| |
| import com.cloud.configuration.Config; |
| import com.cloud.event.ActionEvent; |
| import com.cloud.event.EventTypes; |
| import com.cloud.exception.InvalidParameterValueException; |
| import com.cloud.exception.NetworkRuleConflictException; |
| import com.cloud.exception.PermissionDeniedException; |
| import com.cloud.exception.ResourceUnavailableException; |
| import com.cloud.network.Site2SiteCustomerGateway; |
| import com.cloud.network.Site2SiteVpnConnection; |
| import com.cloud.network.Site2SiteVpnConnection.State; |
| import com.cloud.network.Site2SiteVpnGateway; |
| import com.cloud.network.dao.IPAddressDao; |
| import com.cloud.network.dao.IPAddressVO; |
| import com.cloud.network.dao.Site2SiteCustomerGatewayDao; |
| import com.cloud.network.dao.Site2SiteCustomerGatewayVO; |
| import com.cloud.network.dao.Site2SiteVpnConnectionDao; |
| import com.cloud.network.dao.Site2SiteVpnConnectionVO; |
| import com.cloud.network.dao.Site2SiteVpnGatewayDao; |
| import com.cloud.network.dao.Site2SiteVpnGatewayVO; |
| import com.cloud.network.element.Site2SiteVpnServiceProvider; |
| import com.cloud.network.vpc.VpcManager; |
| import com.cloud.network.vpc.VpcVO; |
| import com.cloud.network.vpc.dao.VpcDao; |
| import com.cloud.projects.Project.ListProjectResourcesCriteria; |
| import com.cloud.user.Account; |
| import com.cloud.user.AccountManager; |
| import com.cloud.user.dao.AccountDao; |
| import com.cloud.utils.NumbersUtil; |
| import com.cloud.utils.Pair; |
| import com.cloud.utils.Ternary; |
| import com.cloud.utils.component.ManagerBase; |
| import com.cloud.utils.db.DB; |
| import com.cloud.utils.db.Filter; |
| import com.cloud.utils.db.JoinBuilder; |
| import com.cloud.utils.db.SearchBuilder; |
| import com.cloud.utils.db.SearchCriteria; |
| import com.cloud.utils.exception.CloudRuntimeException; |
| import com.cloud.utils.net.NetUtils; |
| import com.cloud.vm.DomainRouterVO; |
| |
| @Component |
| public class Site2SiteVpnManagerImpl extends ManagerBase implements Site2SiteVpnManager { |
| private static final Logger s_logger = Logger.getLogger(Site2SiteVpnManagerImpl.class); |
| |
| List<Site2SiteVpnServiceProvider> _s2sProviders; |
| @Inject |
| Site2SiteCustomerGatewayDao _customerGatewayDao; |
| @Inject |
| Site2SiteVpnGatewayDao _vpnGatewayDao; |
| @Inject |
| Site2SiteVpnConnectionDao _vpnConnectionDao; |
| @Inject |
| VpcDao _vpcDao; |
| @Inject |
| IPAddressDao _ipAddressDao; |
| @Inject |
| AccountDao _accountDao; |
| @Inject |
| ConfigurationDao _configDao; |
| @Inject |
| VpcManager _vpcMgr; |
| @Inject |
| AccountManager _accountMgr; |
| @Inject |
| private AnnotationDao annotationDao; |
| |
| String _name; |
| int _connLimit; |
| int _subnetsLimit; |
| |
| @Override |
| public boolean configure(String name, Map<String, Object> params) throws ConfigurationException { |
| Map<String, String> configs = _configDao.getConfiguration(params); |
| _connLimit = NumbersUtil.parseInt(configs.get(Config.Site2SiteVpnConnectionPerVpnGatewayLimit.key()), 4); |
| _subnetsLimit = NumbersUtil.parseInt(configs.get(Config.Site2SiteVpnSubnetsPerCustomerGatewayLimit.key()), 10); |
| assert (_s2sProviders.iterator().hasNext()) : "Did not get injected with a list of S2S providers!"; |
| return true; |
| } |
| |
| @Override |
| @ActionEvent(eventType = EventTypes.EVENT_S2S_VPN_GATEWAY_CREATE, eventDescription = "creating s2s vpn gateway", async = true) |
| public Site2SiteVpnGateway createVpnGateway(CreateVpnGatewayCmd cmd) { |
| Account caller = CallContext.current().getCallingAccount(); |
| Account owner = _accountMgr.getAccount(cmd.getEntityOwnerId()); |
| |
| //Verify that caller can perform actions in behalf of vpc owner |
| _accountMgr.checkAccess(caller, null, false, owner); |
| |
| Long vpcId = cmd.getVpcId(); |
| VpcVO vpc = _vpcDao.findById(vpcId); |
| if (vpc == null) { |
| throw new InvalidParameterValueException("Invalid VPC " + vpcId + " for site to site vpn gateway creation!"); |
| } |
| Site2SiteVpnGatewayVO gws = _vpnGatewayDao.findByVpcId(vpcId); |
| if (gws != null) { |
| throw new InvalidParameterValueException("The VPN gateway of VPC " + vpcId + " already existed!"); |
| } |
| //Use source NAT ip for VPC |
| List<IPAddressVO> ips = _ipAddressDao.listByAssociatedVpc(vpcId, true); |
| if (ips.size() != 1) { |
| throw new CloudRuntimeException("Cannot found source nat ip of vpc " + vpcId); |
| } |
| |
| Site2SiteVpnGatewayVO gw = new Site2SiteVpnGatewayVO(owner.getAccountId(), owner.getDomainId(), ips.get(0).getId(), vpcId); |
| |
| if (cmd.getDisplay() != null) { |
| gw.setDisplay(cmd.getDisplay()); |
| } |
| |
| _vpnGatewayDao.persist(gw); |
| return gw; |
| } |
| |
| protected void checkCustomerGatewayCidrList(String guestCidrList) { |
| String[] cidrList = guestCidrList.split(","); |
| if (cidrList.length > _subnetsLimit) { |
| throw new InvalidParameterValueException("Too many subnets of customer gateway! The limit is " + _subnetsLimit); |
| } |
| // Remote sub nets cannot overlap themselves |
| for (int i = 0; i < cidrList.length - 1; i++) { |
| for (int j = i + 1; j < cidrList.length; j++) { |
| if (NetUtils.isNetworksOverlap(cidrList[i], cidrList[j])) { |
| throw new InvalidParameterValueException("The subnet of customer gateway " + cidrList[i] + " is overlapped with another subnet " + cidrList[j] + |
| " of customer gateway!"); |
| } |
| } |
| } |
| } |
| |
| @Override |
| @ActionEvent(eventType = EventTypes.EVENT_S2S_VPN_CUSTOMER_GATEWAY_CREATE, eventDescription = "creating s2s customer gateway", create = true) |
| public Site2SiteCustomerGateway createCustomerGateway(CreateVpnCustomerGatewayCmd cmd) { |
| Account caller = CallContext.current().getCallingAccount(); |
| Account owner = _accountMgr.getAccount(cmd.getEntityOwnerId()); |
| |
| //Verify that caller can perform actions in behalf of vpc owner |
| _accountMgr.checkAccess(caller, null, false, owner); |
| |
| String name = cmd.getName(); |
| String gatewayIp = cmd.getGatewayIp(); |
| |
| if (!NetUtils.isValidIp4(gatewayIp) && !NetUtils.verifyDomainName(gatewayIp)) { |
| throw new InvalidParameterValueException("The customer gateway ip/Domain " + gatewayIp + " is invalid!"); |
| } |
| if (name == null) { |
| name = "VPN-" + gatewayIp; |
| } |
| String peerCidrList = cmd.getGuestCidrList(); |
| if (!NetUtils.isValidCidrList(peerCidrList)) { |
| throw new InvalidParameterValueException("The customer gateway peer cidr list " + peerCidrList + " contains an invalid cidr!"); |
| } |
| String ipsecPsk = cmd.getIpsecPsk(); |
| String ikePolicy = cmd.getIkePolicy(); |
| String espPolicy = cmd.getEspPolicy(); |
| if (!NetUtils.isValidS2SVpnPolicy("ike", ikePolicy)) { |
| throw new InvalidParameterValueException("The customer gateway IKE policy " + ikePolicy + " is invalid! Verify the required Diffie Hellman (DH) group is specified."); |
| } |
| if (!NetUtils.isValidS2SVpnPolicy("esp", espPolicy)) { |
| throw new InvalidParameterValueException("The customer gateway ESP policy " + espPolicy + " is invalid!"); |
| } |
| Long ikeLifetime = cmd.getIkeLifetime(); |
| if (ikeLifetime == null) { |
| // Default value of lifetime is 1 day |
| ikeLifetime = (long)86400; |
| } |
| if (ikeLifetime > 86400) { |
| throw new InvalidParameterValueException("The IKE lifetime " + ikeLifetime + " of vpn connection is invalid!"); |
| } |
| Long espLifetime = cmd.getEspLifetime(); |
| if (espLifetime == null) { |
| // Default value of lifetime is 1 hour |
| espLifetime = (long)3600; |
| } |
| if (espLifetime > 86400) { |
| throw new InvalidParameterValueException("The ESP lifetime " + espLifetime + " of vpn connection is invalid!"); |
| } |
| |
| Boolean dpd = cmd.getDpd(); |
| if (dpd == null) { |
| dpd = false; |
| } |
| |
| Boolean encap = cmd.getEncap(); |
| if (encap == null) { |
| encap = false; |
| } |
| |
| long accountId = owner.getAccountId(); |
| if (_customerGatewayDao.findByNameAndAccountId(name, accountId) != null) { |
| throw new InvalidParameterValueException("The customer gateway with name " + name + " already existed!"); |
| } |
| |
| Boolean splitConnections = cmd.getSplitConnections(); |
| if (splitConnections == null) { |
| splitConnections = false; |
| } |
| |
| String ikeVersion = cmd.getIkeVersion(); |
| if (ikeVersion == null) { |
| ikeVersion = "ike"; |
| } |
| |
| checkCustomerGatewayCidrList(peerCidrList); |
| |
| Site2SiteCustomerGatewayVO gw = |
| new Site2SiteCustomerGatewayVO(name, accountId, owner.getDomainId(), gatewayIp, peerCidrList, ipsecPsk, ikePolicy, espPolicy, ikeLifetime, espLifetime, dpd, encap, splitConnections, ikeVersion); |
| gw = _customerGatewayDao.persist(gw); |
| CallContext.current().putContextParameter(Site2SiteCustomerGateway.class, gw.getUuid()); |
| return gw; |
| } |
| |
| @Override |
| @ActionEvent(eventType = EventTypes.EVENT_S2S_VPN_CONNECTION_CREATE, eventDescription = "creating s2s vpn connection", create = true) |
| public Site2SiteVpnConnection createVpnConnection(CreateVpnConnectionCmd cmd) throws NetworkRuleConflictException { |
| Account caller = CallContext.current().getCallingAccount(); |
| Account owner = _accountMgr.getAccount(cmd.getEntityOwnerId()); |
| |
| //Verify that caller can perform actions in behalf of vpc owner |
| _accountMgr.checkAccess(caller, null, false, owner); |
| |
| Long customerGatewayId = cmd.getCustomerGatewayId(); |
| Site2SiteCustomerGateway customerGateway = _customerGatewayDao.findById(customerGatewayId); |
| if (customerGateway == null) { |
| throw new InvalidParameterValueException("Unable to found specified Site to Site VPN customer gateway " + customerGatewayId + " !"); |
| } |
| _accountMgr.checkAccess(caller, null, false, customerGateway); |
| |
| Long vpnGatewayId = cmd.getVpnGatewayId(); |
| Site2SiteVpnGateway vpnGateway = _vpnGatewayDao.findById(vpnGatewayId); |
| if (vpnGateway == null) { |
| throw new InvalidParameterValueException("Unable to found specified Site to Site VPN gateway " + vpnGatewayId + " !"); |
| } |
| _accountMgr.checkAccess(caller, null, false, vpnGateway); |
| |
| if (customerGateway.getAccountId() != vpnGateway.getAccountId() || customerGateway.getDomainId() != vpnGateway.getDomainId()) { |
| throw new InvalidParameterValueException("VPN connection can only be esitablished between same account's VPN gateway and customer gateway!"); |
| } |
| |
| if (_vpnConnectionDao.findByVpnGatewayIdAndCustomerGatewayId(vpnGatewayId, customerGatewayId) != null) { |
| throw new InvalidParameterValueException("The vpn connection with customer gateway id " + customerGatewayId + " and vpn gateway id " + vpnGatewayId + |
| " already existed!"); |
| } |
| String[] cidrList = customerGateway.getGuestCidrList().split(","); |
| |
| // Remote sub nets cannot overlap VPC's sub net |
| String vpcCidr = _vpcDao.findById(vpnGateway.getVpcId()).getCidr(); |
| for (String cidr : cidrList) { |
| if (NetUtils.isNetworksOverlap(vpcCidr, cidr)) { |
| throw new InvalidParameterValueException("The subnets of customer gateway " + customerGatewayId + "'s subnet " + cidr + " is overlapped with VPC cidr " + |
| vpcCidr + "!"); |
| } |
| } |
| |
| // We also need to check if the new connection's remote CIDR is overlapped with existed connections |
| List<Site2SiteVpnConnectionVO> conns = _vpnConnectionDao.listByVpnGatewayId(vpnGatewayId); |
| if (conns.size() >= _connLimit) { |
| throw new InvalidParameterValueException("There are too many VPN connections with current VPN gateway! The limit is " + _connLimit); |
| } |
| for (Site2SiteVpnConnectionVO vc : conns) { |
| if (vc == null) { |
| continue; |
| } |
| Site2SiteCustomerGatewayVO gw = _customerGatewayDao.findById(vc.getCustomerGatewayId()); |
| String[] oldCidrList = gw.getGuestCidrList().split(","); |
| for (String oldCidr : oldCidrList) { |
| for (String cidr : cidrList) { |
| if (NetUtils.isNetworksOverlap(cidr, oldCidr)) { |
| throw new InvalidParameterValueException("The new connection's remote subnet " + cidr + |
| " is overlapped with existed VPN connection to customer gateway " + gw.getName() + "'s subnet " + oldCidr); |
| } |
| } |
| } |
| } |
| |
| Site2SiteVpnConnectionVO conn = new Site2SiteVpnConnectionVO(owner.getAccountId(), owner.getDomainId(), vpnGatewayId, customerGatewayId, cmd.isPassive()); |
| conn.setState(State.Pending); |
| if (cmd.getDisplay() != null) { |
| conn.setDisplay(cmd.getDisplay()); |
| } |
| |
| _vpnConnectionDao.persist(conn); |
| return conn; |
| } |
| |
| @Override |
| @DB |
| @ActionEvent(eventType = EventTypes.EVENT_S2S_VPN_CONNECTION_CREATE, eventDescription = "starting s2s vpn connection", async = true) |
| public Site2SiteVpnConnection startVpnConnection(long id) throws ResourceUnavailableException { |
| Site2SiteVpnConnectionVO conn = _vpnConnectionDao.acquireInLockTable(id); |
| if (conn == null) { |
| throw new CloudRuntimeException("Unable to acquire lock on " + conn); |
| } |
| try { |
| if (conn.getState() != State.Pending && conn.getState() != State.Disconnected) { |
| throw new InvalidParameterValueException( |
| "Site to site VPN connection with specified connectionId not in correct state(pending or disconnected) to process!"); |
| } |
| |
| conn.setState(State.Pending); |
| _vpnConnectionDao.persist(conn); |
| |
| boolean result = true; |
| for (Site2SiteVpnServiceProvider element : _s2sProviders) { |
| result = result & element.startSite2SiteVpn(conn); |
| } |
| |
| if (result) { |
| if (conn.isPassive()) { |
| conn.setState(State.Disconnected); |
| } else { |
| conn.setState(State.Connecting); |
| } |
| _vpnConnectionDao.persist(conn); |
| return conn; |
| } |
| conn.setState(State.Error); |
| _vpnConnectionDao.persist(conn); |
| throw new ResourceUnavailableException("Failed to apply site-to-site VPN", Site2SiteVpnConnection.class, id); |
| } finally { |
| _vpnConnectionDao.releaseFromLockTable(conn.getId()); |
| } |
| } |
| |
| @Override |
| public Site2SiteVpnGateway getVpnGateway(Long vpnGatewayId) { |
| return _vpnGatewayDao.findById(vpnGatewayId); |
| } |
| |
| @Override |
| public Site2SiteCustomerGateway getCustomerGateway(Long customerGatewayId) { |
| return _customerGatewayDao.findById(customerGatewayId); |
| } |
| |
| @Override |
| @ActionEvent(eventType = EventTypes.EVENT_S2S_VPN_CUSTOMER_GATEWAY_DELETE, eventDescription = "deleting s2s vpn customer gateway", create = true) |
| public boolean deleteCustomerGateway(DeleteVpnCustomerGatewayCmd cmd) { |
| CallContext.current().setEventDetails(" Id: " + cmd.getId()); |
| Account caller = CallContext.current().getCallingAccount(); |
| |
| Long id = cmd.getId(); |
| Site2SiteCustomerGateway customerGateway = _customerGatewayDao.findById(id); |
| if (customerGateway == null) { |
| throw new InvalidParameterValueException("Fail to find customer gateway with " + id + " !"); |
| } |
| _accountMgr.checkAccess(caller, null, false, customerGateway); |
| |
| return doDeleteCustomerGateway(customerGateway); |
| } |
| |
| protected boolean doDeleteCustomerGateway(Site2SiteCustomerGateway gw) { |
| long id = gw.getId(); |
| List<Site2SiteVpnConnectionVO> vpnConnections = _vpnConnectionDao.listByCustomerGatewayId(id); |
| if (vpnConnections != null && vpnConnections.size() != 0) { |
| throw new InvalidParameterValueException("Unable to delete VPN customer gateway with id " + id + " because there is still related VPN connections!"); |
| } |
| annotationDao.removeByEntityType(AnnotationService.EntityType.VPN_CUSTOMER_GATEWAY.name(), gw.getUuid()); |
| _customerGatewayDao.remove(id); |
| return true; |
| } |
| |
| protected void doDeleteVpnGateway(Site2SiteVpnGateway gw) { |
| List<Site2SiteVpnConnectionVO> conns = _vpnConnectionDao.listByVpnGatewayId(gw.getId()); |
| if (conns != null && conns.size() != 0) { |
| throw new InvalidParameterValueException("Unable to delete VPN gateway " + gw.getId() + " because there is still related VPN connections!"); |
| } |
| _vpnGatewayDao.remove(gw.getId()); |
| } |
| |
| @Override |
| @ActionEvent(eventType = EventTypes.EVENT_S2S_VPN_GATEWAY_DELETE, eventDescription = "deleting s2s vpn gateway", async = true) |
| public boolean deleteVpnGateway(DeleteVpnGatewayCmd cmd) { |
| CallContext.current().setEventDetails(" Id: " + cmd.getId()); |
| Account caller = CallContext.current().getCallingAccount(); |
| |
| Long id = cmd.getId(); |
| Site2SiteVpnGateway vpnGateway = _vpnGatewayDao.findById(id); |
| if (vpnGateway == null) { |
| throw new InvalidParameterValueException("Fail to find vpn gateway with " + id + " !"); |
| } |
| |
| _accountMgr.checkAccess(caller, null, false, vpnGateway); |
| |
| doDeleteVpnGateway(vpnGateway); |
| return true; |
| } |
| |
| @Override |
| @ActionEvent(eventType = EventTypes.EVENT_S2S_VPN_CUSTOMER_GATEWAY_UPDATE, eventDescription = "update s2s vpn customer gateway", create = true) |
| public Site2SiteCustomerGateway updateCustomerGateway(UpdateVpnCustomerGatewayCmd cmd) { |
| CallContext.current().setEventDetails(" Id: " + cmd.getId()); |
| Account caller = CallContext.current().getCallingAccount(); |
| |
| Long id = cmd.getId(); |
| Site2SiteCustomerGatewayVO gw = _customerGatewayDao.findById(id); |
| if (gw == null) { |
| throw new InvalidParameterValueException("Find to find customer gateway with id " + id); |
| } |
| _accountMgr.checkAccess(caller, null, false, gw); |
| |
| String name = cmd.getName(); |
| String gatewayIp = cmd.getGatewayIp(); |
| |
| if (!NetUtils.isValidIp4(gatewayIp) && !NetUtils.verifyDomainName(gatewayIp)) { |
| throw new InvalidParameterValueException("The customer gateway ip/Domain " + gatewayIp + " is invalid!"); |
| } |
| if (name == null) { |
| name = "VPN-" + gatewayIp; |
| } |
| String guestCidrList = cmd.getGuestCidrList(); |
| if (!NetUtils.isValidCidrList(guestCidrList)) { |
| throw new InvalidParameterValueException("The customer gateway peer cidr list " + guestCidrList + " contains an invalid cidr!"); |
| } |
| String ipsecPsk = cmd.getIpsecPsk(); |
| String ikePolicy = cmd.getIkePolicy(); |
| String espPolicy = cmd.getEspPolicy(); |
| if (!NetUtils.isValidS2SVpnPolicy("ike", ikePolicy)) { |
| throw new InvalidParameterValueException("The customer gateway IKE policy" + ikePolicy + " is invalid! Verify the required Diffie Hellman (DH) group is specified."); |
| } |
| if (!NetUtils.isValidS2SVpnPolicy("esp", espPolicy)) { |
| throw new InvalidParameterValueException("The customer gateway ESP policy" + espPolicy + " is invalid!"); |
| } |
| Long ikeLifetime = cmd.getIkeLifetime(); |
| if (ikeLifetime == null) { |
| // Default value of lifetime is 1 day |
| ikeLifetime = (long)86400; |
| } |
| if (ikeLifetime > 86400) { |
| throw new InvalidParameterValueException("The IKE lifetime " + ikeLifetime + " of vpn connection is invalid!"); |
| } |
| Long espLifetime = cmd.getEspLifetime(); |
| if (espLifetime == null) { |
| // Default value of lifetime is 1 hour |
| espLifetime = (long)3600; |
| } |
| if (espLifetime > 86400) { |
| throw new InvalidParameterValueException("The ESP lifetime " + espLifetime + " of vpn connection is invalid!"); |
| } |
| |
| Boolean dpd = cmd.getDpd(); |
| if (dpd == null) { |
| dpd = false; |
| } |
| |
| Boolean encap = cmd.getEncap(); |
| if (encap == null) { |
| encap = false; |
| } |
| |
| Boolean splitConnections = cmd.getSplitConnections(); |
| |
| String ikeVersion = cmd.getIkeVersion(); |
| |
| checkCustomerGatewayCidrList(guestCidrList); |
| |
| long accountId = gw.getAccountId(); |
| Site2SiteCustomerGatewayVO existedGw = _customerGatewayDao.findByNameAndAccountId(name, accountId); |
| if (existedGw != null && existedGw.getId() != gw.getId()) { |
| throw new InvalidParameterValueException("The customer gateway with name " + name + " already existed!"); |
| } |
| |
| gw.setName(name); |
| gw.setGatewayIp(gatewayIp); |
| gw.setGuestCidrList(guestCidrList); |
| gw.setIkePolicy(ikePolicy); |
| gw.setEspPolicy(espPolicy); |
| gw.setIpsecPsk(ipsecPsk); |
| gw.setIkeLifetime(ikeLifetime); |
| gw.setEspLifetime(espLifetime); |
| gw.setDpd(dpd); |
| gw.setEncap(encap); |
| gw.setSplitConnections(splitConnections); |
| if (ikeVersion != null) { |
| gw.setIkeVersion(ikeVersion); |
| } |
| _customerGatewayDao.persist(gw); |
| |
| setupVpnConnection(caller, id); |
| |
| return gw; |
| } |
| |
| private void setupVpnConnection(Account caller, Long vpnCustomerGwIp) { |
| List<Site2SiteVpnConnectionVO> conns = _vpnConnectionDao.listByCustomerGatewayId(vpnCustomerGwIp); |
| if (conns != null) { |
| for (Site2SiteVpnConnection conn : conns) { |
| try { |
| _accountMgr.checkAccess(caller, null, false, conn); |
| } catch (PermissionDeniedException e) { |
| // Just don't restart this connection, as the user has no rights to it |
| // Maybe should issue a notification to the system? |
| s_logger.info("Site2SiteVpnManager:updateCustomerGateway() Not resetting VPN connection " + conn.getId() + " as user lacks permission"); |
| continue; |
| } |
| |
| if (conn.getState() == State.Pending) { |
| // Vpn connection cannot be reset when the state is Pending |
| continue; |
| } |
| try { |
| if (conn.getState() == State.Connected || conn.getState() == State.Connecting || conn.getState() == State.Error) { |
| stopVpnConnection(conn.getId()); |
| } |
| startVpnConnection(conn.getId()); |
| } catch (ResourceUnavailableException e) { |
| // Should never get here, as we are looping on the actual connections, but we must handle it regardless |
| s_logger.warn("Failed to update VPN connection"); |
| } |
| } |
| } |
| } |
| |
| @Override |
| @ActionEvent(eventType = EventTypes.EVENT_S2S_VPN_CONNECTION_DELETE, eventDescription = "deleting s2s vpn connection", create = true) |
| public boolean deleteVpnConnection(DeleteVpnConnectionCmd cmd) throws ResourceUnavailableException { |
| CallContext.current().setEventDetails(" Id: " + cmd.getId()); |
| Account caller = CallContext.current().getCallingAccount(); |
| |
| Long id = cmd.getId(); |
| Site2SiteVpnConnectionVO conn = _vpnConnectionDao.findById(id); |
| if (conn == null) { |
| throw new InvalidParameterValueException("Fail to find site to site VPN connection " + id + " to delete!"); |
| } |
| |
| _accountMgr.checkAccess(caller, null, false, conn); |
| |
| if (conn.getState() != State.Pending) { |
| stopVpnConnection(id); |
| } |
| _vpnConnectionDao.remove(id); |
| return true; |
| } |
| |
| @DB |
| private void stopVpnConnection(Long id) throws ResourceUnavailableException { |
| Site2SiteVpnConnectionVO conn = _vpnConnectionDao.acquireInLockTable(id); |
| if (conn == null) { |
| throw new CloudRuntimeException("Unable to acquire lock on " + conn); |
| } |
| try { |
| if (conn.getState() == State.Pending) { |
| throw new InvalidParameterValueException("Site to site VPN connection with specified id is currently Pending, unable to Disconnect!"); |
| } |
| |
| conn.setState(State.Disconnected); |
| _vpnConnectionDao.persist(conn); |
| |
| boolean result = true; |
| for (Site2SiteVpnServiceProvider element : _s2sProviders) { |
| result = result & element.stopSite2SiteVpn(conn); |
| } |
| |
| if (!result) { |
| conn.setState(State.Error); |
| _vpnConnectionDao.persist(conn); |
| throw new ResourceUnavailableException("Failed to apply site-to-site VPN", Site2SiteVpnConnection.class, id); |
| } |
| } finally { |
| _vpnConnectionDao.releaseFromLockTable(conn.getId()); |
| } |
| } |
| |
| @Override |
| @ActionEvent(eventType = EventTypes.EVENT_S2S_VPN_CONNECTION_RESET, eventDescription = "reseting s2s vpn connection", create = true) |
| public Site2SiteVpnConnection resetVpnConnection(ResetVpnConnectionCmd cmd) throws ResourceUnavailableException { |
| CallContext.current().setEventDetails(" Id: " + cmd.getId()); |
| Account caller = CallContext.current().getCallingAccount(); |
| |
| Long id = cmd.getId(); |
| Site2SiteVpnConnectionVO conn = _vpnConnectionDao.findById(id); |
| if (conn == null) { |
| throw new InvalidParameterValueException("Fail to find site to site VPN connection " + id + " to reset!"); |
| } |
| _accountMgr.checkAccess(caller, null, false, conn); |
| |
| // Set vpn state to disconnected |
| conn.setState(State.Disconnected); |
| _vpnConnectionDao.persist(conn); |
| |
| // Stop and start the connection again |
| stopVpnConnection(id); |
| startVpnConnection(id); |
| conn = _vpnConnectionDao.findById(id); |
| return conn; |
| } |
| |
| @Override |
| public Pair<List<? extends Site2SiteCustomerGateway>, Integer> searchForCustomerGateways(ListVpnCustomerGatewaysCmd cmd) { |
| Long id = cmd.getId(); |
| Long domainId = cmd.getDomainId(); |
| boolean isRecursive = cmd.isRecursive(); |
| String accountName = cmd.getAccountName(); |
| boolean listAll = cmd.listAll(); |
| long startIndex = cmd.getStartIndex(); |
| long pageSizeVal = cmd.getPageSizeVal(); |
| String keyword = cmd.getKeyword(); |
| |
| Account caller = CallContext.current().getCallingAccount(); |
| List<Long> permittedAccounts = new ArrayList<Long>(); |
| |
| Ternary<Long, Boolean, ListProjectResourcesCriteria> domainIdRecursiveListProject = new Ternary<Long, Boolean, |
| ListProjectResourcesCriteria>(domainId, isRecursive, null); |
| _accountMgr.buildACLSearchParameters(caller, id, accountName, cmd.getProjectId(), permittedAccounts, domainIdRecursiveListProject, listAll, false); |
| domainId = domainIdRecursiveListProject.first(); |
| isRecursive = domainIdRecursiveListProject.second(); |
| ListProjectResourcesCriteria listProjectResourcesCriteria = domainIdRecursiveListProject.third(); |
| Filter searchFilter = new Filter(Site2SiteCustomerGatewayVO.class, "id", false, startIndex, pageSizeVal); |
| |
| SearchBuilder<Site2SiteCustomerGatewayVO> sb = _customerGatewayDao.createSearchBuilder(); |
| _accountMgr.buildACLSearchBuilder(sb, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria); |
| |
| sb.and("id", sb.entity().getId(), SearchCriteria.Op.EQ); |
| sb.and("name", sb.entity().getName(), SearchCriteria.Op.LIKE); |
| |
| SearchCriteria<Site2SiteCustomerGatewayVO> sc = sb.create(); |
| _accountMgr.buildACLSearchCriteria(sc, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria); |
| |
| if (id != null) { |
| sc.setParameters("id", id); |
| } |
| if(keyword != null && !keyword.isEmpty()) |
| { |
| sc.setParameters("name", "%" + keyword + "%"); |
| } |
| |
| Pair<List<Site2SiteCustomerGatewayVO>, Integer> result = _customerGatewayDao.searchAndCount(sc, searchFilter); |
| return new Pair<List<? extends Site2SiteCustomerGateway>, Integer>(result.first(), result.second()); |
| } |
| |
| @Override |
| public Pair<List<? extends Site2SiteVpnGateway>, Integer> searchForVpnGateways(ListVpnGatewaysCmd cmd) { |
| Long id = cmd.getId(); |
| Long vpcId = cmd.getVpcId(); |
| Boolean display = cmd.getDisplay(); |
| |
| Long domainId = cmd.getDomainId(); |
| boolean isRecursive = cmd.isRecursive(); |
| String accountName = cmd.getAccountName(); |
| boolean listAll = cmd.listAll(); |
| long startIndex = cmd.getStartIndex(); |
| long pageSizeVal = cmd.getPageSizeVal(); |
| |
| Account caller = CallContext.current().getCallingAccount(); |
| List<Long> permittedAccounts = new ArrayList<Long>(); |
| |
| Ternary<Long, Boolean, ListProjectResourcesCriteria> domainIdRecursiveListProject = new Ternary<Long, Boolean, |
| ListProjectResourcesCriteria>(domainId, isRecursive, null); |
| _accountMgr.buildACLSearchParameters(caller, id, accountName, cmd.getProjectId(), permittedAccounts, domainIdRecursiveListProject, listAll, false); |
| domainId = domainIdRecursiveListProject.first(); |
| isRecursive = domainIdRecursiveListProject.second(); |
| ListProjectResourcesCriteria listProjectResourcesCriteria = domainIdRecursiveListProject.third(); |
| Filter searchFilter = new Filter(Site2SiteVpnGatewayVO.class, "id", false, startIndex, pageSizeVal); |
| |
| SearchBuilder<Site2SiteVpnGatewayVO> sb = _vpnGatewayDao.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("display", sb.entity().isDisplay(), SearchCriteria.Op.EQ); |
| |
| SearchCriteria<Site2SiteVpnGatewayVO> sc = sb.create(); |
| _accountMgr.buildACLSearchCriteria(sc, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria); |
| |
| if (id != null) { |
| sc.addAnd("id", SearchCriteria.Op.EQ, id); |
| } |
| |
| if (display != null) { |
| sc.setParameters("display", display); |
| } |
| |
| if (vpcId != null) { |
| sc.addAnd("vpcId", SearchCriteria.Op.EQ, vpcId); |
| } |
| |
| Pair<List<Site2SiteVpnGatewayVO>, Integer> result = _vpnGatewayDao.searchAndCount(sc, searchFilter); |
| return new Pair<List<? extends Site2SiteVpnGateway>, Integer>(result.first(), result.second()); |
| } |
| |
| @Override |
| public Pair<List<? extends Site2SiteVpnConnection>, Integer> searchForVpnConnections(ListVpnConnectionsCmd cmd) { |
| Long id = cmd.getId(); |
| Long vpcId = cmd.getVpcId(); |
| Boolean display = cmd.getDisplay(); |
| |
| Long domainId = cmd.getDomainId(); |
| boolean isRecursive = cmd.isRecursive(); |
| String accountName = cmd.getAccountName(); |
| boolean listAll = cmd.listAll(); |
| long startIndex = cmd.getStartIndex(); |
| long pageSizeVal = cmd.getPageSizeVal(); |
| |
| Account caller = CallContext.current().getCallingAccount(); |
| List<Long> permittedAccounts = new ArrayList<Long>(); |
| |
| Ternary<Long, Boolean, ListProjectResourcesCriteria> domainIdRecursiveListProject = new Ternary<Long, Boolean, |
| ListProjectResourcesCriteria>(domainId, isRecursive, null); |
| _accountMgr.buildACLSearchParameters(caller, id, accountName, cmd.getProjectId(), permittedAccounts, domainIdRecursiveListProject, listAll, false); |
| domainId = domainIdRecursiveListProject.first(); |
| isRecursive = domainIdRecursiveListProject.second(); |
| ListProjectResourcesCriteria listProjectResourcesCriteria = domainIdRecursiveListProject.third(); |
| Filter searchFilter = new Filter(Site2SiteVpnConnectionVO.class, "id", false, startIndex, pageSizeVal); |
| |
| SearchBuilder<Site2SiteVpnConnectionVO> sb = _vpnConnectionDao.createSearchBuilder(); |
| _accountMgr.buildACLSearchBuilder(sb, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria); |
| |
| sb.and("id", sb.entity().getId(), SearchCriteria.Op.EQ); |
| sb.and("display", sb.entity().isDisplay(), SearchCriteria.Op.EQ); |
| |
| if (vpcId != null) { |
| SearchBuilder<Site2SiteVpnGatewayVO> gwSearch = _vpnGatewayDao.createSearchBuilder(); |
| gwSearch.and("vpcId", gwSearch.entity().getVpcId(), SearchCriteria.Op.EQ); |
| sb.join("gwSearch", gwSearch, sb.entity().getVpnGatewayId(), gwSearch.entity().getId(), JoinBuilder.JoinType.INNER); |
| } |
| |
| SearchCriteria<Site2SiteVpnConnectionVO> sc = sb.create(); |
| _accountMgr.buildACLSearchCriteria(sc, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria); |
| |
| if (display != null) { |
| sc.setParameters("display", display); |
| } |
| if (id != null) { |
| sc.addAnd("id", SearchCriteria.Op.EQ, id); |
| } |
| |
| if (vpcId != null) { |
| sc.setJoinParameters("gwSearch", "vpcId", vpcId); |
| } |
| |
| Pair<List<Site2SiteVpnConnectionVO>, Integer> result = _vpnConnectionDao.searchAndCount(sc, searchFilter); |
| return new Pair<List<? extends Site2SiteVpnConnection>, Integer>(result.first(), result.second()); |
| } |
| |
| @Override |
| public boolean cleanupVpnConnectionByVpc(long vpcId) { |
| List<Site2SiteVpnConnectionVO> conns = _vpnConnectionDao.listByVpcId(vpcId); |
| for (Site2SiteVpnConnection conn : conns) { |
| _vpnConnectionDao.remove(conn.getId()); |
| } |
| return true; |
| } |
| |
| @Override |
| public boolean cleanupVpnGatewayByVpc(long vpcId) { |
| Site2SiteVpnGatewayVO gw = _vpnGatewayDao.findByVpcId(vpcId); |
| if (gw == null) { |
| return true; |
| } |
| doDeleteVpnGateway(gw); |
| return true; |
| } |
| |
| @Override |
| @DB |
| public void markDisconnectVpnConnByVpc(long vpcId) { |
| List<Site2SiteVpnConnectionVO> conns = _vpnConnectionDao.listByVpcId(vpcId); |
| for (Site2SiteVpnConnectionVO conn : conns) { |
| if (conn == null) { |
| continue; |
| } |
| Site2SiteVpnConnectionVO lock = _vpnConnectionDao.acquireInLockTable(conn.getId()); |
| if (lock == null) { |
| throw new CloudRuntimeException("Unable to acquire lock on " + conn); |
| } |
| try { |
| if (conn.getState() == Site2SiteVpnConnection.State.Connected || conn.getState() == Site2SiteVpnConnection.State.Connecting) { |
| conn.setState(Site2SiteVpnConnection.State.Disconnected); |
| _vpnConnectionDao.persist(conn); |
| } |
| } finally { |
| _vpnConnectionDao.releaseFromLockTable(lock.getId()); |
| } |
| } |
| } |
| |
| @Override |
| public List<Site2SiteVpnConnectionVO> getConnectionsForRouter(DomainRouterVO router) { |
| List<Site2SiteVpnConnectionVO> conns = new ArrayList<Site2SiteVpnConnectionVO>(); |
| // One router for one VPC |
| Long vpcId = router.getVpcId(); |
| if (router.getVpcId() == null) { |
| return conns; |
| } |
| conns.addAll(_vpnConnectionDao.listByVpcId(vpcId)); |
| return conns; |
| } |
| |
| @Override |
| public boolean deleteCustomerGatewayByAccount(long accountId) { |
| boolean result = true; |
| ; |
| List<Site2SiteCustomerGatewayVO> gws = _customerGatewayDao.listByAccountId(accountId); |
| for (Site2SiteCustomerGatewayVO gw : gws) { |
| result = result & doDeleteCustomerGateway(gw); |
| } |
| return result; |
| } |
| |
| @Override |
| public void reconnectDisconnectedVpnByVpc(Long vpcId) { |
| List<Site2SiteVpnConnectionVO> conns = _vpnConnectionDao.listByVpcId(vpcId); |
| for (Site2SiteVpnConnectionVO conn : conns) { |
| if (conn == null) { |
| continue; |
| } |
| if (conn.getState() == Site2SiteVpnConnection.State.Disconnected) { |
| try { |
| startVpnConnection(conn.getId()); |
| } catch (ResourceUnavailableException e) { |
| Site2SiteCustomerGatewayVO gw = _customerGatewayDao.findById(conn.getCustomerGatewayId()); |
| s_logger.warn("Site2SiteVpnManager: Fail to re-initiate VPN connection " + conn.getId() + " which connect to " + gw.getName()); |
| } |
| } |
| } |
| } |
| |
| public List<Site2SiteVpnServiceProvider> getS2sProviders() { |
| return _s2sProviders; |
| } |
| |
| @Inject |
| public void setS2sProviders(List<Site2SiteVpnServiceProvider> s2sProviders) { |
| _s2sProviders = s2sProviders; |
| } |
| |
| @Override |
| @ActionEvent(eventType = EventTypes.EVENT_S2S_VPN_CONNECTION_UPDATE, eventDescription = "creating s2s vpn gateway", async = true) |
| public Site2SiteVpnConnection updateVpnConnection(long id, String customId, Boolean forDisplay) { |
| Account caller = CallContext.current().getCallingAccount(); |
| Site2SiteVpnConnectionVO conn = _vpnConnectionDao.findById(id); |
| if (conn == null) { |
| throw new InvalidParameterValueException("Fail to find site to site VPN connection " + id); |
| } |
| |
| _accountMgr.checkAccess(caller, null, false, conn); |
| if (customId != null) { |
| conn.setUuid(customId); |
| } |
| |
| if (forDisplay != null) { |
| conn.setDisplay(forDisplay); |
| } |
| |
| _vpnConnectionDao.update(id, conn); |
| return _vpnConnectionDao.findById(id); |
| } |
| |
| @Override |
| @ActionEvent(eventType = EventTypes.EVENT_S2S_VPN_GATEWAY_UPDATE, eventDescription = "updating s2s vpn gateway", async = true) |
| public Site2SiteVpnGateway updateVpnGateway(Long id, String customId, Boolean forDisplay) { |
| Account caller = CallContext.current().getCallingAccount(); |
| |
| Site2SiteVpnGatewayVO vpnGateway = _vpnGatewayDao.findById(id); |
| if (vpnGateway == null) { |
| throw new InvalidParameterValueException("Fail to find vpn gateway with " + id); |
| } |
| |
| _accountMgr.checkAccess(caller, null, false, vpnGateway); |
| if (customId != null) { |
| vpnGateway.setUuid(customId); |
| } |
| |
| if (forDisplay != null) { |
| vpnGateway.setDisplay(forDisplay); |
| } |
| |
| _vpnGatewayDao.update(id, vpnGateway); |
| return _vpnGatewayDao.findById(id); |
| |
| } |
| } |