<template>
|
<div class="s-cluster-management">
|
<div class="ui-top-view">
|
<div class="ui-top-title">视频分析集群管理</div>
|
</div>
|
<el-row>
|
<el-col :span="12">
|
<el-tabs v-model="activeName" id="e-alaycluster" v-if="!isHasColony">
|
<el-tab-pane label="创建集群" name="1" :disabled="isHasColony">
|
<el-form :model="ruleForm" :rules="rules" ref="ruleForm" label-width="100px">
|
<el-form-item label="集群名称" prop="clustername">
|
<el-input v-model="ruleForm.clustername" placeholder="手动输入, 如“集群A”" size="small"></el-input>
|
</el-form-item>
|
<el-form-item label="集群ID">
|
<el-input v-model="clusterid" placeholder="不允许输入,保存后回显" disabled size="small"></el-input>
|
</el-form-item>
|
<el-form-item label="集群密码" prop="clusterpwd" style="width:500px">
|
<el-input v-model="ruleForm.clusterpwd" placeholder="请输入6位密码,或点击生成" size="small">
|
<el-button type="text" slot="suffix" @click="generatePassword">生成密码</el-button>
|
</el-input>
|
</el-form-item>
|
<el-form-item label="虚拟/外部IP" prop="virtualIp">
|
<ip-input :ip="ruleForm.virtualIp" :on-blur="onIpBlur"></ip-input>
|
</el-form-item>
|
<el-form-item style="width:500px">
|
<el-button type="primary" size="small" @click="submitForm('ruleForm')">保存</el-button>
|
</el-form-item>
|
</el-form>
|
</el-tab-pane>
|
|
<!-- 加入已有集群 -->
|
<el-tab-pane label="加入已有集群" name="2" :disabled="isHasColony">
|
<el-form label-width="80px" :model="joinForm" :rules="joinRules" ref="joinForm">
|
<el-form-item label="IP地址" style="width:440px">
|
<el-input
|
v-model="joinForm.clusterip"
|
placeholder="请输入集群内任意IP地址"
|
size="small"
|
autocomplete="new-password"
|
>
|
<el-button
|
type="text"
|
slot="suffix"
|
v-show="!searchDis"
|
@click="searchColony"
|
>搜索集群</el-button>
|
<el-button type="text" slot="suffix" v-show="searchDis" @click="stopSearch">
|
<i class="el-icon-loading"></i>停止搜索
|
</el-button>
|
</el-input>
|
|
<!-- <el-button size="mini" :disabled="searchDis" @click="searchColony">搜索集群</el-button>
|
<el-button size="mini" @click="stopSearch">停止搜索</el-button>-->
|
</el-form-item>
|
<el-form-item label="集群密码" prop="clusterpwd" style="width:500px">
|
<el-input
|
v-model="joinForm.clusterpwd"
|
placeholder="请输入集群密码"
|
show-password
|
size="small"
|
autocomplete="new-password"
|
></el-input>
|
</el-form-item>
|
<el-form-item style="width:440px">
|
<el-button type="primary" @click="join('joinForm')" size="small">加入集群</el-button>
|
</el-form-item>
|
</el-form>
|
</el-tab-pane>
|
</el-tabs>
|
<!-- 有集群的情况 -->
|
<div v-if="isHasColony" id="h-alaycluster">
|
<el-form :model="ruleForm" ref="ruleForm" label-width="100px">
|
<el-form-item label="集群名称" prop="clustername">
|
<el-input v-model="ruleForm.clustername" placeholder="手动输入, 如“集群A”" size="small"></el-input>
|
</el-form-item>
|
<el-form-item label="集群ID">
|
<el-input v-model="clusterid" placeholder="不允许输入,保存后回显" disabled size="small"></el-input>
|
</el-form-item>
|
<el-form-item label="集群密码" prop="clusterpwd" style="width:500px">
|
<el-input
|
v-model="ruleForm.clusterpwd"
|
disabled
|
placeholder="请输入6位密码,或点击生成"
|
size="small"
|
></el-input>
|
</el-form-item>
|
|
<el-form-item label="虚拟IP" prop="virtualIp">
|
<ip-input :ip="ruleForm.virtualIp" :on-blur="onIpBlur"></ip-input>
|
</el-form-item>
|
<el-form-item style="width:440px;text-align: right;">
|
<el-button size="small" type="danger" @click="leave">退出集群</el-button>
|
<el-button
|
style="margin-right:10px;"
|
type="primary"
|
size="small"
|
@click="submitForm('manageForm')"
|
>保存</el-button>
|
</el-form-item>
|
</el-form>
|
</div>
|
</el-col>
|
<el-col :span="12" style="height: 100%;" v-if="members.length !== 0">
|
<serfDiagram
|
ref="diagram"
|
:members="members"
|
:agent="agentName"
|
v-loading="loading"
|
@selected-node="joinNode"
|
class="nodes-svg"
|
></serfDiagram>
|
</el-col>
|
</el-row>
|
|
<div class="ui-top-view">
|
<div class="ui-top-title">存储集群管理</div>
|
</div>
|
<el-row>
|
<el-col :span="12">
|
<el-tabs id="e-dbcluster" v-model="sActiveName">
|
<el-tab-pane label="创建集群" name="s-first" v-if="sActiveName != 's-third1'">
|
<el-button
|
type="primary"
|
style="float: left;margin: 20px 0px;"
|
size="small"
|
@click="createEsCluster()"
|
>创建存储集群</el-button>
|
<!-- <p>点击将本机创建为存储集群</p> -->
|
</el-tab-pane>
|
<el-tab-pane label="加入已有集群" name="s-second" v-if="sActiveName != 's-third1'">
|
<el-form label-width="80px">
|
<el-form-item label="IP地址" style="text-align: left;width: 300px;">
|
<el-input
|
v-model="esNodeIp"
|
placeholder="请输入集群内任意IP地址"
|
size="small"
|
autocomplete="off"
|
></el-input>
|
<el-checkbox
|
label="主节点"
|
v-model="esNodeType"
|
style="margin-left: 20px;position: absolute;"
|
></el-checkbox>
|
</el-form-item>
|
<el-form-item>
|
<el-button
|
type="primary"
|
@click="joinESCluster()"
|
size="small"
|
style="float: left;"
|
>加入集群</el-button>
|
</el-form-item>
|
</el-form>
|
</el-tab-pane>
|
<el-tab-pane label="集群信息" name="s-third">
|
<el-table :data="esNodes" style="width: 100%">
|
<el-table-column prop="nodeType" label="节点类型"></el-table-column>
|
<el-table-column prop="name" label="节点名称"></el-table-column>
|
<el-table-column prop="ip" label="节点IP地址" min-width="90px"></el-table-column>
|
<el-table-column prop="buildDate" label="注册时间" min-width="120px"></el-table-column>
|
</el-table>
|
</el-tab-pane>
|
</el-tabs>
|
</el-col>
|
</el-row>
|
|
</div>
|
</template>
|
|
<script>
|
import {
|
createSerfCluster,
|
randomPwd,
|
search,
|
getSearchNodes,
|
stopSearching,
|
findCluster,
|
updateClusterName,
|
joinCluster,
|
leave,
|
getVrrp,
|
setVrrp,
|
createESNode,
|
addESNode,
|
getEsClusterInfo
|
} from "@/api/clusterManage";
|
|
import {
|
getDevInfo
|
} from "@/api/system";
|
|
import serfDiagram from "@/components/serfDiagram";
|
import ipInput from "@/components/subComponents/IPInput";
|
import {isIPv4} from "@/scripts/validate";
|
export default {
|
components: {
|
serfDiagram,
|
ipInput
|
},
|
data() {
|
const checkPwd = (rule, value, callback) => {
|
if (!value) {
|
return callback(new Error("密码不能为空"));
|
}
|
setTimeout(() => {
|
// if (value.length > 16 || value.length < 6) {
|
// callback(new Error("密码应为6-16位!"));
|
// } else {
|
// callback();
|
// }
|
if (value.length != 6) {
|
callback(new Error("密码应为6位!"));
|
} else {
|
callback();
|
}
|
}, 1000);
|
};
|
|
return {
|
activeName: "1",
|
sActiveName: "s-first",
|
clusterid: "",
|
esNodeIp: "",
|
esNodeType: "",
|
clusterpwd2: "",
|
sClusterip: "",
|
ruleForm: {
|
clustername: "",
|
clusterpwd: "",
|
virtualIp: ""
|
},
|
vrIpForm: {
|
enable: true,
|
//serve_port: "",
|
serve_port: null,
|
virtual_ip: ""
|
},
|
manageForm: {
|
clustername: "测试集群1",
|
clusterpwd: "123456",
|
virtualip: "192.168.1.188"
|
},
|
joinForm: {
|
clusterip: "",
|
clusterpwd: ""
|
},
|
rules: {
|
clustername: [
|
{ required: true, message: "请输入集群名称", trigger: "change" }
|
],
|
clusterpwd: [{ validator: checkPwd, trigger: "change" }],
|
virtualIp: [
|
{ required: true, validator: isIPv4, trigger: "change" }
|
]
|
},
|
// vrIpRules: {
|
// virtualIp: [
|
// { required: true, message: "请输入虚拟IP", trigger: "change" }
|
// ]
|
// },
|
joinRules: {
|
clusterpwd: [
|
{ required: true, message: "请输入集群密码", trigger: "change" },
|
{ validator: checkPwd, trigger: "change" }
|
]
|
},
|
esNodes: [],
|
scheduleId: "",
|
isHasColony: false,
|
currentCluster: {},
|
searchNum: "",
|
loading: false,
|
searchDis: false,
|
agentName: "",
|
members: []
|
};
|
},
|
mounted() {
|
this.findCluster();
|
this.getVrrpInfo();
|
this.getEsClusterNodes();
|
},
|
methods: {
|
cleanValue() {
|
this.members = [];
|
},
|
sHandleClick(tab, event) {
|
console.log(tab, event);
|
},
|
submitForm(formName) {
|
this.$refs[formName].validate(valid => {
|
if (valid) {
|
debugger
|
//alert("submit!");
|
let json = {
|
clusterId: this.clusterid,
|
clusterName: this.ruleForm.clustername,
|
password: this.ruleForm.clusterpwd,
|
virtualIp: this.ruleForm.virtualIp
|
};
|
this.createCluster(json).then(() => {
|
this.findCluster();
|
});
|
} else {
|
console.log("error submit!!");
|
return false;
|
}
|
});
|
},
|
|
saveForm(formName) {
|
this.$refs[formName].validate(valid => {
|
if (valid) {
|
alert("submit!");
|
let json = {
|
enable: this.vrIpForm.enable,
|
serve_port: this.vrIpForm.serve_port,
|
virtual_ip: this.vrIpForm.virtual_ip,
|
|
};
|
setVrrp(json).then(() => {
|
this.getVrrpInfo();
|
});
|
} else {
|
console.log("error submit!!");
|
return false;
|
}
|
});
|
},
|
|
join (formName) {
|
this.$refs[formName].validate(valid => {
|
if (valid) {
|
if (Object.keys(this.currentCluster).length === 0) {
|
this.$notify({
|
type: "info",
|
duration: 1000,
|
message: "请先选择一个集群节点"
|
});
|
return true;
|
}
|
let nodeIps = this.members.map(i => {
|
return i.Address;
|
});
|
let json = {
|
clusterId: this.currentCluster.cluster_id,
|
password: this.joinForm.clusterpwd,
|
nodeIps: nodeIps
|
};
|
this.joinCluster(json).then(() => {
|
this.findCluster();
|
});
|
} else {
|
console.log("error submit!!");
|
return false;
|
}
|
});
|
},
|
async createCluster(json) {
|
let res = await createSerfCluster(json);
|
console.log(res, "创建集群");
|
this.$notify({
|
title: res.success ? "成功" : "失败",
|
message: res.msg,
|
type: res.success ? "success" : "error"
|
});
|
},
|
async randomPwd() {
|
let res = await randomPwd();
|
if (res && res.success) {
|
this.ruleForm.clusterpwd = res.data;
|
}
|
},
|
async searchColony() {
|
this.$refs["joinForm"].validate(valid => {
|
if (valid) {
|
this.members = [];
|
let json = {
|
password: this.joinForm.clusterpwd,
|
ip: this.joinForm.clusterip
|
};
|
|
this.search(json)
|
.then(() => {
|
this.setSchedule();
|
// this.searchDis = false;
|
// this.loading = false;
|
})
|
.catch(() => {
|
this.searchDis = false;
|
this.loading = false;
|
});
|
} else {
|
this.searchDis = false;
|
this.loading = false;
|
return false;
|
}
|
});
|
},
|
async search(json) {
|
let res = await search(json);
|
if (res && res.success) {
|
console.log(res, "搜索集群");
|
this.searchNum = res.data;
|
}
|
this.searchDis = true;
|
this.loading = true;
|
window.setTimeout(() => {
|
this.stopSearch();
|
}, 10 * 1000);
|
},
|
async getSearchNodes() {
|
let res = await getSearchNodes();
|
if (res && res.success) {
|
let list = res.data.map(i => {
|
let obj = {};
|
obj.cluster_id = i.clusterID ? i.clusterID : "";
|
obj.create_time = i.create_time ? i.create_time : "";
|
obj.id = i.nodeID ? i.nodeID : "";
|
obj.node_id = i.nodeID ? i.nodeID : "";
|
obj.Address = i.nodeAddress ? i.nodeAddress : "";
|
obj.nodeName = i.nodeAddress ? i.nodeAddress : "";
|
obj.role = i.role ? i.role : "pc";
|
return obj;
|
});
|
list.map(i => {
|
let found = this.members.find(element => {
|
return element.node_id === i.node_id;
|
});
|
if (found === undefined) {
|
this.members.push(i);
|
}
|
});
|
}
|
},
|
setSchedule() {
|
this.scheduleId = window.setInterval(() => {
|
this.getSearchNodes();
|
}, 1000);
|
},
|
async stopSearch() {
|
if (!this.loading) {
|
return true;
|
}
|
stopSearching({
|
searchNum: this.searchNum
|
}).then((res) => {
|
console.log(res, '正常结束')
|
this.loading = false;
|
this.searchDis = false;
|
window.clearInterval(this.scheduleId);
|
}).catch((err) => {
|
console.log(err, '报错结束')
|
this.$notify({
|
type: 'error',
|
duration: 1000,
|
message: '停止搜索报错!'
|
})
|
// window.setTimeout(()=>{
|
// this.loading = false;
|
// this.searchDis = false;
|
// window.clearInterval(this.scheduleId);
|
// },2000)
|
})
|
},
|
async findCluster() {
|
let res = await findCluster();
|
if (res && res.success) {
|
if (res.data && res.data.clusterId) {
|
this.isHasColony = true;
|
this.activeName = "3";
|
this.clusterid = res.data.clusterId;
|
this.ruleForm.clustername = res.data.clusterName;
|
this.ruleForm.clusterpwd = res.data.clusterpwd
|
this.ruleForm.virtualIp = res.data.virtualIp
|
let list = res.data.nodes.map(i => {
|
debugger
|
let obj = {};
|
obj.device_type = i.device_type;
|
obj.cluster_id = i.cluster_id;
|
obj.clusterName = res.data.clusterName;
|
obj.create_time = i.create_time;
|
obj.id = i.id;
|
obj.node_id = i.node_id;
|
obj.node_ip = i.node_ip;
|
obj.nodeName = i.node_name;
|
obj.Address = i.node_ip;
|
obj.role = i.role ? i.role : "pc";
|
return obj;
|
});
|
this.members = this.members.concat(list);
|
} else {
|
this.isHasColony = false;
|
// this.activeName = '1'
|
}
|
}
|
},
|
getVrrpInfo() {
|
getVrrp().then(res => {
|
if (res.success) {
|
this.vrIpForm.virtual_ip = res.data.virtual_ip;
|
this.vrIpForm.enable = res.data.enable;
|
}
|
}).catch(e => {
|
console.log(e)
|
})
|
},
|
async updateClusterName() {
|
let res = await updateClusterName({
|
clusterName: this.mangeForm.colonyName
|
});
|
this.$notify({
|
title: res.success ? "成功" : "失败",
|
message: res.msg,
|
type: res.success ? "success" : "error"
|
});
|
},
|
async joinCluster(json) {
|
let res = await joinCluster(json);
|
if (res.success) {
|
this.members = []
|
}
|
this.$notify({
|
title: res.success ? "成功" : "失败",
|
message: res.msg,
|
type: res.success ? "success" : "error"
|
});
|
},
|
leave() {
|
this.$confirm(`确定退出集群吗?`, {
|
center: true,
|
cancelButtonClass: "comfirm-class-cancle",
|
confirmButtonClass: "comfirm-class-sure"
|
}).then(async () => {
|
let res = await leave();
|
this.$notify({
|
title: res.success ? "成功" : "失败",
|
message: res.msg,
|
type: res.success ? "success" : "error"
|
});
|
if (res && res.success) {
|
this.ruleForm.clustername = "";
|
this.ruleForm.clusterpwd = ""
|
this.clusterid = "";
|
this.isHasColony = false;
|
this.activeName = "1";
|
this.members = [];
|
}
|
}).catch(() => { });
|
|
},
|
joinNode(event, node) {
|
this.currentCluster.cluster_id = node.cluster_id;
|
if (this.activeName === "3") {
|
this.manageForm.clustername = node.clusterName;
|
this.clusterid = node.cluster_id;
|
return;
|
}
|
if (this.activeName === "2") {
|
this.$refs["joinForm"].validate(valid => {
|
if (valid) {
|
this.$confirm("是否要加入节点 " + node.nodeName + "?", "加入集群", {
|
confirmButtonText: "确定",
|
cancelButtonText: "取消",
|
type: "success"
|
})
|
.then(() => {
|
// this.agentName = 'node' + this.members.length
|
// this.members.push({
|
// nodeName: this.agentName,
|
// Address: '172.10.10.26',
|
// role: 'pc'
|
// })
|
// this.$notify({
|
// type: 'success',
|
// duration: 1000,
|
// message: '加入成功!'
|
// })
|
console.log(this.currentCluster, '选择的集群节点')
|
this.join("joinForm");
|
})
|
.catch(() => {
|
this.$notify({
|
type: "info",
|
duration: 1000,
|
message: "已取消"
|
});
|
});
|
} else {
|
console.log("error submit!!");
|
return false;
|
}
|
});
|
}
|
},
|
generatePassword() {
|
var chars =
|
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
var uuid = [];
|
|
for (let i = 0; i < 6; i++) {
|
uuid[i] = chars[0 | (Math.random() * 50)];
|
}
|
|
this.ruleForm.clusterpwd = uuid.join("");
|
},
|
|
async getEsClusterNodes() {
|
let rsp = await getDevInfo();
|
let hostIpAddr = "";
|
if (rsp && rsp.success) {
|
hostIpAddr = rsp.data.ip;
|
}
|
|
if (hostIpAddr.length) {
|
rsp = await getEsClusterInfo({ ip: hostIpAddr });
|
if (rsp && rsp.success) {
|
this.esNodes = rsp.data.map(el => {
|
return {
|
// buildDate: "2018-06-11T23:38:03.357887Z",
|
buildDate: el.buildDate.split("T")[0] + " " + el.buildDate.split("T")[1].slice(0, 8),
|
ip: el.ip,
|
name: el.name,
|
nodeType: el.nodeType,
|
}
|
})
|
|
if (this.esNodes.length) {
|
this.sActiveName = 's-third';
|
}
|
}
|
}
|
},
|
createEsCluster() {
|
createESNode().then(rsp => {
|
if (rsp && rsp.success) {
|
this.$message({
|
type: "success",
|
duration: 2000,
|
message: "创建成功"
|
});
|
|
this.getSearchNodes();
|
} else {
|
this.$message({
|
type: "error",
|
duration: 2000,
|
message: rsp.msg
|
});
|
}
|
}).catch(rsp => {
|
this.$message({
|
type: "error",
|
duration: 2000,
|
message: rsp.msg
|
});
|
})
|
},
|
joinESCluster() {
|
if (!this.esNodeIp.length) {
|
this.$message({
|
type: "error",
|
duration: 2000,
|
message: "请输入正确的ip地址"
|
});
|
return;
|
}
|
|
addESNode({ ip: this.esNodeIp, option: this.esNodeType ? "1" : "2" }).then(rsp => {
|
if (rsp && rsp.success) {
|
this.$message({
|
type: "success",
|
duration: 2000,
|
message: "加入成功"
|
});
|
|
this.getSearchNodes();
|
} else {
|
this.$message({
|
type: "error",
|
duration: 2000,
|
message: rsp.msg
|
});
|
}
|
}).catch(rsp => {
|
this.$message({
|
type: "error",
|
duration: 2000,
|
message: rsp.msg
|
});
|
})
|
},
|
onIpBlur (ip) {
|
//this.vrIpForm.virtual_ip = ip;
|
this.ruleForm.virtualIp = ip;
|
console.log(this.ruleForm.virtualIp)
|
}
|
|
|
|
},
|
mounted () {
|
this.findCluster();
|
|
},
|
created () { }
|
|
};
|
</script>
|
<style lang="scss">
|
.s-cluster-management {
|
width: 100%;
|
height: 100%;
|
overflow: auto;
|
|
.el-button {
|
float: right;
|
}
|
.el-form-item__content {
|
text-align: left;
|
input {
|
max-width: 360px;
|
}
|
}
|
|
#e-alaycluster,
|
#e-dbcluster {
|
.el-tabs__header {
|
border: 0px solid #dcdfe6;
|
.el-tabs__item {
|
padding: 5px 50px;
|
height: 50px;
|
font-family: PingFangSC-Regular;
|
font-size: 14px;
|
color: #222222;
|
text-align: center;
|
border: 0px solid transparent;
|
}
|
.el-tabs__item:nth-child(2) {
|
padding-left: 50px;
|
}
|
.el-tabs__item:last-child {
|
padding-right: 50px;
|
}
|
.el-tabs__item.is-active {
|
color: #ff7733;
|
font-weight: bold;
|
// border-right-color: #fff;
|
// border-left-color: #fff;
|
}
|
.el-tabs__item:not(.is-disabled):hover {
|
color: #ff7733;
|
}
|
}
|
.el-tabs__active-bar {
|
background-color: #ff7733;
|
}
|
.el-form-item__content {
|
text-align: left;
|
input {
|
max-width: 420px;
|
}
|
}
|
}
|
|
#h-alaycluster {
|
.el-form-item__content {
|
text-align: left;
|
input {
|
max-width: 360px;
|
}
|
}
|
}
|
}
|
.ui-top-view {
|
height: 30px;
|
line-height: 30px;
|
}
|
.nodes-svg{
|
background-color: aquamarine;
|
}
|
</style>
|