Commit 2bc4f92c authored by wutu's avatar wutu

网络拓扑动态调整功能已完成

parent 8ea4e48b
......@@ -198,4 +198,15 @@ public class IndexController {
String res = clusterService.adjustCluster(clusterConfig);
return res;
}
@RequestMapping(value = "/adjustClusterTopo")
public String adjustClusterTopo(long clusterId, long topologyId, String[] appNames, String topology) {
// 创建集群id
NetworkTopology topo = new NetworkTopology();
topo.setAppNames(appNames);
topo.setTopologyId(111);
topo.setTopology(parseString(topology));
String res = topologyService.modifyTopology(clusterId, topo);
return res;
}
}
\ No newline at end of file
......@@ -24,4 +24,7 @@ public interface TopologyService {
NetworkTopology getTopology(Long clusterId);
void createLinkForNewer(Long clusterId, String appName, String containerId);
// 调整网络拓扑,这里限定条件为,网络节点不改变
String modifyTopology(long clusterId, NetworkTopology topology);
}
......@@ -359,4 +359,6 @@ public class ClusterServiceImpl implements ClusterService {
return osUtils.memoryUsage(containerId) + "%";
}
// TODO: 动态添加新节点到服务中,可以考虑这种实现,但是感觉不太现实,集群启动了,其中的服务应该是固定了的,添加新的节点也很难使用
// 但是也可能存在一种情况,根据节点情况,启动不同的服务,也有存在的道理。
}
\ No newline at end of file
......@@ -232,4 +232,130 @@ public class TopologyServiceImpl implements TopologyService {
}
}
}
// 调整网络拓扑,这里限定条件为,网络节点不改变
@Override
public String modifyTopology(long clusterId, NetworkTopology topology) {
// 先进行校验
if(topology == null) {
return "topoloy不能为空";
}
// 获取clusterId的网络拓扑
if(!clustersTopo.containsKey(clusterId)) {
return "该集群没有设置topo";
}
NetworkTopology origTopo = clustersTopo.get(clusterId);
// 校验topoId是否一致
if(origTopo.getTopologyId() != topology.getTopologyId()) {
return "不是相同的网络拓扑,无法更改";
}
// 校验成员名称是否相同
for (int i = 0; i < origTopo.getAppNames().length; i++) {
if(!origTopo.getAppNames()[i].equals(topology.getAppNames()[i])) {
return "App名称必须一致";
}
}
int[][] origTopoArr = origTopo.getTopology();
int[][] newTopoArr = topology.getTopology();
// 校验topo是否一致
if((origTopoArr.length != newTopoArr.length)
|| (origTopoArr[0].length != newTopoArr[0].length)) {
return "拓扑大小不一致";
}
// 更新网络拓扑,目前只校验下三角
for (int i = 1; i < newTopoArr.length; i++) {
for (int j = 0; j < i; j++) {
if(origTopoArr[i][j] == 0 && newTopoArr[i][j] == 1) {
// 创建新的连接
addLink(clusterId, origTopo.getAppNames()[i], origTopo.getAppNames()[j]);
}
else if(origTopoArr[i][j] == 1 && newTopoArr[i][j] == 0) {
// 删除旧的连接
delLink(clusterId, origTopo.getAppNames()[i], origTopo.getAppNames()[j]);
}
}
}
clustersTopo.put(clusterId, topology);
return "success";
}
/**
* 删除两个节点之间的连接
* @param clusterId
* @param appName1
* @param appName2
*/
public void delLink(long clusterId, String appName1, String appName2) {
int flag = 0;
// 校验 参数是否合法
// step1: 判断appNames中是否存在ovs虚拟交换机
if(appName1.startsWith("br:")) {
// flag计数器加1
flag++;
}
if(appName2.startsWith("br:")) {
flag++;
}
// 如果两个都是虚拟交换机,则需要创建交换机连接
if(flag == 2) {
// 校验是否是远端的交换机
// 远端交换机输入样例:br:remote:testBr:192.168.31.111
String remoteIp1 = "";
if (appName1.contains("remote")) {
remoteIp1 = appName1.split(":")[3];
}
String remoteIp2 = "";
if (appName2.contains("remote")) {
remoteIp2 = appName2.split(":")[3];
}
// 两个都是本地交换机
if ("".equals(remoteIp1) && "".equals(remoteIp2)) {
// 删除两个交换机之间的连接
ovsService.delOvs(appName1.substring(3), appName2.substring(3));
}
// 如果两个都是远程交换机
else if (!"".equals(remoteIp1) && !"".equals(remoteIp2)) {
// do nothing
}
// 如果其中之一是本地交换机,找到本地交换机,设置远端ip
else {
if ("".equals(remoteIp1)) {
// appName2是远程的
ovsService.delVxlan(appName1.substring(3));
} else if ("".equals(remoteIp2)) {
// appName1是远程的
ovsService.delVxlan(appName2.substring(3));
}
}
}
// 如果其中一个是虚拟交换机,则创建虚拟交换机到容器的连接
else if(flag == 1) {
String ovsName = appName1.startsWith("br:") ? appName1.substring(3) : appName2.substring(3);
String containerName = appName1.startsWith("br:") ? appName2 : appName1;
// 使用ovsDocker删除端口
// 获取全部的APP容器id
Set<String> cids = clusterService.getContainerIdsByClusterId(clusterId, containerName);
cids.forEach( cid -> {
// 获取ip,理论上应该在将该ip放入ip池中
// TODO: 网段应该是和网络拓扑绑定到一起,需要重新进行设计
// String ip = ipService.assignIpString("10.10.1.0/24", cid);
ovsDockerService.delPort(ovsName, "eth1", cid);
});
}
// TODO: 如果两个都是容器,这里可以配置逻辑连接
else {
throw new RuntimeException("Physical topology does not support c2c link.");
}
}
}
......@@ -15,7 +15,12 @@ public interface OVSService {
boolean linkOvs(String br1, String br2);
boolean delOvs(String br1, String br2);
boolean setVxlan(String bridgeName, String remoteIp);
// TODO: 这里边的vxlan端口都设置为了vxlan0
boolean delVxlan(String bridgeName);
boolean delBridgePort(String bridgeName, String portName);
}
......@@ -9,6 +9,8 @@ import java.util.Set;
public interface OvsDockerService {
String addPort(String bridgeName, String devName, String containerId, String ip);
boolean delPort(String bridgeName, String devName, String containerId);
Set<String> getContainerPorts(String containerId);
void deleteContainerPorts(String containerId);
......
......@@ -177,6 +177,24 @@ public class OVSServiceImpl implements OVSService, InitializingBean {
return b && b1 && b2;
}
@Override
public boolean delOvs(String br1, String br2) {
if(!ovsBridges.containsKey(br1) || !ovsBridges.containsKey(br2)) {
LOG.error("ovs bridge[" + br1, ", " + br2 + "]不存在");
return false;
}
String[] vethPair = {br1 + "_" + br2, br2 + "_" + br1};
// 删除ovs上的虚拟网卡
boolean b = ovsUtils.delBridgePort(br1, vethPair[0]);
boolean b1 = ovsUtils.delBridgePort(br2, vethPair[1]);
// 删除虚拟网卡对
boolean b2 = ovsUtils.delVethPort(vethPair);
return b1 && b2 && b;
}
/**
* 设置VxLan
* @param bridgeName
......@@ -193,6 +211,16 @@ public class OVSServiceImpl implements OVSService, InitializingBean {
return ovsUtils.setVxlan(bridgeName, remoteIp);
}
// TODO: 这里边的vxlan端口都设置为了vxlan0
@Override
public boolean delVxlan(String bridgeName) {
if(!isBridge(bridgeName)) {
LOG.warn("bridge[" + bridgeName + "] 不存在");
return false;
}
return ovsUtils.delBridgePort(bridgeName, "vxlan0");
}
/**
* 删除ovs port
* @param bridgeName
......
......@@ -46,6 +46,28 @@ public class OvsDockerServiceImpl implements OvsDockerService {
return portId;
}
/**
* 删除docker的虚拟网卡
* @param bridgeName
* @param devName
* @param containerId
* @return
*/
@Override
public boolean delPort(String bridgeName, String devName, String containerId) {
if(!ovsService.isBridge(bridgeName)) {
throw new RuntimeException("网桥[" + bridgeName + "]不存在!");
}
if(!dockerService.hasRunningContainer(containerId)) {
throw new RuntimeException("容器[" + containerId + "]不存在");
}
String res = ovsDockerUtils.delPort(bridgeName, devName, containerId);
if("".equals(res)) {
return true;
}
return false;
}
/**
* 获取docker的ovs网络端口
* @param containerId
......
......@@ -7,4 +7,6 @@ package top.ninwoo.utils.util;
*/
public interface OvsDockerUtils {
String addPort(String bridgeName, String devName, String containerId, String ip);
String delPort(String bridgeName, String devName, String containerId);
}
......@@ -63,9 +63,12 @@ public interface OvsUtils {
String[] createVethPair(String br1, String br2);
boolean delVethPort(String[] veths);
boolean enableLinuxPort(String port);
boolean enableLinuxPort(String[] ports);
boolean setVxlan(String bridgeName, String remoteIp);
}
......@@ -16,12 +16,22 @@ public class OvsDockerUtilsImpl implements OvsDockerUtils {
LinuxCtlUtils linuxCtlUtils;
@Override
public String addPort(String bridgeName, String devName,String containerId, String ip) {
String cmd = "echo 'Vudo3423' | sudo -S ovs-docker add-port " + bridgeName + " " + devName + " " + containerId + " --ipaddress=" + ip;
public String addPort(String bridgeName, String devName,
String containerId, String ip) {
String cmd = "echo 'Vudo3423' | sudo -S ovs-docker add-port " + bridgeName
+ " " + devName + " " + containerId + " --ipaddress=" + ip;
String res = linuxCtlUtils.runCmd(cmd);
if(res.contains("Error")) {
throw new RuntimeException(res);
}
return res;
}
@Override
public String delPort(String bridgeName, String devName, String containerId) {
String cmd = "echo 'Vudo3423' | sudo -S ovs-docker del-port " + bridgeName + " "
+ devName + " " + containerId;
return linuxCtlUtils.runCmd(cmd);
}
}
......@@ -209,6 +209,26 @@ public class OvsUtilsImpl implements OvsUtils {
return new String[]{veth1, veth2};
}
/**
* 删除veth对
* @param veths
* @return
*/
@Override
public boolean delVethPort(String[] veths) {
String veth1 = veths[0];
String veth2 = veths[1];
String cmd = "echo 'Vudo3423' | sudo -S ip link del " + veth1 + " type veth peer name " + veth2;
String res = linuxCtlUtils.runCmd(cmd);
if(!"".equals(res)) {
LOG.warn("delVethPair:[" + veth1 + "," + veth2 + "]:" + res);
return false;
}
return true;
}
/**
* 启动虚拟网卡
* @param port
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment