mirror of
https://gitee.com/dromara/Jpom.git
synced 2024-12-02 20:08:40 +08:00
feat(add) 新增 docker swarm 集群管理
This commit is contained in:
parent
273011c210
commit
2e1e4aaaf4
@ -7,6 +7,8 @@
|
||||
1. nginx 删除操作新增还原配置
|
||||
2. 【server】新增用户登录日志记录
|
||||
3. 【server】log view 新增正则参考
|
||||
4. 【server】docker 控制台新增 docker 信息查看
|
||||
5. 【server】新增 docker swarm 集群管理
|
||||
|
||||
### 🐞 解决BUG、优化功能
|
||||
|
||||
|
@ -275,11 +275,7 @@ public class DockerInfoController extends BaseServerController {
|
||||
parameter.put("force", true);
|
||||
plugin.execute("leaveSwarm", parameter, JSONObject.class);
|
||||
//
|
||||
DockerInfoModel update = new DockerInfoModel();
|
||||
update.setId(id);
|
||||
update.setSwarmId(StrUtil.EMPTY);
|
||||
update.setSwarmNodeId(StrUtil.EMPTY);
|
||||
dockerInfoService.update(update);
|
||||
dockerInfoService.unbind(id);
|
||||
return new JsonMessage<>(200, "强制解绑成功");
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,6 @@ package io.jpom.controller.docker;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.db.Entity;
|
||||
import cn.jiangzeyin.common.JsonMessage;
|
||||
@ -25,7 +24,10 @@ import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.*;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
@ -104,7 +106,7 @@ public class DockerSwarmInfoController extends BaseServerController {
|
||||
DockerSwarmInfoMode dockerSwarmInfoMode = infoModeBuilder.build();
|
||||
consumer.accept(dockerSwarmInfoMode);
|
||||
// 更新 docker id
|
||||
this.bindDockerSwarm(dockerInfoModel1, tag, null, id);
|
||||
dockerInfoService.bindDockerSwarm(dockerInfoModel1, tag, null, id);
|
||||
}
|
||||
|
||||
private void check(String id, String swarmId) {
|
||||
@ -144,26 +146,6 @@ public class DockerSwarmInfoController extends BaseServerController {
|
||||
return JsonMessage.getString(200, "修改成功");
|
||||
}
|
||||
|
||||
private void bindDockerSwarm(DockerInfoModel joinSwarmDocker, String tag, JSONObject swarm, String swarmId) {
|
||||
DockerInfoModel dockerInfoModel = new DockerInfoModel();
|
||||
dockerInfoModel.setSwarmId(swarmId);
|
||||
//
|
||||
if (swarm != null) {
|
||||
String swarmNodeId = swarm.getString("nodeID");
|
||||
dockerInfoModel.setSwarmNodeId(swarmNodeId);
|
||||
}
|
||||
dockerInfoModel.setId(joinSwarmDocker.getId());
|
||||
String tags = joinSwarmDocker.getTags();
|
||||
// 处理标签
|
||||
List<String> allTag = StrUtil.splitTrim(tags, StrUtil.COMMA);
|
||||
allTag = ObjectUtil.defaultIfNull(allTag, new ArrayList<>());
|
||||
if (!allTag.contains(tag)) {
|
||||
allTag.add(tag);
|
||||
}
|
||||
dockerInfoModel.setTags(CollUtil.join(allTag, StrUtil.COMMA));
|
||||
dockerInfoService.update(dockerInfoModel);
|
||||
}
|
||||
|
||||
/**
|
||||
* 加入集群
|
||||
*
|
||||
@ -210,7 +192,7 @@ public class DockerSwarmInfoController extends BaseServerController {
|
||||
Assert.state(optional.isPresent(), "当前 docker 已经加入到其他集群啦");
|
||||
// 绑定数据
|
||||
String managerId = managerSwarmInfo.getString("id");
|
||||
this.bindDockerSwarm(joinSwarmDocker, swarmInfoMode1.getTag(), swarm, managerId);
|
||||
dockerInfoService.bindDockerSwarm(joinSwarmDocker, swarmInfoMode1.getTag(), swarm, managerId);
|
||||
return JsonMessage.getString(200, "集群绑定成功");
|
||||
}
|
||||
}
|
||||
@ -231,7 +213,7 @@ public class DockerSwarmInfoController extends BaseServerController {
|
||||
JSONObject swarm = info.getJSONObject("swarm");
|
||||
Assert.notNull(swarm, "获取 docker 集群信息失败:-1");
|
||||
String managerId = managerSwarmInfo.getString("id");
|
||||
this.bindDockerSwarm(joinSwarmDocker, swarmInfoMode1.getTag(), swarm, managerId);
|
||||
dockerInfoService.bindDockerSwarm(joinSwarmDocker, swarmInfoMode1.getTag(), swarm, managerId);
|
||||
return JsonMessage.getString(200, "集群创建成功");
|
||||
}
|
||||
|
||||
@ -265,14 +247,9 @@ public class DockerSwarmInfoController extends BaseServerController {
|
||||
public JsonMessage<List<JSONObject>> nodeList(
|
||||
@ValidatorItem String id,
|
||||
String nodeId, String nodeName, String nodeRole) throws Exception {
|
||||
HttpServletRequest request = getRequest();
|
||||
DockerSwarmInfoMode swarmInfoMode1 = dockerSwarmInfoService.getByKey(id, request);
|
||||
Assert.notNull(swarmInfoMode1, "没有对应的集群");
|
||||
DockerInfoModel managerSwarmDocker = dockerInfoService.getByKey(swarmInfoMode1.getDockerId(), request);
|
||||
Assert.notNull(managerSwarmDocker, "对应的 docker 不存在");
|
||||
//
|
||||
IPlugin plugin = PluginFactory.getPlugin(DockerSwarmInfoService.DOCKER_PLUGIN_NAME);
|
||||
Map<String, Object> map = managerSwarmDocker.toParameter();
|
||||
Map<String, Object> map = this.getPluginMap(id);
|
||||
map.put("id", nodeId);
|
||||
map.put("name", nodeName);
|
||||
map.put("role", nodeRole);
|
||||
@ -280,19 +257,65 @@ public class DockerSwarmInfoController extends BaseServerController {
|
||||
return new JsonMessage<>(200, "", listSwarmNodes);
|
||||
}
|
||||
|
||||
private Map<String, Object> getPluginMap(String id) {
|
||||
HttpServletRequest request = getRequest();
|
||||
DockerSwarmInfoMode swarmInfoMode1 = dockerSwarmInfoService.getByKey(id, request);
|
||||
Assert.notNull(swarmInfoMode1, "没有对应的集群");
|
||||
//
|
||||
DockerInfoModel managerSwarmDocker = dockerInfoService.getByKey(swarmInfoMode1.getDockerId(), request);
|
||||
Assert.notNull(managerSwarmDocker, "对应的 docker 不存在");
|
||||
return managerSwarmDocker.toParameter();
|
||||
}
|
||||
|
||||
// /**
|
||||
// * 退出集群
|
||||
// *
|
||||
// * @param id 集群ID
|
||||
// * @return json
|
||||
// */
|
||||
// @GetMapping(value = "leave", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
// @Feature(method = MethodFeature.DEL)
|
||||
// public JsonMessage<String> leave(@ValidatorItem String id) {
|
||||
// HttpServletRequest request = getRequest();
|
||||
// DockerSwarmInfoMode swarmInfoMode1 = dockerSwarmInfoService.getByKey(id, request);
|
||||
// Assert.notNull(swarmInfoMode1, "没有对应的集群");
|
||||
// return new JsonMessage<>(200, "解绑成功");
|
||||
// }
|
||||
/**
|
||||
* 修改节点信息
|
||||
*
|
||||
* @param id 集群ID
|
||||
* @return json
|
||||
*/
|
||||
@PostMapping(value = "update", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Feature(method = MethodFeature.EXECUTE)
|
||||
public JsonMessage<String> update(@ValidatorItem String id, @ValidatorItem String nodeId, @ValidatorItem String availability, @ValidatorItem String role) throws Exception {
|
||||
//
|
||||
IPlugin plugin = PluginFactory.getPlugin(DockerSwarmInfoService.DOCKER_PLUGIN_NAME);
|
||||
Map<String, Object> map = this.getPluginMap(id);
|
||||
map.put("nodeId", nodeId);
|
||||
map.put("availability", availability);
|
||||
map.put("role", role);
|
||||
plugin.execute("updateSwarmNode", map);
|
||||
return new JsonMessage<>(200, "解绑成功");
|
||||
}
|
||||
|
||||
/**
|
||||
* 退出集群
|
||||
*
|
||||
* @param id 集群ID
|
||||
* @return json
|
||||
*/
|
||||
@GetMapping(value = "leave", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Feature(method = MethodFeature.DEL)
|
||||
public JsonMessage<String> leave(@ValidatorItem String id, @ValidatorItem String nodeId) throws Exception {
|
||||
//
|
||||
IPlugin plugin = PluginFactory.getPlugin(DockerSwarmInfoService.DOCKER_PLUGIN_NAME);
|
||||
// 查询节点信息
|
||||
DockerInfoModel dockerInfoModel = new DockerInfoModel();
|
||||
dockerInfoModel.setSwarmNodeId(nodeId);
|
||||
List<DockerInfoModel> dockerInfoModels = dockerInfoService.queryList(dockerInfoModel, 2);
|
||||
Assert.state(CollUtil.size(dockerInfoModels) == 1, "当前节点未在系统中绑定或者绑定信息异常,不能操作");
|
||||
//
|
||||
{
|
||||
DockerInfoModel dockerInfoModel1 = CollUtil.getFirst(dockerInfoModels);
|
||||
Map<String, Object> parameter = dockerInfoModel1.toParameter();
|
||||
parameter.put("force", true);
|
||||
plugin.execute("leaveSwarm", parameter, JSONObject.class);
|
||||
}
|
||||
{
|
||||
Map<String, Object> map = this.getPluginMap(id);
|
||||
map.put("nodeId", nodeId);
|
||||
plugin.execute("removeSwarmNode", map);
|
||||
}
|
||||
//
|
||||
dockerInfoService.unbind(id);
|
||||
return new JsonMessage<>(200, "剔除成功");
|
||||
}
|
||||
}
|
||||
|
@ -25,6 +25,7 @@ package io.jpom.service.docker;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.date.SystemClock;
|
||||
import cn.hutool.core.thread.ThreadUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.cron.task.Task;
|
||||
import cn.hutool.db.Entity;
|
||||
@ -40,6 +41,7 @@ import io.jpom.service.h2db.BaseWorkspaceService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@ -181,4 +183,45 @@ public class DockerInfoService extends BaseWorkspaceService<DockerInfoModel> imp
|
||||
String sql = StrUtil.format("SELECT * FROM {} where workspaceId=? and instr(tags,?)", super.getTableName());
|
||||
return (int) super.count(sql, workspaceId, tag);
|
||||
}
|
||||
|
||||
/**
|
||||
* docker 绑定集群
|
||||
*
|
||||
* @param joinSwarmDocker docker
|
||||
* @param tag 标签
|
||||
* @param swarm 集群信息
|
||||
* @param swarmId 集群ID
|
||||
*/
|
||||
public void bindDockerSwarm(DockerInfoModel joinSwarmDocker, String tag, JSONObject swarm, String swarmId) {
|
||||
DockerInfoModel dockerInfoModel = new DockerInfoModel();
|
||||
dockerInfoModel.setSwarmId(swarmId);
|
||||
//
|
||||
if (swarm != null) {
|
||||
String swarmNodeId = swarm.getString("nodeID");
|
||||
dockerInfoModel.setSwarmNodeId(swarmNodeId);
|
||||
}
|
||||
dockerInfoModel.setId(joinSwarmDocker.getId());
|
||||
String tags = joinSwarmDocker.getTags();
|
||||
// 处理标签
|
||||
List<String> allTag = StrUtil.splitTrim(tags, StrUtil.COMMA);
|
||||
allTag = ObjectUtil.defaultIfNull(allTag, new ArrayList<>());
|
||||
if (!allTag.contains(tag)) {
|
||||
allTag.add(tag);
|
||||
}
|
||||
dockerInfoModel.setTags(CollUtil.join(allTag, StrUtil.COMMA));
|
||||
this.update(dockerInfoModel);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解绑集群信息
|
||||
*
|
||||
* @param id docker id
|
||||
*/
|
||||
public void unbind(String id) {
|
||||
DockerInfoModel update = new DockerInfoModel();
|
||||
update.setId(id);
|
||||
update.setSwarmId(StrUtil.EMPTY);
|
||||
update.setSwarmNodeId(StrUtil.EMPTY);
|
||||
this.update(update);
|
||||
}
|
||||
}
|
||||
|
@ -22,20 +22,21 @@
|
||||
*/
|
||||
package io.jpom;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import cn.hutool.core.io.IoUtil;
|
||||
import cn.hutool.core.util.EnumUtil;
|
||||
import cn.hutool.core.util.ReflectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.github.dockerjava.api.DockerClient;
|
||||
import com.github.dockerjava.api.command.JoinSwarmCmd;
|
||||
import com.github.dockerjava.api.command.LeaveSwarmCmd;
|
||||
import com.github.dockerjava.api.command.ListSwarmNodesCmd;
|
||||
import com.github.dockerjava.api.model.Swarm;
|
||||
import com.github.dockerjava.api.model.SwarmNode;
|
||||
import com.github.dockerjava.api.model.SwarmSpec;
|
||||
import com.github.dockerjava.api.command.*;
|
||||
import com.github.dockerjava.api.model.*;
|
||||
import com.github.dockerjava.core.command.RemoveSwarmNodeCmdImpl;
|
||||
import io.jpom.plugin.IDefaultPlugin;
|
||||
import io.jpom.plugin.PluginConfig;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@ -67,12 +68,62 @@ public class DefaultDockerSwarmPluginImpl implements IDefaultPlugin {
|
||||
case "leaveSwarm":
|
||||
this.leaveSwarmCmd(parameter);
|
||||
return null;
|
||||
case "updateSwarmNode":
|
||||
this.updateSwarmNodeCmd(parameter);
|
||||
return null;
|
||||
case "removeSwarmNode":
|
||||
this.removeSwarmNodeCmd(parameter);
|
||||
return null;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void removeSwarmNodeCmd(Map<String, Object> parameter) {
|
||||
DockerClient dockerClient = DockerUtil.build(parameter);
|
||||
try {
|
||||
DockerCmdExecFactory dockerCmdExecFactory = (DockerCmdExecFactory) ReflectUtil.getFieldValue(dockerClient, "dockerCmdExecFactory");
|
||||
Assert.notNull(dockerCmdExecFactory, "当前方法不被支持,暂时不能使用");
|
||||
String nodeId = (String) parameter.get("nodeId");
|
||||
RemoveSwarmNodeCmdImpl removeSwarmNodeCmd = new RemoveSwarmNodeCmdImpl(
|
||||
dockerCmdExecFactory.removeSwarmNodeCmdExec(), nodeId);
|
||||
removeSwarmNodeCmd.withForce(true);
|
||||
removeSwarmNodeCmd.exec();
|
||||
} finally {
|
||||
IoUtil.close(dockerClient);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateSwarmNodeCmd(Map<String, Object> parameter) {
|
||||
DockerClient dockerClient = DockerUtil.build(parameter);
|
||||
try {
|
||||
String nodeId = (String) parameter.get("nodeId");
|
||||
List<SwarmNode> nodes = dockerClient.listSwarmNodesCmd()
|
||||
.withIdFilter(CollUtil.newArrayList(nodeId)).exec();
|
||||
SwarmNode swarmNode = CollUtil.getFirst(nodes);
|
||||
Assert.notNull(swarmNode, "没有对应的节点");
|
||||
ObjectVersion version = swarmNode.getVersion();
|
||||
Assert.notNull(version, "对应的节点信息不完整不能继续");
|
||||
//
|
||||
String availabilityStr = (String) parameter.get("availability");
|
||||
String roleStr = (String) parameter.get("role");
|
||||
//
|
||||
SwarmNodeAvailability availability = EnumUtil.fromString(SwarmNodeAvailability.class, availabilityStr);
|
||||
SwarmNodeRole role = EnumUtil.fromString(SwarmNodeRole.class, roleStr);
|
||||
UpdateSwarmNodeCmd swarmNodeCmd = dockerClient.updateSwarmNodeCmd();
|
||||
swarmNodeCmd.withSwarmNodeId(nodeId);
|
||||
SwarmNodeSpec swarmNodeSpec = new SwarmNodeSpec();
|
||||
swarmNodeSpec.withAvailability(availability);
|
||||
swarmNodeSpec.withRole(role);
|
||||
swarmNodeCmd.withSwarmNodeSpec(swarmNodeSpec);
|
||||
swarmNodeCmd.withVersion(version.getIndex());
|
||||
swarmNodeCmd.exec();
|
||||
} finally {
|
||||
IoUtil.close(dockerClient);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void leaveSwarmCmd(Map<String, Object> parameter) {
|
||||
DockerClient dockerClient = DockerUtil.build(parameter);
|
||||
|
@ -32,10 +32,7 @@ import com.alibaba.fastjson.JSONObject;
|
||||
import com.alibaba.fastjson.serializer.SerializerFeature;
|
||||
import com.github.dockerjava.api.DockerClient;
|
||||
import com.github.dockerjava.api.command.*;
|
||||
import com.github.dockerjava.api.model.Info;
|
||||
import com.github.dockerjava.api.model.Swarm;
|
||||
import com.github.dockerjava.api.model.SwarmNode;
|
||||
import com.github.dockerjava.api.model.SwarmSpec;
|
||||
import com.github.dockerjava.api.model.*;
|
||||
import com.github.dockerjava.core.DefaultDockerClientConfig;
|
||||
import com.github.dockerjava.core.DockerClientConfig;
|
||||
import com.github.dockerjava.core.DockerClientImpl;
|
||||
@ -177,6 +174,28 @@ public class TestSwarm {
|
||||
removeSwarmNodeCmd.exec();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void update() {
|
||||
DockerClient client = this.client(node1);
|
||||
|
||||
|
||||
String nodeId = "rk2gxpql2449t0s1ymtivtyoy";
|
||||
List<SwarmNode> nodes = client.listSwarmNodesCmd().withIdFilter(CollUtil.newArrayList(nodeId)).exec();
|
||||
System.out.println(nodes);
|
||||
SwarmNode swarmNode = CollUtil.getFirst(nodes);
|
||||
UpdateSwarmNodeCmd swarmNodeCmd = client.updateSwarmNodeCmd();
|
||||
|
||||
swarmNodeCmd.withSwarmNodeId(nodeId);
|
||||
SwarmNodeSpec swarmNodeSpec = new SwarmNodeSpec();
|
||||
swarmNodeSpec.withAvailability(SwarmNodeAvailability.PAUSE);
|
||||
swarmNodeSpec.withRole(SwarmNodeRole.WORKER);
|
||||
swarmNodeCmd.withSwarmNodeSpec(swarmNodeSpec);
|
||||
|
||||
swarmNodeCmd.withVersion(swarmNode.getVersion().getIndex());
|
||||
|
||||
swarmNodeCmd.exec();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testJoin() {
|
||||
|
||||
|
@ -69,3 +69,27 @@ export function dockerSwarmNodeList(params) {
|
||||
data: params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 容器集群节点修改
|
||||
* @param {JSON} params
|
||||
*/
|
||||
export function dockerSwarmNodeUpdate(params) {
|
||||
return axios({
|
||||
url: "/docker-swarm/update",
|
||||
method: "post",
|
||||
data: params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 容器集群节点剔除
|
||||
* @param {JSON} params
|
||||
*/
|
||||
export function dockerSwarmNodeLeave(params) {
|
||||
return axios({
|
||||
url: "/docker-swarm/leave",
|
||||
method: "get",
|
||||
params: params,
|
||||
});
|
||||
}
|
||||
|
@ -50,7 +50,7 @@
|
||||
</template>
|
||||
<template v-else>
|
||||
<a-tooltip>
|
||||
<a-tooltip :title="`${parseInt(record.status) !== 1 ? '已经离线' : '已经创建过集群啦'}`">
|
||||
<a-tooltip :title="`${parseInt(record.status) !== 1 ? '已经离线' : '已经在集群啦'}`">
|
||||
<a-button size="small" disabled type="primary">集群</a-button>
|
||||
</a-tooltip>
|
||||
</a-tooltip>
|
||||
@ -140,7 +140,7 @@
|
||||
</a-modal>
|
||||
<!-- 创建集群 -->
|
||||
<a-modal v-model="initSwarmVisible" title="创建 Docker 集群" @ok="handleSwarm" :maskClosable="false">
|
||||
<a-form-model ref="editForm" :rules="rules" :model="temp" :label-col="{ span: 4 }" :wrapper-col="{ span: 18 }">
|
||||
<a-form-model ref="initForm" :rules="rules" :model="temp" :label-col="{ span: 4 }" :wrapper-col="{ span: 18 }">
|
||||
<a-form-model-item label="集群名称" prop="name">
|
||||
<a-input v-model="temp.name" placeholder="容器名称" />
|
||||
</a-form-model-item>
|
||||
@ -150,7 +150,7 @@
|
||||
</a-modal>
|
||||
<!-- 加入集群 -->
|
||||
<a-modal v-model="joinSwarmVisible" title="加入 Docker 集群" @ok="handleSwarmJoin" :maskClosable="false">
|
||||
<a-form-model ref="editForm" :rules="rules" :model="temp" :label-col="{ span: 4 }" :wrapper-col="{ span: 18 }">
|
||||
<a-form-model ref="joinForm" :rules="rules" :model="temp" :label-col="{ span: 4 }" :wrapper-col="{ span: 18 }">
|
||||
<a-form-model-item label="选择集群" prop="swarmId">
|
||||
<a-select
|
||||
show-search
|
||||
@ -416,7 +416,13 @@ export default {
|
||||
},
|
||||
// 强制解绑
|
||||
handleLeaveForce(record) {
|
||||
const html = "<h1 style='color:red;'>真的要强制退出集群吗?</h1><ul style='color:red;'>" + "<li>请提前备份数据再操作奥</li>" + "<li>操作不能撤回奥</li>" + " </ul>";
|
||||
const html =
|
||||
"<h1 style='color:red;'>真的要强制退出集群吗?</h1> " +
|
||||
"<h3 style='color:red;'>如果当前集群还存在可能出现数据不一致问题奥</h3> " +
|
||||
"<ul style='color:red;'>" +
|
||||
"<li>请提前备份数据再操作奥</li>" +
|
||||
"<li>操作不能撤回奥</li>" +
|
||||
" </ul>";
|
||||
const h = this.$createElement;
|
||||
this.$confirm({
|
||||
title: "系统提示",
|
||||
@ -480,7 +486,7 @@ export default {
|
||||
dockerId: record.id,
|
||||
};
|
||||
this.initSwarmVisible = true;
|
||||
this.$refs["editForm"]?.resetFields();
|
||||
this.$refs["initForm"]?.resetFields();
|
||||
},
|
||||
// 加入集群
|
||||
joinSwarm(record) {
|
||||
@ -490,11 +496,11 @@ export default {
|
||||
dockerId: record.id,
|
||||
};
|
||||
this.joinSwarmVisible = true;
|
||||
this.$refs["editForm"]?.resetFields();
|
||||
this.$refs["joinForm"]?.resetFields();
|
||||
});
|
||||
},
|
||||
handleSwarm() {
|
||||
this.$refs["editForm"].validate((valid) => {
|
||||
this.$refs["initForm"].validate((valid) => {
|
||||
if (!valid) {
|
||||
return false;
|
||||
}
|
||||
@ -512,7 +518,7 @@ export default {
|
||||
},
|
||||
// 处理加入集群
|
||||
handleSwarmJoin() {
|
||||
this.$refs["editForm"].validate((valid) => {
|
||||
this.$refs["joinForm"].validate((valid) => {
|
||||
if (!valid) {
|
||||
return false;
|
||||
}
|
||||
|
@ -50,7 +50,7 @@
|
||||
</a-modal>
|
||||
<!-- 节点信息 -->
|
||||
<a-modal v-model="nodeVisible" width="90vw" title="集群节点" :footer="null" :maskClosable="false">
|
||||
<swarm-node :id="this.temp.id" />
|
||||
<swarm-node ref="swarmNode" :id="this.temp.id" />
|
||||
</a-modal>
|
||||
</div>
|
||||
</template>
|
||||
@ -158,6 +158,9 @@ export default {
|
||||
handleNode(record) {
|
||||
this.temp = record;
|
||||
this.nodeVisible = true;
|
||||
this.$nextTick(() => {
|
||||
this.$refs.swarmNode.refreshData();
|
||||
});
|
||||
},
|
||||
// 提交 数据
|
||||
handleEditOk() {
|
||||
@ -183,7 +186,7 @@ export default {
|
||||
handleUnbind(record) {
|
||||
this.$confirm({
|
||||
title: "系统提示",
|
||||
content: "真的要解绑该集群么?解绑至少删除在本系统的关联数据,不会删除容器里面数据",
|
||||
content: "真的要解绑该集群么?解绑只删除在本系统的关联数据,不会删除容器里面数据",
|
||||
okText: "确认",
|
||||
cancelText: "取消",
|
||||
onOk: () => {
|
||||
|
@ -9,30 +9,59 @@
|
||||
<a-select-option key="worker">工作节点</a-select-option>
|
||||
<a-select-option key="manager">管理节点</a-select-option>
|
||||
</a-select>
|
||||
<a-tooltip title="按住 Ctr 或者 Alt 键点击按钮快速回到第一页">
|
||||
<a-button type="primary" @click="loadData" :loading="loading">搜索</a-button>
|
||||
</a-tooltip>
|
||||
|
||||
<a-button type="primary" @click="loadData" :loading="loading">搜索</a-button>
|
||||
</a-space>
|
||||
</template>
|
||||
<a-tooltip slot="tooltip" slot-scope="text" placement="topLeft" :title="text">
|
||||
<span>{{ text }}</span>
|
||||
</a-tooltip>
|
||||
|
||||
<a-tooltip slot="status" slot-scope="text, item" placement="topLeft" :title="text">
|
||||
<a-tag :color="text === 'READY' ? 'green' : text === 'DOWN' ? 'red' : ''">
|
||||
{{ text }}-<template v-if="item.spec">{{ item.spec.role }}</template>
|
||||
<a-tooltip slot="status" slot-scope="text, item" placement="topLeft" :title="`节点状态:${text} 节点可用性:${item.spec ? item.spec.availability || '' : ''}`">
|
||||
<a-tag :color="(item.spec && item.spec.availability) === 'ACTIVE' ? 'green' : 'red'">
|
||||
{{ text }}
|
||||
<template v-if="item.spec">{{ item.spec.availability }}</template>
|
||||
</a-tag>
|
||||
</a-tooltip>
|
||||
<!-- 角色显示 -->
|
||||
<a-tooltip
|
||||
slot="role"
|
||||
slot-scope="text, item"
|
||||
placement="topLeft"
|
||||
:title="`角色:${text} ${item.managerStatus && item.managerStatus.reachability === 'REACHABLE' ? '管理状态:' + item.managerStatus.reachability : ''}`"
|
||||
>
|
||||
<a-tag :color="`${item.managerStatus && item.managerStatus.reachability === 'REACHABLE' ? 'green' : ''}`">
|
||||
{{ text }}
|
||||
</a-tag>
|
||||
</a-tooltip>
|
||||
<a-tooltip slot="address" slot-scope="text, item" placement="topLeft" :title="text">
|
||||
<a-icon v-if="item.managerStatus && item.managerStatus.leader" type="cloud-server" />
|
||||
{{ text }}
|
||||
</a-tooltip>
|
||||
|
||||
<a-tooltip slot="os" slot-scope="text, item" placement="topLeft" :title="text">
|
||||
<span>
|
||||
<a-tag>{{ text }}-{{ item.description && item.description.platform && item.description.platform.architecture }}</a-tag>
|
||||
</span>
|
||||
</a-tooltip>
|
||||
<a-tooltip slot="updatedAt" slot-scope="text, item" placement="topLeft" :title="`修改时间:${text} 创建时间:${item.createdAt}`">
|
||||
<span>
|
||||
<a-tag>{{ text }}</a-tag>
|
||||
</span>
|
||||
</a-tooltip>
|
||||
|
||||
<template slot="operation" slot-scope="text, record">
|
||||
<a-space>
|
||||
<a-button size="small" type="primary" @click="handleEdit(record)">编辑</a-button>
|
||||
<a-dropdown>
|
||||
<template v-if="record.managerStatus && record.managerStatus.leader"> - </template>
|
||||
<template v-else>
|
||||
<a-button size="small" type="primary" @click="handleEdit(record)">修改</a-button>
|
||||
<a-button size="small" type="danger" @click="handleLeava(record)">剔除</a-button>
|
||||
</template>
|
||||
|
||||
<!-- <template v-else>
|
||||
<a-button size="small" type="danger" v-if="!item.managerStatus.leader" @click="handleLeava(record)">剔除</a-button>
|
||||
</template> -->
|
||||
<!-- <a-dropdown>
|
||||
<a class="ant-dropdown-link" @click="(e) => e.preventDefault()"> 更多 <a-icon type="down" /> </a>
|
||||
<a-menu slot="overlay">
|
||||
<a-menu-item> </a-menu-item>
|
||||
@ -40,15 +69,33 @@
|
||||
<a-button size="small" type="danger" @click="handleUnbind(record)">解绑</a-button>
|
||||
</a-menu-item>
|
||||
</a-menu></a-dropdown
|
||||
>
|
||||
> -->
|
||||
</a-space>
|
||||
</template>
|
||||
</a-table>
|
||||
<!-- 编辑节点 -->
|
||||
<a-modal v-model="editVisible" title="编辑节点" @ok="handleEditOk" :maskClosable="false">
|
||||
<a-form-model ref="editForm" :rules="rules" :model="temp" :label-col="{ span: 4 }" :wrapper-col="{ span: 18 }">
|
||||
<a-form-model-item label="角色" prop="role">
|
||||
<a-radio-group name="role" v-model="temp.role">
|
||||
<a-radio value="WORKER"> 工作节点</a-radio>
|
||||
<a-radio value="MANAGER"> 管理节点 </a-radio>
|
||||
</a-radio-group>
|
||||
</a-form-model-item>
|
||||
<a-form-model-item label="状态" prop="availability">
|
||||
<a-radio-group name="availability" v-model="temp.availability">
|
||||
<a-radio value="ACTIVE"> 活跃</a-radio>
|
||||
<a-radio value="PAUSE"> 暂停 </a-radio>
|
||||
<a-radio value="DRAIN"> 排空 </a-radio>
|
||||
</a-radio-group>
|
||||
</a-form-model-item>
|
||||
</a-form-model>
|
||||
</a-modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { editDockerSwarm, dockerSwarmNodeList, unbindSwarm } from "@/api/docker-swarm";
|
||||
import { dockerSwarmNodeList, dockerSwarmNodeLeave, dockerSwarmNodeUpdate } from "@/api/docker-swarm";
|
||||
|
||||
export default {
|
||||
components: {},
|
||||
@ -65,42 +112,51 @@ export default {
|
||||
temp: {},
|
||||
editVisible: false,
|
||||
initSwarmVisible: false,
|
||||
rules: {
|
||||
role: [{ required: true, message: "请选择节点角色", trigger: "blur" }],
|
||||
availability: [{ required: true, message: "请选择节点状态", trigger: "blur" }],
|
||||
},
|
||||
columns: [
|
||||
{ title: "节点Id", dataIndex: "id", ellipsis: true, scopedSlots: { customRender: "tooltip" } },
|
||||
{ title: "节点地址", dataIndex: "status.address", ellipsis: true, scopedSlots: { customRender: "tooltip" } },
|
||||
{ title: "状态", width: 160, align: "center", dataIndex: "status.state", ellipsis: true, scopedSlots: { customRender: "status" } },
|
||||
{ title: "主机名", dataIndex: "description.hostname", ellipsis: true, scopedSlots: { customRender: "tooltip" } },
|
||||
{ title: "系统类型", width: 140, align: "center", dataIndex: "description.platform.os", ellipsis: true, scopedSlots: { customRender: "os" } },
|
||||
{
|
||||
title: "创建时间",
|
||||
dataIndex: "createdAt",
|
||||
{ title: "节点地址", width: 150, dataIndex: "status.address", ellipsis: true, scopedSlots: { customRender: "address" } },
|
||||
{ title: "状态", width: 140, dataIndex: "status.state", ellipsis: true, scopedSlots: { customRender: "status" } },
|
||||
{ title: "角色", width: 110, dataIndex: "spec.role", ellipsis: true, scopedSlots: { customRender: "role" } },
|
||||
|
||||
ellipsis: true,
|
||||
scopedSlots: { customRender: "tooltip" },
|
||||
width: 170,
|
||||
},
|
||||
{ title: "系统类型", width: 140, align: "center", dataIndex: "description.platform.os", ellipsis: true, scopedSlots: { customRender: "os" } },
|
||||
// {
|
||||
// title: "创建时间",
|
||||
// dataIndex: "createdAt",
|
||||
|
||||
// ellipsis: true,
|
||||
// scopedSlots: { customRender: "tooltip" },
|
||||
// width: 170,
|
||||
// },
|
||||
{
|
||||
title: "修改时间",
|
||||
dataIndex: "updatedAt",
|
||||
|
||||
ellipsis: true,
|
||||
scopedSlots: { customRender: "tooltip" },
|
||||
scopedSlots: { customRender: "updatedAt" },
|
||||
width: 170,
|
||||
},
|
||||
{ title: "操作", dataIndex: "operation", scopedSlots: { customRender: "operation" }, align: "center", width: 140 },
|
||||
{ title: "操作", dataIndex: "operation", scopedSlots: { customRender: "operation" }, align: "center", width: 120 },
|
||||
],
|
||||
};
|
||||
},
|
||||
computed: {},
|
||||
mounted() {
|
||||
this.list = [];
|
||||
this.loadData();
|
||||
// this.loadData();
|
||||
},
|
||||
methods: {
|
||||
refreshData() {
|
||||
this.list = [];
|
||||
this.loadData();
|
||||
},
|
||||
// 加载数据
|
||||
loadData(pointerEvent) {
|
||||
loadData() {
|
||||
this.loading = true;
|
||||
this.listQuery.page = pointerEvent?.altKey || pointerEvent?.ctrlKey ? 1 : this.listQuery.page;
|
||||
|
||||
this.listQuery.id = this.id;
|
||||
dockerSwarmNodeList(this.listQuery).then((res) => {
|
||||
if (res.code === 200) {
|
||||
@ -109,22 +165,21 @@ export default {
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
// 修改
|
||||
handleEdit(record) {
|
||||
this.temp = record;
|
||||
this.editVisible = true;
|
||||
|
||||
this.$refs["editForm"]?.resetFields();
|
||||
this.temp = {
|
||||
nodeId: record.id,
|
||||
role: record.spec.role,
|
||||
availability: record.spec.availability,
|
||||
};
|
||||
},
|
||||
// 提交 数据
|
||||
handleEditOk() {
|
||||
// 检验表单
|
||||
this.$refs["editForm"].validate((valid) => {
|
||||
if (!valid) {
|
||||
return false;
|
||||
}
|
||||
|
||||
editDockerSwarm(this.temp).then((res) => {
|
||||
this.temp.id = this.id;
|
||||
dockerSwarmNodeUpdate(this.temp).then((res) => {
|
||||
if (res.code === 200) {
|
||||
// 成功
|
||||
this.$notification.success({
|
||||
@ -137,18 +192,19 @@ export default {
|
||||
});
|
||||
},
|
||||
// 解绑
|
||||
handleUnbind(record) {
|
||||
handleLeava(record) {
|
||||
this.$confirm({
|
||||
title: "系统提示",
|
||||
content: "真的要解绑该集群么?解绑至少删除在本系统的关联数据,不会删除容器里面数据",
|
||||
content: "真的要在该集群剔除此节点么?",
|
||||
okText: "确认",
|
||||
cancelText: "取消",
|
||||
onOk: () => {
|
||||
// 组装参数
|
||||
const params = {
|
||||
id: record.id,
|
||||
nodeId: record.id,
|
||||
id: this.id,
|
||||
};
|
||||
unbindSwarm(params).then((res) => {
|
||||
dockerSwarmNodeLeave(params).then((res) => {
|
||||
if (res.code === 200) {
|
||||
this.$notification.success({
|
||||
message: res.msg,
|
||||
|
Loading…
Reference in New Issue
Block a user