diff --git a/api/src/com/cloud/api/commands/DeleteRemoteAccessVpnCmd.java b/api/src/com/cloud/api/commands/DeleteRemoteAccessVpnCmd.java index 917bf35f90b..15f7860bc5a 100644 --- a/api/src/com/cloud/api/commands/DeleteRemoteAccessVpnCmd.java +++ b/api/src/com/cloud/api/commands/DeleteRemoteAccessVpnCmd.java @@ -20,6 +20,7 @@ package com.cloud.api.commands; import org.apache.log4j.Logger; +import com.cloud.api.ApiConstants; import com.cloud.api.BaseAsyncCmd; import com.cloud.api.Implementation; import com.cloud.api.Parameter; @@ -41,6 +42,9 @@ public class DeleteRemoteAccessVpnCmd extends BaseAsyncCmd { @Parameter(name="publicip", type=CommandType.STRING, required=true, description="public ip address of the vpn server") private String publicIp; + // unexposed parameter needed for events logging + @Parameter(name=ApiConstants.ACCOUNT_ID, type=CommandType.LONG, expose=false) + private Long ownerId; ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -56,8 +60,10 @@ public class DeleteRemoteAccessVpnCmd extends BaseAsyncCmd { @Override public long getEntityOwnerId() { - RemoteAccessVpn vpn = _entityMgr.findById(RemoteAccessVpn.class, new Ip(publicIp)); - return vpn.getAccountId(); + if (ownerId == null) { + ownerId = _entityMgr.findById(RemoteAccessVpn.class, new Ip(publicIp)).getAccountId(); + } + return ownerId; } @Override diff --git a/api/src/com/cloud/api/commands/ListRemoteAccessVpnsCmd.java b/api/src/com/cloud/api/commands/ListRemoteAccessVpnsCmd.java index 388d12a9bc4..3cfb0dc7d17 100644 --- a/api/src/com/cloud/api/commands/ListRemoteAccessVpnsCmd.java +++ b/api/src/com/cloud/api/commands/ListRemoteAccessVpnsCmd.java @@ -80,10 +80,11 @@ public class ListRemoteAccessVpnsCmd extends BaseListCmd { List vpns = _ravService.searchForRemoteAccessVpns(this); ListResponse response = new ListResponse(); List vpnResponses = new ArrayList(); - for (RemoteAccessVpn vpn : vpns) { - vpnResponses.add(_responseGenerator.createRemoteAccessVpnResponse(vpn)); + if (vpns != null && !vpns.isEmpty()) { + for (RemoteAccessVpn vpn : vpns) { + vpnResponses.add(_responseGenerator.createRemoteAccessVpnResponse(vpn)); + } } - response.setResponses(vpnResponses); response.setResponseName(getCommandName()); this.setResponseObject(response); diff --git a/api/src/com/cloud/api/response/RemoteAccessVpnResponse.java b/api/src/com/cloud/api/response/RemoteAccessVpnResponse.java index c56f837cad9..b85cf760105 100644 --- a/api/src/com/cloud/api/response/RemoteAccessVpnResponse.java +++ b/api/src/com/cloud/api/response/RemoteAccessVpnResponse.java @@ -39,6 +39,9 @@ public class RemoteAccessVpnResponse extends BaseResponse { @SerializedName("domainname") @Param(description="the domain name of the account of the remote access vpn") private String domainName; + @SerializedName("state") @Param(description="the state of the rule") + private String state; + public String getAccountName() { return accountName; } @@ -89,5 +92,11 @@ public class RemoteAccessVpnResponse extends BaseResponse { return domainName; } - + public String getState() { + return state; + } + + public void setState(String state) { + this.state = state; + } } diff --git a/api/src/com/cloud/exception/ResourceUnavailableException.java b/api/src/com/cloud/exception/ResourceUnavailableException.java index ffe8a9bc999..d8f77bb8003 100644 --- a/api/src/com/cloud/exception/ResourceUnavailableException.java +++ b/api/src/com/cloud/exception/ResourceUnavailableException.java @@ -30,7 +30,7 @@ public class ResourceUnavailableException extends Exception { } public ResourceUnavailableException(String msg, Class scope, long resourceId, Throwable cause) { - super(new StringBuilder("Resource [").append(scope).append(":").append(resourceId).append("] is unreachable: ").append(msg).toString(), cause); + super(new StringBuilder("Resource [").append(scope.getSimpleName()).append(":").append(resourceId).append("] is unreachable: ").append(msg).toString(), cause); _scope = scope; _id = resourceId; } diff --git a/core/src/com/cloud/agent/api/routing/VpnUsersCfgCommand.java b/core/src/com/cloud/agent/api/routing/VpnUsersCfgCommand.java index b032144a154..c5391a031de 100644 --- a/core/src/com/cloud/agent/api/routing/VpnUsersCfgCommand.java +++ b/core/src/com/cloud/agent/api/routing/VpnUsersCfgCommand.java @@ -19,7 +19,7 @@ package com.cloud.agent.api.routing; import java.util.List; -import com.cloud.network.VpnUserVO; +import com.cloud.network.VpnUser; public class VpnUsersCfgCommand extends NetworkElementCommand { @@ -70,13 +70,13 @@ public class VpnUsersCfgCommand extends NetworkElementCommand { } - public VpnUsersCfgCommand(List addUsers, List removeUsers) { + public VpnUsersCfgCommand(List addUsers, List removeUsers) { userpwds = new UsernamePassword[addUsers.size() + removeUsers.size()]; int i = 0; - for (VpnUserVO vpnUser: removeUsers) { + for (VpnUser vpnUser: removeUsers) { userpwds[i++] = new UsernamePassword(vpnUser.getUsername(), vpnUser.getPassword(), false); } - for (VpnUserVO vpnUser: addUsers) { + for (VpnUser vpnUser: addUsers) { userpwds[i++] = new UsernamePassword(vpnUser.getUsername(), vpnUser.getPassword(), true); } } diff --git a/core/src/com/cloud/network/VpnUserVO.java b/core/src/com/cloud/network/VpnUserVO.java index a48b0551c29..586fb690db4 100644 --- a/core/src/com/cloud/network/VpnUserVO.java +++ b/core/src/com/cloud/network/VpnUserVO.java @@ -53,8 +53,9 @@ public class VpnUserVO implements VpnUser { public VpnUserVO() { } - public VpnUserVO(long accountId, String userName, String password) { + public VpnUserVO(long accountId, long domainId, String userName, String password) { this.accountId = accountId; + this.domainId = domainId; this.username = userName; this.password = password; this.state = State.Add; diff --git a/server/src/com/cloud/api/ApiResponseHelper.java b/server/src/com/cloud/api/ApiResponseHelper.java index 663e237981e..e0f725e7f91 100644 --- a/server/src/com/cloud/api/ApiResponseHelper.java +++ b/server/src/com/cloud/api/ApiResponseHelper.java @@ -1288,9 +1288,12 @@ public class ApiResponseHelper implements ResponseGenerator { if (accountTemp != null) { vpnResponse.setAccountName(accountTemp.getAccountName()); vpnResponse.setDomainName(ApiDBUtils.findDomainById(accountTemp.getDomainId()).getName()); - } + } + vpnResponse.setState(vpn.getState().toString()); vpnResponse.setObjectName("remoteaccessvpn"); + + return vpnResponse; } diff --git a/server/src/com/cloud/network/dao/FirewallRulesDao.java b/server/src/com/cloud/network/dao/FirewallRulesDao.java index 34fe34536f4..b5a99cbb4ce 100644 --- a/server/src/com/cloud/network/dao/FirewallRulesDao.java +++ b/server/src/com/cloud/network/dao/FirewallRulesDao.java @@ -36,6 +36,8 @@ public interface FirewallRulesDao extends GenericDao { boolean revoke(FirewallRuleVO rule); boolean releasePorts(Ip ip, String protocol, FirewallRule.Purpose purpose, int[] ports); + + List listByIpAndPurpose(Ip ip, FirewallRule.Purpose purpose); // public List listIPForwarding(String publicIPAddress, boolean forwarding); // public List listIPForwarding(String publicIPAddress, String port, boolean forwarding); diff --git a/server/src/com/cloud/network/dao/FirewallRulesDaoImpl.java b/server/src/com/cloud/network/dao/FirewallRulesDaoImpl.java index c3a4e2dcbf8..c1d2afcd907 100644 --- a/server/src/com/cloud/network/dao/FirewallRulesDaoImpl.java +++ b/server/src/com/cloud/network/dao/FirewallRulesDaoImpl.java @@ -80,6 +80,15 @@ public class FirewallRulesDaoImpl extends GenericDaoBase i int results = remove(sc); return results == ports.length; } + + @Override + public List listByIpAndPurpose(Ip ip, FirewallRule.Purpose purpose) { + SearchCriteria sc = ReleaseSearch.create(); + sc.setParameters("ip", ip); + sc.setParameters("purpose", purpose); + + return listBy(sc); + } @Override public List listByIpAndNotRevoked(Ip ip) { diff --git a/server/src/com/cloud/network/dao/RemoteAccessVpnDao.java b/server/src/com/cloud/network/dao/RemoteAccessVpnDao.java index 36bea257d62..6b6bc300d1b 100644 --- a/server/src/com/cloud/network/dao/RemoteAccessVpnDao.java +++ b/server/src/com/cloud/network/dao/RemoteAccessVpnDao.java @@ -20,12 +20,14 @@ package com.cloud.network.dao; import java.util.List; +import com.cloud.network.RemoteAccessVpn; import com.cloud.network.RemoteAccessVpnVO; import com.cloud.utils.db.GenericDao; import com.cloud.utils.net.Ip; public interface RemoteAccessVpnDao extends GenericDao { RemoteAccessVpnVO findByPublicIpAddress(String ipAddress); + RemoteAccessVpnVO findByPublicIpAddressAndState(String ipAddress, RemoteAccessVpn.State state); RemoteAccessVpnVO findByAccountAndNetwork(Long accountId, Long zoneId); List findByAccount(Long accountId); } diff --git a/server/src/com/cloud/network/dao/RemoteAccessVpnDaoImpl.java b/server/src/com/cloud/network/dao/RemoteAccessVpnDaoImpl.java index 28606e60694..bb0de654e01 100644 --- a/server/src/com/cloud/network/dao/RemoteAccessVpnDaoImpl.java +++ b/server/src/com/cloud/network/dao/RemoteAccessVpnDaoImpl.java @@ -24,6 +24,7 @@ import javax.ejb.Local; import org.apache.log4j.Logger; +import com.cloud.network.RemoteAccessVpn; import com.cloud.network.RemoteAccessVpnVO; import com.cloud.utils.db.GenericDaoBase; import com.cloud.utils.db.SearchBuilder; @@ -42,6 +43,7 @@ public class RemoteAccessVpnDaoImpl extends GenericDaoBase sc = AllFieldsSearch.create(); sc.setParameters("accountId", accountId); return listBy(sc); + } + + @Override + public RemoteAccessVpnVO findByPublicIpAddressAndState(String ipAddress, RemoteAccessVpn.State state) { + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("ipAddress", ipAddress); + sc.setParameters("state", state); + return findOneBy(sc); } } diff --git a/server/src/com/cloud/network/element/VirtualRouterElement.java b/server/src/com/cloud/network/element/VirtualRouterElement.java index 32de0b5dec0..5f18c62659f 100644 --- a/server/src/com/cloud/network/element/VirtualRouterElement.java +++ b/server/src/com/cloud/network/element/VirtualRouterElement.java @@ -39,6 +39,8 @@ import com.cloud.network.Network.Provider; import com.cloud.network.Network.Service; import com.cloud.network.NetworkManager; import com.cloud.network.PublicIpAddress; +import com.cloud.network.RemoteAccessVpn; +import com.cloud.network.VpnUser; import com.cloud.network.dao.LoadBalancerDao; import com.cloud.network.dao.NetworkDao; import com.cloud.network.lb.LoadBalancingRule; @@ -47,6 +49,7 @@ import com.cloud.network.lb.LoadBalancingRulesManager; import com.cloud.network.router.VirtualNetworkApplianceManager; import com.cloud.network.rules.FirewallRule; import com.cloud.network.rules.FirewallRule.Purpose; +import com.cloud.network.vpn.RemoteAccessVpnElement; import com.cloud.offering.NetworkOffering; import com.cloud.offering.NetworkOffering.GuestIpType; import com.cloud.offerings.dao.NetworkOfferingDao; @@ -66,7 +69,7 @@ import com.cloud.vm.dao.UserVmDao; @Local(value=NetworkElement.class) -public class VirtualRouterElement extends AdapterBase implements NetworkElement { +public class VirtualRouterElement extends AdapterBase implements NetworkElement, RemoteAccessVpnElement { private static final Logger s_logger = Logger.getLogger(VirtualRouterElement.class); private static final Map> capabilities = setCapabilities(); @@ -169,6 +172,42 @@ public class VirtualRouterElement extends AdapterBase implements NetworkElement } return false; } + + + @Override + public String[] applyVpnUsers(RemoteAccessVpn vpn, List users) throws ResourceUnavailableException{ + Network network = _networkConfigDao.findById(vpn.getNetworkId()); + DataCenter dc = _dataCenterDao.findById(network.getDataCenterId()); + if (canHandle(network.getGuestType(),dc)) { + return _routerMgr.applyVpnUsers(network, users); + } else { + s_logger.debug("Element " + this.getName() + " doesn't handle applyVpnUsers command"); + return null; + } + } + + @Override + public boolean start(Network network, RemoteAccessVpn vpn) throws ResourceUnavailableException { + DataCenter dc = _dataCenterDao.findById(network.getDataCenterId()); + if (canHandle(network.getGuestType(),dc)) { + return _routerMgr.startRemoteAccessVpn(network, vpn); + } else { + s_logger.debug("Element " + this.getName() + " doesn't handle createVpn command"); + return false; + } + } + + @Override + public boolean stop(Network network, RemoteAccessVpn vpn) throws ResourceUnavailableException { + DataCenter dc = _dataCenterDao.findById(network.getDataCenterId()); + if (canHandle(network.getGuestType(),dc)) { + return _routerMgr.deleteRemoteAccessVpn(network, vpn); + } else { + s_logger.debug("Element " + this.getName() + " doesn't handle removeVpn command"); + return false; + } + } + @Override public boolean applyIps(Network network, List ipAddress) throws ResourceUnavailableException { @@ -224,5 +263,5 @@ public class VirtualRouterElement extends AdapterBase implements NetworkElement return capabilities; } - + } diff --git a/server/src/com/cloud/network/router/VirtualNetworkApplianceManager.java b/server/src/com/cloud/network/router/VirtualNetworkApplianceManager.java index 076ebaf7492..a9bed9f9840 100644 --- a/server/src/com/cloud/network/router/VirtualNetworkApplianceManager.java +++ b/server/src/com/cloud/network/router/VirtualNetworkApplianceManager.java @@ -30,7 +30,9 @@ import com.cloud.exception.PermissionDeniedException; import com.cloud.exception.ResourceUnavailableException; import com.cloud.network.Network; import com.cloud.network.PublicIpAddress; +import com.cloud.network.RemoteAccessVpn; import com.cloud.network.RemoteAccessVpnVO; +import com.cloud.network.VpnUser; import com.cloud.network.VpnUserVO; import com.cloud.network.rules.FirewallRule; import com.cloud.user.Account; @@ -97,11 +99,11 @@ public interface VirtualNetworkApplianceManager extends Manager { VirtualRouter deployDhcp(Network guestNetwork, DeployDestination dest, Account owner) throws InsufficientCapacityException, ResourceUnavailableException, ConcurrentOperationException; - RemoteAccessVpnVO startRemoteAccessVpn(RemoteAccessVpnVO vpnVO) throws ResourceUnavailableException; + boolean startRemoteAccessVpn(Network network, RemoteAccessVpn vpn) throws ResourceUnavailableException; boolean addRemoveVpnUsers(RemoteAccessVpnVO vpnVO, List addUsers, List removeUsers); - boolean deleteRemoteAccessVpn(RemoteAccessVpnVO vpnVO); + boolean deleteRemoteAccessVpn(Network network, RemoteAccessVpn vpn) throws ResourceUnavailableException; VirtualRouter addVirtualMachineIntoNetwork(Network config, NicProfile nic, VirtualMachineProfile vm, DeployDestination dest, ReservationContext context, Boolean startDhcp) throws ConcurrentOperationException, InsufficientCapacityException, ResourceUnavailableException; @@ -110,4 +112,6 @@ public interface VirtualNetworkApplianceManager extends Manager { boolean applyLBRules(Network network, List rules) throws ResourceUnavailableException; boolean applyPortForwardingRules(Network network, List rules) throws AgentUnavailableException; + String[] applyVpnUsers(Network network, List users) throws ResourceUnavailableException; + } diff --git a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java index 8ab259baa97..1c773fcb19a 100644 --- a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java +++ b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java @@ -52,9 +52,11 @@ import com.cloud.agent.api.routing.DhcpEntryCommand; import com.cloud.agent.api.routing.IPAssocCommand; import com.cloud.agent.api.routing.LoadBalancerConfigCommand; import com.cloud.agent.api.routing.NetworkElementCommand; +import com.cloud.agent.api.routing.RemoteAccessVpnCfgCommand; import com.cloud.agent.api.routing.SavePasswordCommand; import com.cloud.agent.api.routing.SetPortForwardingRulesCommand; import com.cloud.agent.api.routing.VmDataCommand; +import com.cloud.agent.api.routing.VpnUsersCfgCommand; import com.cloud.agent.api.to.IpAddressTO; import com.cloud.agent.api.to.LoadBalancerTO; import com.cloud.agent.manager.Commands; @@ -109,9 +111,11 @@ import com.cloud.network.Networks.BroadcastDomainType; import com.cloud.network.Networks.IsolationType; import com.cloud.network.Networks.TrafficType; import com.cloud.network.PublicIpAddress; +import com.cloud.network.RemoteAccessVpn; import com.cloud.network.RemoteAccessVpnVO; import com.cloud.network.SshKeysDistriMonitor; import com.cloud.network.VirtualNetworkApplianceService; +import com.cloud.network.VpnUser; import com.cloud.network.VpnUserVO; import com.cloud.network.addr.PublicIp; import com.cloud.network.dao.FirewallRulesDao; @@ -587,20 +591,20 @@ public class VirtualNetworkApplianceManagerImpl implements VirtualNetworkApplian * } */ - private boolean resendVpnServerData(final DomainRouterVO router) { - RemoteAccessVpnVO vpnVO = _remoteAccessVpnDao.findByAccountAndNetwork(router.getAccountId(), router.getDataCenterId()); - - if (vpnVO != null) { - try { - vpnVO = startRemoteAccessVpn(vpnVO); - } catch (ResourceUnavailableException e) { - s_logger.warn("Unable to resend vpn server information to restarted router: " + router.getInstanceName()); - return false; - } - return (vpnVO != null); - } - return true; - } +// private boolean resendVpnServerData(final DomainRouterVO router) { +// RemoteAccessVpnVO vpnVO = _remoteAccessVpnDao.findByAccountAndNetwork(router.getAccountId(), router.getDataCenterId()); +// +// if (vpnVO != null) { +// try { +// vpnVO = startRemoteAccessVpn(vpnVO); +// } catch (ResourceUnavailableException e) { +// s_logger.warn("Unable to resend vpn server information to restarted router: " + router.getInstanceName()); +// return false; +// } +// return (vpnVO != null); +// } +// return true; +// } @Override public boolean stopRouter(final long routerId) { @@ -1559,81 +1563,86 @@ public class VirtualNetworkApplianceManagerImpl implements VirtualNetworkApplian } @Override - public RemoteAccessVpnVO startRemoteAccessVpn(RemoteAccessVpnVO vpnVO) throws ResourceUnavailableException { - return null; -// DomainRouterVO router = getRouter(vpnVO.getAccountId(), vpnVO.getZoneId()); -// if (router == null) { -// s_logger.warn("Failed to start remote access VPN: no router found for account and zone"); -// return null; -// } -// if (router.getState() != State.Running && router.getState() != State.Starting) { -// s_logger.warn("Failed to start remote access VPN: router not in running state"); -// return null; -// } -// List vpnUsers = _vpnUsersDao.listByAccount(vpnVO.getAccountId()); -// VpnUsersCfgCommand addUsersCmd = new VpnUsersCfgCommand(router.getPrivateIpAddress(), vpnUsers, new ArrayList()); -// RemoteAccessVpnCfgCommand startVpnCmd = new RemoteAccessVpnCfgCommand(true, router.getPrivateIpAddress(), vpnVO.getServerAddress(), -// vpnVO.getLocalIp(), vpnVO.getIpRange(), vpnVO.getIpsecPresharedKey()); -// Commands cmds = new Commands(OnError.Stop); -// cmds.addCommand("users", addUsersCmd); -// cmds.addCommand("startVpn", startVpnCmd); -// try { -// _agentMgr.send(router.getHostId(), cmds); -// } catch (AgentUnavailableException e) { -// s_logger.debug("Failed to start remote access VPN: ", e); -// return null; -// } catch (OperationTimedoutException e) { -// s_logger.debug("Failed to start remote access VPN: ", e); -// return null; -// } -// Answer answer = cmds.getAnswer("users"); -// if (!answer.getResult()) { -// s_logger.error("Unable to start vpn: unable add users to vpn in zone " + vpnVO.getZoneId() + " for account " + vpnVO.getAccountId() -// + " on domR: " + router.getInstanceName() + " due to " + answer.getDetails()); -// throw new ResourceUnavailableException("Unable to start vpn: Unable to add users to vpn in zone " + vpnVO.getZoneId() + " for account " -// + vpnVO.getAccountId() + " on domR: " + router.getInstanceName() + " due to " + answer.getDetails(), DataCenter.class, -// vpnVO.getZoneId()); -// } -// answer = cmds.getAnswer("startVpn"); -// if (!answer.getResult()) { -// s_logger.error("Unable to start vpn in zone " + vpnVO.getZoneId() + " for account " + vpnVO.getAccountId() + " on domR: " -// + router.getInstanceName() + " due to " + answer.getDetails()); -// throw new ResourceUnavailableException("Unable to start vpn in zone " + vpnVO.getZoneId() + " for account " + vpnVO.getAccountId() -// + " on domR: " + router.getInstanceName() + " due to " + answer.getDetails(), DataCenter.class, vpnVO.getZoneId()); -// } -// return vpnVO; + public boolean startRemoteAccessVpn(Network network, RemoteAccessVpn vpn) throws ResourceUnavailableException { + + DomainRouterVO router = _routerDao.findByNetworkConfiguration(network.getId()); + if (router == null) { + s_logger.warn("Failed to start remote access VPN: no router found for account and zone"); + throw new ResourceUnavailableException("Unable to apply lb rules", DataCenter.class, network.getDataCenterId()); + } + if (router.getState() != State.Running && router.getState() != State.Starting) { + s_logger.warn("Failed to start remote access VPN: router not in running state"); + throw new ResourceUnavailableException("Unable to assign ip addresses, domR is not in right state " + router.getState(), DataCenter.class, network.getDataCenterId()); + } + + List vpnUsers = _vpnUsersDao.listByAccount(vpn.getAccountId()); + List addUsers = new ArrayList(); + List removeUsers = new ArrayList(); + for (VpnUser user: vpnUsers) { + if (user.getState() == VpnUser.State.Add) { + addUsers.add(user); + } else if (user.getState() == VpnUser.State.Revoke) { + removeUsers.add(user); + } + } + + VpnUsersCfgCommand addUsersCmd = new VpnUsersCfgCommand(addUsers, removeUsers); + addUsersCmd.setAccessDetail(NetworkElementCommand.ROUTER_IP, router.getPrivateIpAddress()); + addUsersCmd.setAccessDetail(NetworkElementCommand.ROUTER_NAME, router.getInstanceName()); + + RemoteAccessVpnCfgCommand startVpnCmd = new RemoteAccessVpnCfgCommand(true, vpn.getServerAddress().addr(), + vpn.getLocalIp(), vpn.getIpRange(), vpn.getIpsecPresharedKey()); + startVpnCmd.setAccessDetail(NetworkElementCommand.ROUTER_IP, router.getPrivateIpAddress()); + startVpnCmd.setAccessDetail(NetworkElementCommand.ROUTER_NAME, router.getInstanceName()); + + Commands cmds = new Commands(OnError.Stop); + cmds.addCommand("users", addUsersCmd); + cmds.addCommand("startVpn", startVpnCmd); + + //return sendCommandsToRouter(router, cmds); + try { + _agentMgr.send(router.getHostId(), cmds); + } catch (OperationTimedoutException e) { + s_logger.debug("Failed to start remote access VPN: ", e); + throw new AgentUnavailableException("Unable to send commands to virtual router ", router.getHostId(), e); + } + Answer answer = cmds.getAnswer("users"); + if (!answer.getResult()) { + s_logger.error("Unable to start vpn: unable add users to vpn in zone " + router.getDataCenterId() + " for account " + vpn.getAccountId() + + " on domR: " + router.getInstanceName() + " due to " + answer.getDetails()); + throw new ResourceUnavailableException("Unable to start vpn: Unable to add users to vpn in zone " + router.getDataCenterId() + " for account " + + vpn.getAccountId() + " on domR: " + router.getInstanceName() + " due to " + answer.getDetails(), DataCenter.class, + router.getDataCenterId()); + } + answer = cmds.getAnswer("startVpn"); + if (!answer.getResult()) { + s_logger.error("Unable to start vpn in zone " + router.getDataCenterId() + " for account " + vpn.getAccountId() + " on domR: " + + router.getInstanceName() + " due to " + answer.getDetails()); + throw new ResourceUnavailableException("Unable to start vpn in zone " + router.getDataCenterId() + " for account " + vpn.getAccountId() + + " on domR: " + router.getInstanceName() + " due to " + answer.getDetails(), DataCenter.class, router.getDataCenterId()); + } + return true; } @Override - public boolean deleteRemoteAccessVpn(RemoteAccessVpnVO vpnVO) { - return false; -// DomainRouterVO router = getRouter(vpnVO.getAccountId(), vpnVO.getZoneId()); -// if (router == null) { -// s_logger.warn("Failed to delete remote access VPN: no router found for account and zone"); -// return false; -// } -// if (router.getState() != State.Running) { -// s_logger.warn("Failed to delete remote access VPN: router not in running state"); -// return false; -// } -// try { -// Answer answer = _agentMgr.send( -// router.getHostId(), -// new RemoteAccessVpnCfgCommand(false, router.getPrivateIpAddress(), vpnVO.getServerAddress(), vpnVO.getLocalIp(), vpnVO -// .getIpRange(), vpnVO.getIpsecPresharedKey())); -// if (answer != null && answer.getResult()) { -// return true; -// } else { -// s_logger.debug("Failed to delete remote access VPN: " + answer.getDetails()); -// return false; -// } -// } catch (AgentUnavailableException e) { -// s_logger.debug("Failed to delete remote access VPN: ", e); -// return false; -// } catch (OperationTimedoutException e) { -// s_logger.debug("Failed to delete remote access VPN: ", e); -// return false; -// } + public boolean deleteRemoteAccessVpn(Network network, RemoteAccessVpn vpn) throws ResourceUnavailableException{ + + DomainRouterVO router = getRouter(vpn.getAccountId(), network.getDataCenterId()); + if (router == null) { + s_logger.warn("Failed to delete remote access VPN: no router found for account and zone"); + throw new ResourceUnavailableException("Unable to apply lb rules", DataCenter.class, network.getDataCenterId()); + } + if (router.getState() != State.Running) { + s_logger.warn("Failed to delete remote access VPN: router not in running state"); + throw new ResourceUnavailableException("Unable to assign ip addresses, domR is not in right state " + router.getState(), DataCenter.class, network.getDataCenterId()); + } + Commands cmds = new Commands(OnError.Continue); + RemoteAccessVpnCfgCommand removeVpnCmd = new RemoteAccessVpnCfgCommand(false, vpn.getServerAddress().addr(), vpn.getLocalIp(), vpn.getIpRange(), vpn.getIpsecPresharedKey()); + removeVpnCmd.setAccessDetail(NetworkElementCommand.ROUTER_IP, router.getPrivateIpAddress()); + removeVpnCmd.setAccessDetail(NetworkElementCommand.ROUTER_NAME, router.getInstanceName()); + cmds.addCommand(removeVpnCmd); + + return sendCommandsToRouter(router, cmds); } public DomainRouterVO start(long routerId, User user, Account caller) throws StorageUnavailableException, InsufficientCapacityException, @@ -1743,6 +1752,49 @@ public class VirtualNetworkApplianceManagerImpl implements VirtualNetworkApplian // return false; // } } + + + @Override + public String[] applyVpnUsers(Network network, List users) throws ResourceUnavailableException{ + DomainRouterVO router = _routerDao.findByNetworkConfiguration(network.getId()); + if (router == null) { + s_logger.warn("Failed to add/remove VPN users: no router found for account and zone"); + throw new ResourceUnavailableException("Unable to assign ip addresses, domR doesn't exist for network " + network.getId(), DataCenter.class, network.getDataCenterId()); + } + if (router.getState() != State.Running) { + s_logger.warn("Failed to add/remove VPN users: router not in running state"); + throw new ResourceUnavailableException("Unable to assign ip addresses, domR is not in right state " + router.getState(), DataCenter.class, network.getDataCenterId()); + } + + Commands cmds = new Commands(OnError.Continue); + List addUsers = new ArrayList(); + List removeUsers = new ArrayList(); + for (VpnUser user: users) { + if (user.getState() == VpnUser.State.Add || user.getState() == VpnUser.State.Active) { + addUsers.add(user); + } else if (user.getState() == VpnUser.State.Revoke) { + removeUsers.add(user); + } + } + + VpnUsersCfgCommand cmd = new VpnUsersCfgCommand(addUsers, removeUsers); + cmd.setAccessDetail(NetworkElementCommand.ROUTER_IP, router.getPrivateIpAddress()); + cmd.setAccessDetail(NetworkElementCommand.ROUTER_NAME, router.getInstanceName()); + cmds.addCommand(cmd); + + //Currently we receive just one answer from the agent. In the future we have to parse individual answers and set results accordingly + boolean agentResult = sendCommandsToRouter(router, cmds);; + String[] result = new String[users.size()]; + for (int i = 0; i < result.length; i++) { + if (agentResult) { + result[i] = null; + } else { + result[i] = String.valueOf(agentResult); + } + } + + return result; + } @Override public DomainRouterVO findById(long id) { @@ -1985,4 +2037,7 @@ public class VirtualNetworkApplianceManagerImpl implements VirtualNetworkApplian // TODO Auto-generated method stub return null; } + + + } diff --git a/server/src/com/cloud/network/vpn/RemoteAccessVpnManagerImpl.java b/server/src/com/cloud/network/vpn/RemoteAccessVpnManagerImpl.java index ff839f1a793..8a04ff2e1f5 100644 --- a/server/src/com/cloud/network/vpn/RemoteAccessVpnManagerImpl.java +++ b/server/src/com/cloud/network/vpn/RemoteAccessVpnManagerImpl.java @@ -38,6 +38,7 @@ import com.cloud.event.EventVO; import com.cloud.exception.AccountLimitException; import com.cloud.exception.InvalidParameterValueException; import com.cloud.exception.NetworkRuleConflictException; +import com.cloud.exception.PermissionDeniedException; import com.cloud.exception.ResourceUnavailableException; import com.cloud.network.Network; import com.cloud.network.NetworkManager; @@ -47,11 +48,13 @@ import com.cloud.network.RemoteAccessVpnVO; import com.cloud.network.VpnUser; import com.cloud.network.VpnUser.State; import com.cloud.network.VpnUserVO; +import com.cloud.network.dao.FirewallRulesDao; import com.cloud.network.dao.IPAddressDao; import com.cloud.network.dao.RemoteAccessVpnDao; import com.cloud.network.dao.VpnUserDao; import com.cloud.network.router.VirtualNetworkApplianceManager; import com.cloud.network.rules.FirewallRule.Purpose; +import com.cloud.network.rules.FirewallRuleVO; import com.cloud.network.rules.RulesManager; import com.cloud.user.Account; import com.cloud.user.AccountManager; @@ -76,26 +79,18 @@ import com.cloud.utils.net.NetUtils; public class RemoteAccessVpnManagerImpl implements RemoteAccessVpnService, Manager { private final static Logger s_logger = Logger.getLogger(RemoteAccessVpnManagerImpl.class); String _name; - - @Inject - AccountDao _accountDao; - @Inject - VpnUserDao _vpnUsersDao; - @Inject - RemoteAccessVpnDao _remoteAccessVpnDao; - @Inject - IPAddressDao _ipAddressDao; - @Inject - VirtualNetworkApplianceManager _routerMgr; - @Inject - AccountManager _accountMgr; - @Inject - NetworkManager _networkMgr; - @Inject - RulesManager _rulesMgr; - @Inject - DomainDao _domainDao; - + + @Inject AccountDao _accountDao; + @Inject VpnUserDao _vpnUsersDao; + @Inject RemoteAccessVpnDao _remoteAccessVpnDao; + @Inject IPAddressDao _ipAddressDao; + @Inject VirtualNetworkApplianceManager _routerMgr; + @Inject AccountManager _accountMgr; + @Inject NetworkManager _networkMgr; + @Inject RulesManager _rulesMgr; + @Inject DomainDao _domainDao; + @Inject FirewallRulesDao _rulesDao; + int _userLimit; int _pskLength; String _clientIpRange; @@ -119,13 +114,22 @@ public class RemoteAccessVpnManagerImpl implements RemoteAccessVpnService, Manag } RemoteAccessVpnVO vpnVO = _remoteAccessVpnDao.findByPublicIpAddress(publicIp.toString()); + if (vpnVO != null) { + //if vpn is in Added state, return it to the api + if (vpnVO.getState() == RemoteAccessVpn.State.Added) { + return vpnVO; + } throw new InvalidParameterValueException("A Remote Access VPN already exists for this public Ip address"); } // TODO: assumes one virtual network / domr per account per zone vpnVO = _remoteAccessVpnDao.findByAccountAndNetwork(ipAddr.getAllocatedToAccountId(), ipAddr.getAssociatedWithNetworkId()); if (vpnVO != null) { + //if vpn is in Added state, return it to the api + if (vpnVO.getState() == RemoteAccessVpn.State.Added) { + return vpnVO; + } throw new InvalidParameterValueException("A Remote Access VPN already exists for this account"); } @@ -211,6 +215,7 @@ public class RemoteAccessVpnManagerImpl implements RemoteAccessVpnService, Manag + owner.getAccountName() + " in " + ip, startEventId); vpn.setState(RemoteAccessVpn.State.Removed); + _remoteAccessVpnDao.update(vpn.getServerAddress(), vpn); List elements = _networkMgr.getRemoteAccessVpnElements(); @@ -229,17 +234,31 @@ public class RemoteAccessVpnManagerImpl implements RemoteAccessVpnService, Manag } else { Transaction txn = Transaction.currentTxn(); - txn.start(); - _remoteAccessVpnDao.remove(ip); - if (!_rulesMgr.releasePorts(ip, NetUtils.UDP_PROTO, Purpose.Vpn, NetUtils.VPN_L2TP_PORT, NetUtils.VPN_NATT_PORT, NetUtils.VPN_PORT)) { - s_logger.warn("Unable to release the three vpn ports from the firewall rules"); - txn.rollback(); + try { + txn.start(); + _remoteAccessVpnDao.remove(ip); - } else { + //Cleanup corresponding ports + List ports = _rulesDao.listByIpAndPurpose(ip, Purpose.Vpn); + if (ports != null) { + for (FirewallRuleVO port : ports) { + _rulesDao.remove(port.getId()); + s_logger.debug("Successfully removed firewall rule with ip " + port.getSourceIpAddress() + " and port " + port.getSourcePortStart() + " as a part of vpn cleanup"); + } + } EventUtils.saveEvent(userId, owner.getId(), EventTypes.EVENT_REMOTE_ACCESS_VPN_DESTROY, "Deleted Remote Access VPN for account: " + owner.getAccountName()); + txn.commit(); + } catch (Exception ex) { + txn.rollback(); + s_logger.warn("Unable to release the three vpn ports from the firewall rules", ex); } - txn.commit(); + +// +// if (!_rulesMgr.releasePorts(ip, NetUtils.UDP_PROTO, Purpose.Vpn, NetUtils.VPN_L2TP_PORT, NetUtils.VPN_NATT_PORT, NetUtils.VPN_PORT)) { +// s_logger.warn("Unable to release the three vpn ports from the firewall rules"); +// txn.rollback(); + } } } @@ -270,7 +289,7 @@ public class RemoteAccessVpnManagerImpl implements RemoteAccessVpnService, Manag throw new AccountLimitException("Cannot add more than " + _userLimit + " remote access vpn users"); } - VpnUser user = _vpnUsersDao.persist(new VpnUserVO(vpnOwnerId, username, password)); + VpnUser user = _vpnUsersDao.persist(new VpnUserVO(vpnOwnerId, owner.getDomainId(), username, password)); EventUtils.saveEvent(callerId, owner.getId(), EventTypes.EVENT_VPN_USER_ADD, "Added a VPN user for account: " + owner.getAccountName() + " username= " + username); txn.commit(); @@ -354,7 +373,15 @@ public class RemoteAccessVpnManagerImpl implements RemoteAccessVpnService, Manag List vpns = _remoteAccessVpnDao.findByAccount(vpnOwnerId); List users = _vpnUsersDao.listByAccount(vpnOwnerId); - + + //If user is in Active state, we still have to resend them therefore their status has to be Add + for (VpnUserVO user : users) { + if (user.getState() == State.Active) { + user.setState(State.Add); + _vpnUsersDao.update(user.getId(), user); + } + } + List elements = _networkMgr.getRemoteAccessVpnElements(); boolean success = true; @@ -365,17 +392,18 @@ public class RemoteAccessVpnManagerImpl implements RemoteAccessVpnService, Manag for (RemoteAccessVpnVO vpn : vpns) { try { String[] results = element.applyVpnUsers(vpn, users); - - for (int i = 0; i < results.length; i++) { - s_logger.debug("VPN User " + users.get(i) - + (results[i] == null ? " is set on " : (" couldn't be set due to " + results[i]) + " on ") + vpn); - if (results[i] == null) { - if (!finals[i]) { - finals[i] = true; + if (results != null) { + for (int i = 0; i < results.length; i++) { + s_logger.debug("VPN User " + users.get(i) + + (results[i] == null ? " is set on " : (" couldn't be set due to " + results[i]) + " on ") + vpn); + if (results[i] == null) { + if (!finals[i]) { + finals[i] = true; + } + } else { + finals[i] = false; + success = false; } - } else { - finals[i] = false; - success = false; } } } catch (ResourceUnavailableException e) { @@ -390,14 +418,16 @@ public class RemoteAccessVpnManagerImpl implements RemoteAccessVpnService, Manag } for (int i = 0; i < finals.length; i++) { - if (finals[i]) { - VpnUserVO user = users.get(i); + VpnUserVO user = users.get(i); + if (finals[i]) { if (user.getState() == State.Add) { user.setState(State.Active); _vpnUsersDao.update(user.getId(), user); } else if (user.getState() == State.Revoke) { _vpnUsersDao.remove(user.getId()); } + } else { + s_logger.warn("Failed to apply vpn for user " + user.getUsername() + ", accountId=" + user.getAccountId()); } } @@ -411,6 +441,31 @@ public class RemoteAccessVpnManagerImpl implements RemoteAccessVpnService, Manag Long domainId = cmd.getDomainId(); Long accountId = null; String username = cmd.getUsername(); + + //Verify account information + if (account.getType() == Account.ACCOUNT_TYPE_ADMIN) { + if (domainId != null) { + if ((account != null) && !_domainDao.isChildDomain(account.getDomainId(), domainId)) { + throw new PermissionDeniedException("Invalid domain id (" + domainId + ") given, unable to list virtual machines."); + } + + if (accountName != null) { + account = _accountDao.findActiveAccount(accountName, domainId); + if (account == null) { + throw new InvalidParameterValueException("Unable to find account " + accountName + " in domain " + domainId); + } + accountId = account.getId(); + } + } + if (account.getType() == Account.ACCOUNT_TYPE_DOMAIN_ADMIN) { + DomainVO domain = _domainDao.findById(account.getDomainId()); + if (domain != null) { + domainId = domain.getId(); + } + } + } else { + accountId = account.getId(); + } Filter searchFilter = new Filter(VpnUserVO.class, "username", true, cmd.getStartIndex(), cmd.getPageSizeVal()); @@ -420,6 +475,7 @@ public class RemoteAccessVpnManagerImpl implements RemoteAccessVpnService, Manag sb.and("id", sb.entity().getId(), SearchCriteria.Op.EQ); sb.and("username", sb.entity().getUsername(), SearchCriteria.Op.EQ); sb.and("accountId", sb.entity().getAccountId(), SearchCriteria.Op.EQ); + sb.and("state", sb.entity().getState(), SearchCriteria.Op.EQ); if ((accountId == null) && (domainId != null)) { // if accountId isn't specified, we can do a domain match for the @@ -430,6 +486,9 @@ public class RemoteAccessVpnManagerImpl implements RemoteAccessVpnService, Manag } SearchCriteria sc = sb.create(); + + //list only active users + sc.setParameters("state", State.Active); if (id != null) { sc.setParameters("id", id); @@ -489,6 +548,7 @@ public class RemoteAccessVpnManagerImpl implements RemoteAccessVpnService, Manag SearchCriteria sc = VpnSearch.create(); sc.setParameters("accountId", owner.getId()); + sc.setParameters("state", RemoteAccessVpn.State.Running); DomainVO domain = _domainDao.findById(domainId); sc.setJoinParameters("domainSearch", "path", domain.getPath() + "%"); diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index 663dc8659ce..632d9f4985c 100755 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -99,7 +99,6 @@ import com.cloud.deploy.DataCenterDeployment; import com.cloud.deploy.DeployDestination; import com.cloud.domain.DomainVO; import com.cloud.domain.dao.DomainDao; -import com.cloud.event.Event; import com.cloud.event.EventTypes; import com.cloud.event.EventUtils; import com.cloud.event.EventVO;