S2S VPN: CS-15650: Add connection status update to s2s vpn

This commit is contained in:
Sheng Yang 2012-07-27 16:18:52 -07:00
parent 786d5995df
commit 8eee8f342e
9 changed files with 251 additions and 5 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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 */

View File

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

View File

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