mirror of
https://gitee.com/dromara/Jpom.git
synced 2024-12-02 20:08:40 +08:00
pre swarm task list
This commit is contained in:
parent
65b7235160
commit
f34bdd3124
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
});
|
||||
}
|
||||
|
@ -61,9 +61,6 @@ export default {
|
||||
};
|
||||
</script>
|
||||
<style scoped>
|
||||
.docker-layout {
|
||||
/* background-color: #fff; */
|
||||
}
|
||||
.docker-menu {
|
||||
height: 100%;
|
||||
}
|
||||
|
59
web-vue/src/pages/docker/swarm/console.vue
Normal file
59
web-vue/src/pages/docker/swarm/console.vue
Normal 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>
|
@ -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() {
|
||||
// 检验表单
|
||||
|
@ -146,13 +146,9 @@ export default {
|
||||
},
|
||||
computed: {},
|
||||
mounted() {
|
||||
// this.loadData();
|
||||
this.loadData();
|
||||
},
|
||||
methods: {
|
||||
refreshData() {
|
||||
this.list = [];
|
||||
this.loadData();
|
||||
},
|
||||
// 加载数据
|
||||
loadData() {
|
||||
this.loading = true;
|
||||
|
204
web-vue/src/pages/docker/swarm/service.vue
Normal file
204
web-vue/src/pages/docker/swarm/service.vue
Normal 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>
|
224
web-vue/src/pages/docker/swarm/task.vue
Normal file
224
web-vue/src/pages/docker/swarm/task.vue
Normal 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>
|
Loading…
Reference in New Issue
Block a user