pre swarm task list

This commit is contained in:
bwcx_jzy 2022-02-14 15:09:24 +08:00
parent 65b7235160
commit f34bdd3124
No known key found for this signature in database
GPG Key ID: 5E48E9372088B9E5
12 changed files with 727 additions and 37 deletions

View File

@ -252,7 +252,7 @@ public class DockerSwarmInfoController extends BaseServerController {
String nodeId, String nodeName, String nodeRole) throws Exception {
//
IPlugin plugin = PluginFactory.getPlugin(DockerSwarmInfoService.DOCKER_PLUGIN_NAME);
Map<String, Object> map = this.getPluginMap(id);
Map<String, Object> map = dockerInfoService.getBySwarmPluginMap(id, getRequest());
map.put("id", nodeId);
map.put("name", nodeName);
map.put("role", nodeRole);
@ -260,15 +260,6 @@ 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();
}
/**
* 修改节点信息
@ -281,7 +272,7 @@ public class DockerSwarmInfoController extends BaseServerController {
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<String, Object> map = dockerInfoService.getBySwarmPluginMap(id, getRequest());
map.put("nodeId", nodeId);
map.put("availability", availability);
map.put("role", role);
@ -313,7 +304,7 @@ public class DockerSwarmInfoController extends BaseServerController {
plugin.execute("leaveSwarm", parameter, JSONObject.class);
}
{
Map<String, Object> map = this.getPluginMap(id);
Map<String, Object> map = dockerInfoService.getBySwarmPluginMap(id, getRequest());
map.put("nodeId", nodeId);
plugin.execute("removeSwarmNode", map);
}

View File

@ -0,0 +1,65 @@
package io.jpom.controller.docker;
import cn.jiangzeyin.common.JsonMessage;
import cn.jiangzeyin.common.validator.ValidatorItem;
import com.alibaba.fastjson.JSONObject;
import io.jpom.common.BaseServerController;
import io.jpom.plugin.*;
import io.jpom.service.docker.DockerInfoService;
import io.jpom.service.docker.DockerSwarmInfoService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
import java.util.Map;
/**
* @author bwcx_jzy
* @since 2022/2/14
*/
@RestController
@Feature(cls = ClassFeature.DOCKER_SWARM)
@RequestMapping(value = "/docker-swarm-service")
@Slf4j
public class DockerSwarmServiceController extends BaseServerController {
private final DockerInfoService dockerInfoService;
public DockerSwarmServiceController(DockerInfoService dockerInfoService) {
this.dockerInfoService = dockerInfoService;
}
@PostMapping(value = "list", produces = MediaType.APPLICATION_JSON_VALUE)
@Feature(method = MethodFeature.LIST)
public JsonMessage<List<JSONObject>> list(
@ValidatorItem String id,
String serviceId, String serviceName) throws Exception {
//
IPlugin plugin = PluginFactory.getPlugin(DockerSwarmInfoService.DOCKER_PLUGIN_NAME);
Map<String, Object> map = dockerInfoService.getBySwarmPluginMap(id, getRequest());
map.put("id", serviceId);
map.put("name", serviceName);
List<JSONObject> listSwarmNodes = (List<JSONObject>) plugin.execute("listServices", map);
return new JsonMessage<>(200, "", listSwarmNodes);
}
@PostMapping(value = "task-list", produces = MediaType.APPLICATION_JSON_VALUE)
@Feature(method = MethodFeature.LIST)
public JsonMessage<List<JSONObject>> taskList(
@ValidatorItem String id,
String serviceId, String taskId, String taskName, String taskNode, String taskState) throws Exception {
//
IPlugin plugin = PluginFactory.getPlugin(DockerSwarmInfoService.DOCKER_PLUGIN_NAME);
Map<String, Object> map = dockerInfoService.getBySwarmPluginMap(id, getRequest());
map.put("id", taskId);
map.put("serviceId", serviceId);
map.put("name", taskName);
map.put("node", taskNode);
map.put("state", taskState);
List<JSONObject> listSwarmNodes = (List<JSONObject>) plugin.execute("listTasks", map);
return new JsonMessage<>(200, "", listSwarmNodes);
}
}

View File

@ -40,7 +40,9 @@ import io.jpom.plugin.PluginFactory;
import io.jpom.service.h2db.BaseWorkspaceService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
@ -249,4 +251,20 @@ public class DockerInfoService extends BaseWorkspaceService<DockerInfoModel> imp
update.setSwarmNodeId(StrUtil.EMPTY);
this.update(update);
}
/**
* 获取集群 docker 信息
*
* @param id 集群ID
* @param request 请求对象
* @return map
*/
public Map<String, Object> getBySwarmPluginMap(String id, HttpServletRequest request) {
DockerSwarmInfoMode swarmInfoMode1 = dockerSwarmInfoService.getByKey(id, request);
Assert.notNull(swarmInfoMode1, "没有对应的集群");
//
DockerInfoModel managerSwarmDocker = this.getByKey(swarmInfoMode1.getDockerId(), request);
Assert.notNull(managerSwarmDocker, "对应的 docker 不存在");
return managerSwarmDocker.toParameter();
}
}

View File

@ -74,12 +74,67 @@ public class DefaultDockerSwarmPluginImpl implements IDefaultPlugin {
case "removeSwarmNode":
this.removeSwarmNodeCmd(parameter);
return null;
case "listServices":
return this.listServicesCmd(parameter);
case "listTasks":
return this.listTasksCmd(parameter);
default:
break;
}
return null;
}
private List<JSONObject> listTasksCmd(Map<String, Object> parameter) {
DockerClient dockerClient = DockerUtil.build(parameter);
try {
ListTasksCmd listTasksCmd = dockerClient.listTasksCmd();
String serviceId = (String) parameter.get("serviceId");
String id = (String) parameter.get("id");
if (StrUtil.isNotEmpty(serviceId)) {
listTasksCmd.withServiceFilter(serviceId);
}
if (StrUtil.isNotEmpty(id)) {
listTasksCmd.withIdFilter(id);
}
String name = (String) parameter.get("name");
if (StrUtil.isNotEmpty(name)) {
listTasksCmd.withNameFilter(name);
}
String node = (String) parameter.get("node");
if (StrUtil.isNotEmpty(node)) {
listTasksCmd.withNodeFilter(node);
}
String state = (String) parameter.get("state");
if (StrUtil.isNotEmpty(state)) {
TaskState taskState = EnumUtil.fromString(TaskState.class, state);
listTasksCmd.withStateFilter(taskState);
}
List<Task> exec = listTasksCmd.exec();
return exec.stream().map(swarmNode -> (JSONObject) JSONObject.toJSON(swarmNode)).collect(Collectors.toList());
} finally {
IoUtil.close(dockerClient);
}
}
public List<JSONObject> listServicesCmd(Map<String, Object> parameter) {
DockerClient dockerClient = DockerUtil.build(parameter);
try {
ListServicesCmd listServicesCmd = dockerClient.listServicesCmd();
String id = (String) parameter.get("id");
String name = (String) parameter.get("name");
if (StrUtil.isNotEmpty(id)) {
listServicesCmd.withIdFilter(CollUtil.newArrayList(id));
}
if (StrUtil.isNotEmpty(name)) {
listServicesCmd.withNameFilter(CollUtil.newArrayList(name));
}
List<Service> exec = listServicesCmd.exec();
return exec.stream().map(swarmNode -> (JSONObject) JSONObject.toJSON(swarmNode)).collect(Collectors.toList());
} finally {
IoUtil.close(dockerClient);
}
}
private void removeSwarmNodeCmd(Map<String, Object> parameter) {
DockerClient dockerClient = DockerUtil.build(parameter);
try {

View File

@ -31,6 +31,7 @@ import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.github.dockerjava.api.DockerClient;
import com.github.dockerjava.api.async.ResultCallback;
import com.github.dockerjava.api.command.*;
import com.github.dockerjava.api.model.*;
import com.github.dockerjava.core.DefaultDockerClientConfig;
@ -47,6 +48,7 @@ import org.junit.Before;
import org.junit.Test;
import org.slf4j.LoggerFactory;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ -205,4 +207,48 @@ public class TestSwarm {
joinSwarmCmd.exec();
}
@Test
public void testService() {
DockerClient client = this.client(node1);
ListServicesCmd listServicesCmd = client.listServicesCmd();
List<Service> exec = listServicesCmd.exec();
JSONArray toJSON = (JSONArray) JSONObject.toJSON(exec);
System.out.println(toJSON.toString());
}
@Test
public void testServiceInspect() {
DockerClient client = this.client(node1);
InspectServiceCmd inspectServiceCmd = client.inspectServiceCmd("esjx0f126tvvicfizymdxymxq");
Service exec = inspectServiceCmd.exec();
System.out.println(exec);
}
@Test
public void testServiceLog() throws InterruptedException {
DockerClient client = this.client(node1);
LogSwarmObjectCmd swarmObjectCmd = client.logServiceCmd("esjx0f126tvvicfizymdxymxq");
swarmObjectCmd.withDetails(true);
swarmObjectCmd.withStderr(true);
swarmObjectCmd.withStdout(true);
swarmObjectCmd.exec(new ResultCallback.Adapter<Frame>() {
@Override
public void onNext(Frame object) {
String s = new String(object.getPayload(), StandardCharsets.UTF_8);
System.out.print(s);
}
}).awaitCompletion();
}
@Test
public void tsetTask() {
DockerClient client = this.client(node1);
ListTasksCmd listTasksCmd = client.listTasksCmd();
listTasksCmd.withServiceFilter("esjx0f126tvvicfizymdxymxq");
List<Task> exec = listTasksCmd.exec();
System.out.println(exec);
}
}

View File

@ -93,3 +93,27 @@ export function dockerSwarmNodeLeave(params) {
params: params,
});
}
/**
* 容器集群服务列表
* @param {JSON} params
*/
export function dockerSwarmServicesList(params) {
return axios({
url: "/docker-swarm-service/list",
method: "post",
data: params,
});
}
/**
* 容器集群服务任务列表
* @param {JSON} params
*/
export function dockerSwarmServicesTaskList(params) {
return axios({
url: "/docker-swarm-service/task-list",
method: "post",
data: params,
});
}

View File

@ -61,9 +61,6 @@ export default {
};
</script>
<style scoped>
.docker-layout {
/* background-color: #fff; */
}
.docker-menu {
height: 100%;
}

View File

@ -0,0 +1,59 @@
<template>
<a-layout class="docker-layout">
<a-layout-sider width="100px" style="min-height: calc(100vh - 85px)">
<a-menu theme="light" mode="inline" class="docker-menu" v-model="menuKeyArray" @click="menuClick">
<a-menu-item key="node">
<span class="nav-text">集群节点</span>
</a-menu-item>
<a-menu-item key="server">
<span class="nav-text">集群服务</span>
</a-menu-item>
<a-menu-item key="task">
<span class="nav-text">集群任务</span>
</a-menu-item>
</a-menu>
</a-layout-sider>
<a-layout class="layout-content">
<a-layout-content>
<swarm-node v-if="menuKey === 'node'" :id="this.id" />
<swarm-service v-if="menuKey === 'server'" :id="this.id" />
<swarm-task v-if="menuKey === 'task'" :id="this.id" />
</a-layout-content>
</a-layout>
</a-layout>
</template>
<script>
import SwarmNode from "./node";
import SwarmService from "./service";
import SwarmTask from "./task";
export default {
props: {
id: {
type: String,
},
},
components: {
SwarmNode,
SwarmService,
SwarmTask,
},
data() {
return {
menuKeyArray: ["node"],
menuKey: "node",
};
},
mounted() {},
methods: {
menuClick(item) {
this.menuKey = item.key;
},
},
};
</script>
<style scoped>
.docker-menu {
height: 100%;
}
</style>

View File

@ -24,12 +24,12 @@
<template slot="operation" slot-scope="text, record">
<a-space>
<a-button size="small" :disabled="parseInt(record.status) !== 1" type="primary" @click="handleNode(record)">节点</a-button>
<a-button size="small" type="primary" @click="handleEdit(record)">编辑</a-button>
<a-button size="small" :disabled="parseInt(record.status) !== 1" type="primary" @click="handleConsole(record)">控制台</a-button>
<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>
<a-menu-item> <a-button size="small" type="primary" @click="handleEdit(record)">编辑</a-button> </a-menu-item>
<a-menu-item>
<a-button size="small" type="danger" @click="handleUnbind(record)">解绑</a-button>
</a-menu-item>
@ -48,10 +48,21 @@
<a-form-model-item label="标签" prop="tag"><a-input v-model="temp.tag" placeholder="关联容器标签" /> </a-form-model-item>
</a-form-model>
</a-modal>
<!-- 节点信息 -->
<a-modal v-model="nodeVisible" width="90vw" title="集群节点" :footer="null" :maskClosable="false">
<swarm-node ref="swarmNode" :id="this.temp.id" />
</a-modal>
<!-- 控制台 -->
<a-drawer
:title="`${temp.name} 控制台`"
placement="right"
:width="`${this.getCollapsed ? 'calc(100vw - 80px)' : 'calc(100vw - 200px)'}`"
:visible="consoleVisible"
@close="
() => {
this.consoleVisible = false;
}
"
>
<console v-if="consoleVisible" :id="temp.id"></console>
</a-drawer>
</div>
</template>
@ -59,11 +70,12 @@
import { PAGE_DEFAULT_LIMIT, PAGE_DEFAULT_SIZW_OPTIONS, PAGE_DEFAULT_SHOW_TOTAL, PAGE_DEFAULT_LIST_QUERY } from "@/utils/const";
import { editDockerSwarm, dockerSwarmList, unbindSwarm } from "@/api/docker-swarm";
import { parseTime } from "@/utils/time";
import SwarmNode from "./node.vue";
import { mapGetters } from "vuex";
import Console from "./console";
export default {
components: {
SwarmNode,
Console,
},
props: {},
data() {
@ -73,7 +85,7 @@ export default {
list: [],
temp: {},
editVisible: false,
nodeVisible: false,
consoleVisible: false,
columns: [
{ title: "名称", dataIndex: "name", ellipsis: true, scopedSlots: { customRender: "tooltip" } },
{ title: "节点地址", dataIndex: "nodeAddr", ellipsis: true, scopedSlots: { customRender: "tooltip" } },
@ -100,7 +112,7 @@ export default {
},
width: 170,
},
{ title: "操作", dataIndex: "operation", scopedSlots: { customRender: "operation" }, align: "center", width: 190 },
{ title: "操作", dataIndex: "operation", scopedSlots: { customRender: "operation" }, align: "center", width: 140 },
],
rules: {
// id: [{ required: true, message: "Please input ID", trigger: "blur" }],
@ -118,6 +130,7 @@ export default {
};
},
computed: {
...mapGetters(["getCollapsed"]),
pagination() {
return {
total: this.listQuery.total,
@ -154,14 +167,12 @@ export default {
this.editVisible = true;
this.$refs["editForm"]?.resetFields();
},
//
handleNode(record) {
//
handleConsole(record) {
this.temp = record;
this.nodeVisible = true;
this.$nextTick(() => {
this.$refs.swarmNode.refreshData();
});
this.consoleVisible = true;
},
//
handleEditOk() {
//

View File

@ -146,13 +146,9 @@ export default {
},
computed: {},
mounted() {
// this.loadData();
this.loadData();
},
methods: {
refreshData() {
this.list = [];
this.loadData();
},
//
loadData() {
this.loading = true;

View File

@ -0,0 +1,204 @@
<template>
<div>
<a-table :data-source="list" size="middle" :columns="columns" bordered :pagination="false" :rowKey="(record, index) => index">
<template slot="title">
<a-space>
<a-input v-model="listQuery['serviceId']" placeholder="id" class="search-input-item" />
<a-input v-model="listQuery['serviceName']" placeholder="名称" class="search-input-item" />
<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} 节点可用性:${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>
<a-tooltip slot="replicas" slot-scope="text, record" placement="topLeft" :title="text" @click="handleTask(record)">
<a-tag>{{ text }}</a-tag>
</a-tooltip>
<!-- <template slot="operation" slot-scope="text, record">
<a-space>
<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>
</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>
<!-- 查看任务 -->
<a-modal v-model="taskVisible" title="查看任务" width="80vw" :footer="null" :maskClosable="false">
<swarm-task v-if="taskVisible" :id="this.id" :serviceId="this.temp.id" />
</a-modal>
</div>
</template>
<script>
import { dockerSwarmServicesList, dockerSwarmNodeLeave, dockerSwarmNodeUpdate } from "@/api/docker-swarm";
import SwarmTask from "./task";
export default {
components: { SwarmTask },
props: {
id: {
type: String,
},
},
data() {
return {
loading: false,
listQuery: {},
list: [],
temp: {},
editVisible: false,
initSwarmVisible: false,
taskVisible: 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: "spec.name", ellipsis: true, scopedSlots: { customRender: "tooltip" } },
{ title: "模式", dataIndex: "spec.mode.mode", ellipsis: true, width: 120, scopedSlots: { customRender: "tooltip" } },
{ title: "副本数", dataIndex: "spec.mode.replicated.replicas", width: 90, ellipsis: true, scopedSlots: { customRender: "replicas" } },
{ title: "端点", dataIndex: "spec.endpointSpec.mode", ellipsis: true, width: 100, scopedSlots: { customRender: "tooltip" } },
{
title: "修改时间",
dataIndex: "updatedAt",
ellipsis: true,
scopedSlots: { customRender: "updatedAt" },
width: 170,
},
{ title: "操作", dataIndex: "operation", scopedSlots: { customRender: "operation" }, align: "center", width: 120 },
],
};
},
computed: {},
mounted() {
this.loadData();
},
methods: {
//
loadData() {
this.loading = true;
this.listQuery.id = this.id;
dockerSwarmServicesList(this.listQuery).then((res) => {
if (res.code === 200) {
this.list = res.data;
}
this.loading = false;
});
},
//
handleTask(record) {
this.taskVisible = true;
this.temp = record;
},
handleEdit(record) {
this.editVisible = true;
this.temp = {
nodeId: record.id,
role: record.spec.role,
availability: record.spec.availability,
};
},
handleEditOk() {
this.$refs["editForm"].validate((valid) => {
if (!valid) {
return false;
}
this.temp.id = this.id;
dockerSwarmNodeUpdate(this.temp).then((res) => {
if (res.code === 200) {
//
this.$notification.success({
message: res.msg,
});
this.editVisible = false;
this.loadData();
}
});
});
},
//
handleLeava(record) {
this.$confirm({
title: "系统提示",
content: "真的要在该集群剔除此节点么?",
okText: "确认",
cancelText: "取消",
onOk: () => {
//
const params = {
nodeId: record.id,
id: this.id,
};
dockerSwarmNodeLeave(params).then((res) => {
if (res.code === 200) {
this.$notification.success({
message: res.msg,
});
this.loadData();
}
});
},
});
},
},
};
</script>

View File

@ -0,0 +1,224 @@
<template>
<div>
<a-table :data-source="list" size="middle" :columns="columns" bordered :pagination="false" :rowKey="(record, index) => index">
<template slot="title">
<a-space>
<a-input v-model="listQuery['serviceId']" v-if="!this.serviceId" placeholder="服务id" class="search-input-item" />
<a-input v-model="listQuery['taskName']" placeholder="任务名称" class="search-input-item" />
<a-input v-model="listQuery['taskId']" placeholder="任务id" class="search-input-item" />
<a-input v-model="listQuery['taskNode']" placeholder="节点id" class="search-input-item" />
<a-select show-search option-filter-prop="children" v-model="listQuery['taskState']" allowClear placeholder="状态" class="search-input-item">
<a-select-option key="NEW">新任务</a-select-option>
<a-select-option key="ALLOCATED">已分配</a-select-option>
<a-select-option key="PENDING">未决定</a-select-option>
<a-select-option key="ASSIGNED">已指定</a-select-option>
<a-select-option key="ACCEPTED">公认</a-select-option>
<a-select-option key="PREPARING">准备中</a-select-option>
<a-select-option key="READY">准备</a-select-option>
<a-select-option key="STARTING">开始</a-select-option>
<a-select-option key="RUNNING">运行中</a-select-option>
<a-select-option key="COMPLETE">完成</a-select-option>
<a-select-option key="SHUTDOWN">关闭</a-select-option>
<a-select-option key="FAILED">失败</a-select-option>
<a-select-option key="REJECTED">拒绝</a-select-option>
<a-select-option key="REMOVE">消除</a-select-option>
<a-select-option key="ORPHANED">孤儿</a-select-option>
</a-select>
<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} 节点可用性:${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>
{{ text }}
</span>
</a-tooltip>
<!-- <template slot="operation" slot-scope="text, record">
<a-space>
<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>
</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 { dockerSwarmServicesTaskList, dockerSwarmNodeLeave, dockerSwarmNodeUpdate } from "@/api/docker-swarm";
export default {
components: {},
props: {
id: {
type: String,
},
serviceId: { type: String },
},
data() {
return {
loading: false,
listQuery: {},
list: [],
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: "节点Id", dataIndex: "nodeId", ellipsis: true, scopedSlots: { customRender: "tooltip" } },
{ title: "服务ID", dataIndex: "serviceId", ellipsis: true, scopedSlots: { customRender: "tooltip" } },
{ title: "镜像", dataIndex: "spec.containerSpec.image", ellipsis: true, width: 120, scopedSlots: { customRender: "tooltip" } },
// { title: "", dataIndex: "spec.mode.replicated.replicas", width: 90, ellipsis: true, scopedSlots: { customRender: "tooltip" } },
// { title: "", dataIndex: "spec.endpointSpec.mode", ellipsis: true, width: 100, scopedSlots: { customRender: "tooltip" } },
// { title: "", width: 150, dataIndex: "status.address", ellipsis: true, scopedSlots: { customRender: "address" } },
{ title: "状态", width: 140, dataIndex: "desiredState", ellipsis: true, scopedSlots: { customRender: "tooltip" } },
{ title: "slot", width: 50, dataIndex: "slot", ellipsis: true, scopedSlots: { customRender: "tooltip" } },
// { 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: "updatedAt" },
width: 180,
},
{ title: "操作", dataIndex: "operation", scopedSlots: { customRender: "operation" }, align: "center", width: 120 },
],
};
},
computed: {},
mounted() {
this.loadData();
},
methods: {
//
loadData() {
this.loading = true;
if (this.serviceId) {
this.listQuery.serviceId = this.serviceId;
}
this.listQuery.id = this.id;
dockerSwarmServicesTaskList(this.listQuery).then((res) => {
if (res.code === 200) {
this.list = res.data;
}
this.loading = false;
});
},
handleEdit(record) {
this.editVisible = true;
this.temp = {
nodeId: record.id,
role: record.spec.role,
availability: record.spec.availability,
};
},
handleEditOk() {
this.$refs["editForm"].validate((valid) => {
if (!valid) {
return false;
}
this.temp.id = this.id;
dockerSwarmNodeUpdate(this.temp).then((res) => {
if (res.code === 200) {
//
this.$notification.success({
message: res.msg,
});
this.editVisible = false;
this.loadData();
}
});
});
},
//
handleLeava(record) {
this.$confirm({
title: "系统提示",
content: "真的要在该集群剔除此节点么?",
okText: "确认",
cancelText: "取消",
onOk: () => {
//
const params = {
nodeId: record.id,
id: this.id,
};
dockerSwarmNodeLeave(params).then((res) => {
if (res.code === 200) {
this.$notification.success({
message: res.msg,
});
this.loadData();
}
});
},
});
},
},
};
</script>