mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
S2S VPN: CS-15650: Add connection status update to s2s vpn
This commit is contained in:
parent
786d5995df
commit
8eee8f342e
@ -0,0 +1,55 @@
|
||||
package com.cloud.agent.api;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class CheckS2SVpnConnectionsAnswer extends Answer {
|
||||
Map<String, Boolean> ipToConnected;
|
||||
Map<String, String> ipToDetail;
|
||||
String details;
|
||||
|
||||
protected CheckS2SVpnConnectionsAnswer() {
|
||||
ipToConnected = new HashMap<String, Boolean>();
|
||||
ipToDetail = new HashMap<String, String>();
|
||||
}
|
||||
|
||||
public CheckS2SVpnConnectionsAnswer(CheckS2SVpnConnectionsCommand cmd, boolean result, String details) {
|
||||
super(cmd, result, details);
|
||||
ipToConnected = new HashMap<String, Boolean>();
|
||||
ipToDetail = new HashMap<String, String>();
|
||||
this.details = details;
|
||||
if (result) {
|
||||
parseDetails(details);
|
||||
}
|
||||
}
|
||||
|
||||
protected void parseDetails(String details) {
|
||||
String[] lines = details.split("&");
|
||||
for (String line : lines) {
|
||||
String[] words = line.split(":");
|
||||
if (words.length != 3) {
|
||||
//Not something we can parse
|
||||
return;
|
||||
}
|
||||
String ip = words[0];
|
||||
boolean connected = words[1].equals("0");
|
||||
String detail = words[2];
|
||||
ipToConnected.put(ip, connected);
|
||||
ipToDetail.put(ip, detail);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isConnected(String ip) {
|
||||
if (this.getResult()) {
|
||||
return ipToConnected.get(ip);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public String getDetail(String ip) {
|
||||
if (this.getResult()) {
|
||||
return ipToDetail.get(ip);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,23 @@
|
||||
package com.cloud.agent.api;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.cloud.agent.api.routing.NetworkElementCommand;
|
||||
|
||||
public class CheckS2SVpnConnectionsCommand extends NetworkElementCommand {
|
||||
List<String> vpnIps;
|
||||
|
||||
@Override
|
||||
public boolean executeInSequence() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public CheckS2SVpnConnectionsCommand(List<String> vpnIps) {
|
||||
super();
|
||||
this.vpnIps = vpnIps;
|
||||
}
|
||||
|
||||
public List<String> getVpnIps() {
|
||||
return vpnIps;
|
||||
}
|
||||
}
|
||||
@ -42,6 +42,8 @@ import com.cloud.agent.api.Answer;
|
||||
import com.cloud.agent.api.BumpUpPriorityCommand;
|
||||
import com.cloud.agent.api.CheckRouterAnswer;
|
||||
import com.cloud.agent.api.CheckRouterCommand;
|
||||
import com.cloud.agent.api.CheckS2SVpnConnectionsAnswer;
|
||||
import com.cloud.agent.api.CheckS2SVpnConnectionsCommand;
|
||||
import com.cloud.agent.api.Command;
|
||||
import com.cloud.agent.api.GetDomRVersionAnswer;
|
||||
import com.cloud.agent.api.GetDomRVersionCmd;
|
||||
@ -139,6 +141,8 @@ public class VirtualRoutingResource implements Manager {
|
||||
return execute((GetDomRVersionCmd)cmd);
|
||||
} else if (cmd instanceof Site2SiteVpnCfgCommand) {
|
||||
return execute((Site2SiteVpnCfgCommand)cmd);
|
||||
} else if (cmd instanceof CheckS2SVpnConnectionsCommand) {
|
||||
return execute((CheckS2SVpnConnectionsCommand)cmd);
|
||||
}
|
||||
else {
|
||||
return Answer.createUnsupportedCommandAnswer(cmd);
|
||||
@ -500,6 +504,21 @@ public class VirtualRoutingResource implements Manager {
|
||||
return null;
|
||||
}
|
||||
|
||||
private CheckS2SVpnConnectionsAnswer execute(CheckS2SVpnConnectionsCommand cmd) {
|
||||
final String routerIP = cmd.getAccessDetail(NetworkElementCommand.ROUTER_IP);
|
||||
|
||||
String args = "";
|
||||
for (String ip : cmd.getVpnIps()) {
|
||||
args += " " + ip;
|
||||
}
|
||||
|
||||
final String result = routerProxy("checkbatchs2svpn.sh", routerIP, args);
|
||||
if (result == null || result.isEmpty()) {
|
||||
return new CheckS2SVpnConnectionsAnswer(cmd, false, "CheckS2SVpnConneciontsCommand failed");
|
||||
}
|
||||
return new CheckS2SVpnConnectionsAnswer(cmd, true, result);
|
||||
}
|
||||
|
||||
protected Answer execute(CheckRouterCommand cmd) {
|
||||
final String routerPrivateIPAddress = cmd.getAccessDetail(NetworkElementCommand.ROUTER_IP);
|
||||
|
||||
|
||||
@ -12,20 +12,20 @@ cat /tmp/vpn-$1.status | grep "ISAKMP SA established" > /dev/null
|
||||
isakmpok=$?
|
||||
if [ $isakmpok -ne 0 ]
|
||||
then
|
||||
echo "ISAKMP SA not found"
|
||||
echo -n "ISAKMP SA not found"
|
||||
echo "Site-to-site VPN have not connected"
|
||||
exit 12
|
||||
fi
|
||||
echo "ISAKMP SA found"
|
||||
echo -n "ISAKMP SA found;"
|
||||
|
||||
cat /tmp/vpn-$1.status | grep "IPsec SA established" > /dev/null
|
||||
ipsecok=$?
|
||||
if [ $ipsecok -ne 0 ]
|
||||
then
|
||||
echo "IPsec SA not found"
|
||||
echo -n "IPsec SA not found;"
|
||||
echo "Site-to-site VPN have not connected"
|
||||
exit 11
|
||||
fi
|
||||
echo "IPsec SA found"
|
||||
echo -n "IPsec SA found;"
|
||||
echo "Site-to-site VPN have connected"
|
||||
exit 0
|
||||
|
||||
@ -53,6 +53,8 @@ import com.cloud.agent.api.CheckOnHostAnswer;
|
||||
import com.cloud.agent.api.CheckOnHostCommand;
|
||||
import com.cloud.agent.api.CheckRouterAnswer;
|
||||
import com.cloud.agent.api.CheckRouterCommand;
|
||||
import com.cloud.agent.api.CheckS2SVpnConnectionsAnswer;
|
||||
import com.cloud.agent.api.CheckS2SVpnConnectionsCommand;
|
||||
import com.cloud.agent.api.CheckVirtualMachineAnswer;
|
||||
import com.cloud.agent.api.CheckVirtualMachineCommand;
|
||||
import com.cloud.agent.api.Command;
|
||||
@ -1020,6 +1022,35 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
|
||||
return new Answer(cmd);
|
||||
}
|
||||
|
||||
protected CheckS2SVpnConnectionsAnswer execute(CheckS2SVpnConnectionsCommand cmd) {
|
||||
if (s_logger.isDebugEnabled()) {
|
||||
s_logger.debug("Executing resource CheckS2SVpnConnectionsCommand: " + _gson.toJson(cmd));
|
||||
s_logger.debug("Run command on domR " + cmd.getAccessDetail(NetworkElementCommand.ROUTER_IP) + ", /opt/cloud/bin/checkbatchs2svpn.sh ");
|
||||
}
|
||||
|
||||
Pair<Boolean, String> result;
|
||||
try {
|
||||
VmwareManager mgr = getServiceContext().getStockObject(VmwareManager.CONTEXT_STOCK_NAME);
|
||||
String controlIp = getRouterSshControlIp(cmd);
|
||||
result = SshHelper.sshExecute(controlIp, DEFAULT_DOMR_SSHPORT, "root", mgr.getSystemVMKeyFile(), null,
|
||||
"/opt/cloud/bin/checkbatchs2svpn.sh ");
|
||||
|
||||
if (!result.first()) {
|
||||
s_logger.error("check site-to-site vpn connections command on domR " + cmd.getAccessDetail(NetworkElementCommand.ROUTER_IP) + " failed, message: " + result.second());
|
||||
|
||||
return new CheckS2SVpnConnectionsAnswer(cmd, false, result.second());
|
||||
}
|
||||
|
||||
if (s_logger.isDebugEnabled()) {
|
||||
s_logger.debug("check site-to-site vpn connections command on domain router " + cmd.getAccessDetail(NetworkElementCommand.ROUTER_IP) + " completed");
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
String msg = "CheckS2SVpnConnectionsCommand failed due to " + VmwareHelper.getExceptionMessage(e);
|
||||
s_logger.error(msg, e);
|
||||
return new CheckS2SVpnConnectionsAnswer(cmd, false, "CheckS2SVpnConneciontsCommand failed");
|
||||
}
|
||||
return new CheckS2SVpnConnectionsAnswer(cmd, true, result.second());
|
||||
}
|
||||
protected Answer execute(CheckRouterCommand cmd) {
|
||||
if (s_logger.isDebugEnabled()) {
|
||||
s_logger.debug("Executing resource CheckRouterCommand: " + _gson.toJson(cmd));
|
||||
|
||||
@ -66,6 +66,8 @@ import com.cloud.agent.api.CheckOnHostAnswer;
|
||||
import com.cloud.agent.api.CheckOnHostCommand;
|
||||
import com.cloud.agent.api.CheckRouterAnswer;
|
||||
import com.cloud.agent.api.CheckRouterCommand;
|
||||
import com.cloud.agent.api.CheckS2SVpnConnectionsAnswer;
|
||||
import com.cloud.agent.api.CheckS2SVpnConnectionsCommand;
|
||||
import com.cloud.agent.api.CheckVirtualMachineAnswer;
|
||||
import com.cloud.agent.api.CheckVirtualMachineCommand;
|
||||
import com.cloud.agent.api.CleanupNetworkRulesCmd;
|
||||
@ -549,6 +551,8 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
|
||||
return execute((SetStaticRouteCommand) cmd);
|
||||
} else if (clazz == Site2SiteVpnCfgCommand.class) {
|
||||
return execute((Site2SiteVpnCfgCommand) cmd);
|
||||
} else if (clazz == CheckS2SVpnConnectionsCommand.class) {
|
||||
return execute((CheckS2SVpnConnectionsCommand) cmd);
|
||||
} else {
|
||||
return Answer.createUnsupportedCommandAnswer(cmd);
|
||||
}
|
||||
@ -1400,6 +1404,18 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
|
||||
return new Answer(cmd);
|
||||
}
|
||||
|
||||
private CheckS2SVpnConnectionsAnswer execute(CheckS2SVpnConnectionsCommand cmd) {
|
||||
Connection conn = getConnection();
|
||||
String args = "checkbatchs2svpn.sh " + cmd.getAccessDetail(NetworkElementCommand.ROUTER_IP);
|
||||
for (String ip : cmd.getVpnIps()) {
|
||||
args += " " + ip;
|
||||
}
|
||||
String result = callHostPlugin(conn, "vmops", "routerProxy", "args", args);
|
||||
if (result == null || result.isEmpty()) {
|
||||
return new CheckS2SVpnConnectionsAnswer(cmd, false, "CheckS2SVpnConneciontsCommand failed");
|
||||
}
|
||||
return new CheckS2SVpnConnectionsAnswer(cmd, true, result);
|
||||
}
|
||||
|
||||
private CheckRouterAnswer execute(CheckRouterCommand cmd) {
|
||||
Connection conn = getConnection();
|
||||
|
||||
@ -47,6 +47,8 @@ import com.cloud.agent.api.Answer;
|
||||
import com.cloud.agent.api.BumpUpPriorityCommand;
|
||||
import com.cloud.agent.api.CheckRouterAnswer;
|
||||
import com.cloud.agent.api.CheckRouterCommand;
|
||||
import com.cloud.agent.api.CheckS2SVpnConnectionsAnswer;
|
||||
import com.cloud.agent.api.CheckS2SVpnConnectionsCommand;
|
||||
import com.cloud.agent.api.Command;
|
||||
import com.cloud.agent.api.GetDomRVersionAnswer;
|
||||
import com.cloud.agent.api.GetDomRVersionCmd;
|
||||
@ -132,6 +134,11 @@ import com.cloud.network.Networks.TrafficType;
|
||||
import com.cloud.network.PhysicalNetworkServiceProvider;
|
||||
import com.cloud.network.PublicIpAddress;
|
||||
import com.cloud.network.RemoteAccessVpn;
|
||||
import com.cloud.network.Site2SiteCustomerGateway;
|
||||
import com.cloud.network.Site2SiteCustomerGatewayVO;
|
||||
import com.cloud.network.Site2SiteVpnConnection;
|
||||
import com.cloud.network.Site2SiteVpnConnectionVO;
|
||||
import com.cloud.network.Site2SiteVpnGatewayVO;
|
||||
import com.cloud.network.SshKeysDistriMonitor;
|
||||
import com.cloud.network.VirtualNetworkApplianceService;
|
||||
import com.cloud.network.VirtualRouterProvider;
|
||||
@ -165,6 +172,7 @@ import com.cloud.network.rules.StaticNat;
|
||||
import com.cloud.network.rules.StaticNatImpl;
|
||||
import com.cloud.network.rules.StaticNatRule;
|
||||
import com.cloud.network.rules.dao.PortForwardingRulesDao;
|
||||
import com.cloud.network.vpn.Site2SiteVpnManager;
|
||||
import com.cloud.offering.ServiceOffering;
|
||||
import com.cloud.offerings.NetworkOfferingVO;
|
||||
import com.cloud.offerings.dao.NetworkOfferingDao;
|
||||
@ -318,6 +326,8 @@ public class VirtualNetworkApplianceManagerImpl implements VirtualNetworkApplian
|
||||
Site2SiteVpnGatewayDao _s2sVpnGatewayDao;
|
||||
@Inject
|
||||
Site2SiteVpnConnectionDao _s2sVpnConnectionDao;
|
||||
@Inject
|
||||
Site2SiteVpnManager _s2sVpnMgr;
|
||||
|
||||
int _routerRamSize;
|
||||
int _routerCpuMHz;
|
||||
@ -901,7 +911,79 @@ public class VirtualNetworkApplianceManagerImpl implements VirtualNetworkApplian
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected void updateSite2SiteVpnConnectionState(List<DomainRouterVO> routers) {
|
||||
for (DomainRouterVO router : routers) {
|
||||
List<Site2SiteVpnConnectionVO> conns = _s2sVpnMgr.getConnectionsForRouter(router);
|
||||
if (conns == null || conns.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
if (router.getState() != State.Running) {
|
||||
for (Site2SiteVpnConnectionVO conn : conns) {
|
||||
conn.setState(Site2SiteVpnConnection.State.Disconnected);
|
||||
_s2sVpnConnectionDao.persist(conn);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
List<String> ipList = new ArrayList<String>();
|
||||
for (Site2SiteVpnConnectionVO conn : conns) {
|
||||
if (conn.getState() != Site2SiteVpnConnection.State.Connected &&
|
||||
conn.getState() != Site2SiteVpnConnection.State.Disconnected) {
|
||||
continue;
|
||||
}
|
||||
Site2SiteCustomerGateway gw = _s2sCustomerGatewayDao.findById(conn.getCustomerGatewayId());
|
||||
ipList.add(gw.getGatewayIp());
|
||||
}
|
||||
String privateIP = router.getPrivateIpAddress();
|
||||
HostVO host = _hostDao.findById(router.getHostId());
|
||||
if (host == null || host.getStatus() != Status.Up) {
|
||||
continue;
|
||||
} else if (host.getManagementServerId() != ManagementServerNode.getManagementServerId()) {
|
||||
/* Only cover hosts managed by this management server */
|
||||
continue;
|
||||
} else if (privateIP != null) {
|
||||
final CheckS2SVpnConnectionsCommand command = new CheckS2SVpnConnectionsCommand(ipList);
|
||||
command.setAccessDetail(NetworkElementCommand.ROUTER_IP, getRouterControlIp(router.getId()));
|
||||
command.setAccessDetail(NetworkElementCommand.ROUTER_NAME, router.getInstanceName());
|
||||
command.setWait(30);
|
||||
final Answer origAnswer = _agentMgr.easySend(router.getHostId(), command);
|
||||
CheckS2SVpnConnectionsAnswer answer = null;
|
||||
if (origAnswer instanceof CheckS2SVpnConnectionsAnswer) {
|
||||
answer = (CheckS2SVpnConnectionsAnswer)origAnswer;
|
||||
} else {
|
||||
s_logger.warn("Unable to update router " + router.getHostName() + "'s VPN connection status");
|
||||
continue;
|
||||
}
|
||||
if (!answer.getResult()) {
|
||||
s_logger.warn("Unable to update router " + router.getHostName() + "'s VPN connection status");
|
||||
continue;
|
||||
}
|
||||
for (Site2SiteVpnConnectionVO conn : conns) {
|
||||
if (conn.getState() != Site2SiteVpnConnection.State.Connected &&
|
||||
conn.getState() != Site2SiteVpnConnection.State.Disconnected) {
|
||||
continue;
|
||||
}
|
||||
Site2SiteVpnConnection.State oldState = conn.getState();
|
||||
Site2SiteCustomerGateway gw = _s2sCustomerGatewayDao.findById(conn.getCustomerGatewayId());
|
||||
if (answer.isConnected(gw.getGatewayIp())) {
|
||||
conn.setState(Site2SiteVpnConnection.State.Connected);
|
||||
} else {
|
||||
conn.setState(Site2SiteVpnConnection.State.Disconnected);
|
||||
}
|
||||
_s2sVpnConnectionDao.persist(conn);
|
||||
if (oldState != conn.getState()) {
|
||||
String title = "Site-to-site Vpn Connection to " + gw.getName() +
|
||||
" just switch from " + oldState + " to " + conn.getState();
|
||||
String context = "Site-to-site Vpn Connection to " + gw.getName() + " on router " + router.getHostName() +
|
||||
"(id: " + router.getId() + ") " + " just switch from " + oldState + " to " + conn.getState();
|
||||
s_logger.info(context);
|
||||
_alertMgr.sendAlert(AlertManager.ALERT_TYPE_DOMAIN_ROUTER,
|
||||
router.getDataCenterIdToDeployIn(), router.getPodIdToDeployIn(), title, context);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void updateRoutersRedundantState(List<DomainRouterVO> routers) {
|
||||
boolean updated = false;
|
||||
for (DomainRouterVO router : routers) {
|
||||
@ -1094,6 +1176,7 @@ public class VirtualNetworkApplianceManagerImpl implements VirtualNetworkApplian
|
||||
s_logger.debug("Found " + routers.size() + " routers. ");
|
||||
|
||||
updateRoutersRedundantState(routers);
|
||||
updateSite2SiteVpnConnectionState(routers);
|
||||
|
||||
/* FIXME assumed the a pair of redundant routers managed by same mgmt server,
|
||||
* then the update above can get the latest status */
|
||||
|
||||
@ -1,7 +1,13 @@
|
||||
package com.cloud.network.vpn;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.cloud.network.Site2SiteVpnConnectionVO;
|
||||
import com.cloud.vm.DomainRouterVO;
|
||||
|
||||
public interface Site2SiteVpnManager extends Site2SiteVpnService {
|
||||
boolean cleanupVpnConnectionByVpc(long vpcId);
|
||||
boolean cleanupVpnGatewayByVpc(long vpcId);
|
||||
void markDisconnectVpnConnByVpc(long vpcId);
|
||||
List<Site2SiteVpnConnectionVO> getConnectionsForRouter(DomainRouterVO router);
|
||||
}
|
||||
|
||||
@ -60,6 +60,7 @@ 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;
|
||||
|
||||
@Local(value = { Site2SiteVpnManager.class, Site2SiteVpnService.class } )
|
||||
public class Site2SiteVpnManagerImpl implements Site2SiteVpnManager, Manager {
|
||||
@ -591,4 +592,16 @@ public class Site2SiteVpnManagerImpl implements Site2SiteVpnManager, Manager {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user