|
|
|
@ -1,22 +1,35 @@
|
|
|
|
|
<template>
|
|
|
|
|
<list-header
|
|
|
|
|
description="节点管理用于管理和监控计算节点的状态。它可以启用或禁用节点,查看节点上的物理GPU卡,以及监控节点上运行的所有任务。"
|
|
|
|
|
/>
|
|
|
|
|
|
|
|
|
|
<preview-bar :handle-click=handleClick />
|
|
|
|
|
|
|
|
|
|
<table-plus
|
|
|
|
|
:api="nodeApi.getNodeList()"
|
|
|
|
|
:columns="columns"
|
|
|
|
|
:rowAction="rowAction"
|
|
|
|
|
:searchSchema="searchSchema"
|
|
|
|
|
:hasPagination="false"
|
|
|
|
|
style="height: auto"
|
|
|
|
|
hideTag
|
|
|
|
|
ref="table"
|
|
|
|
|
staticPage
|
|
|
|
|
>
|
|
|
|
|
</table-plus>
|
|
|
|
|
<list-header description="节点管理用于管理和监控计算节点的状态。它可以启用或禁用节点,查看节点上的物理GPU卡,以及监控节点上运行的所有任务。">
|
|
|
|
|
<template #actions>
|
|
|
|
|
<el-button @click="handleAdd" style="margin-right: 24px;" type="primary" round>发现节点</el-button>
|
|
|
|
|
</template>
|
|
|
|
|
</list-header>
|
|
|
|
|
|
|
|
|
|
<preview-bar :handle-click=handleClick />
|
|
|
|
|
|
|
|
|
|
<table-plus :api="nodeApi.getNodeList()" :columns="columns" :rowAction="rowAction" :searchSchema="searchSchema"
|
|
|
|
|
:hasPagination="false" style="height: auto" hideTag ref="table" staticPage>
|
|
|
|
|
</table-plus>
|
|
|
|
|
|
|
|
|
|
<el-dialog @close="nodeSelect = []" v-model="dialogVisible" title="添加节点" width="600" :before-close="handleClose">
|
|
|
|
|
<div v-loading="loading">
|
|
|
|
|
<template v-if="nodeList && nodeList.length > 0">
|
|
|
|
|
<div style="display: flex; align-items: center;" v-for="{ nodeIp }, index in nodeList" :key="nodeIp">
|
|
|
|
|
<el-checkbox :model-value="nodeSelect.includes(nodeIp)" @change="handleCheckboxChange(nodeIp)" />
|
|
|
|
|
<span style="color: #0B1524; margin-left: 8px;">{{ nodeIp }}</span>
|
|
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
<template v-else>
|
|
|
|
|
<div>
|
|
|
|
|
<el-empty description="暂无节点数据" />
|
|
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
</div>
|
|
|
|
|
<template #footer>
|
|
|
|
|
<el-button @click="dialogVisible = false">取消</el-button>
|
|
|
|
|
<el-button :loading="btnLoading" type="primary" @click="handleOk">确认</el-button>
|
|
|
|
|
</template>
|
|
|
|
|
</el-dialog>
|
|
|
|
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
@ -26,16 +39,25 @@ import searchSchema from '~/vgpu/views/node/admin/searchSchema';
|
|
|
|
|
import { useRouter } from 'vue-router';
|
|
|
|
|
import PreviewBar from '~/vgpu/components/previewBar.vue';
|
|
|
|
|
import { roundToDecimal } from '@/utils';
|
|
|
|
|
import {ElMessage, ElMessageBox} from 'element-plus';
|
|
|
|
|
import { ElMessage, ElMessageBox } from 'element-plus';
|
|
|
|
|
import { ref } from 'vue';
|
|
|
|
|
|
|
|
|
|
const router = useRouter();
|
|
|
|
|
|
|
|
|
|
const table = ref();
|
|
|
|
|
|
|
|
|
|
// 节点选择相关
|
|
|
|
|
const dialogVisible = ref(false)
|
|
|
|
|
const nodeList = ref([])
|
|
|
|
|
const nodeSelect = ref([])
|
|
|
|
|
const loading = ref(true)
|
|
|
|
|
const btnLoading = ref(false)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const handleClick = async (params) => {
|
|
|
|
|
const name = params.data.name;
|
|
|
|
|
const {list} = await nodeApi.getNodes({filters:{}})
|
|
|
|
|
const { list } = await nodeApi.getNodes({ filters: {} })
|
|
|
|
|
const node = list.find(node => node.name === name);
|
|
|
|
|
if (node) {
|
|
|
|
|
const uuid = node.uid;
|
|
|
|
@ -45,6 +67,49 @@ const handleClick = async (params) => {
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 确认操作
|
|
|
|
|
const handleOk = async () => {
|
|
|
|
|
if (!nodeSelect.value.length) {
|
|
|
|
|
ElMessage({
|
|
|
|
|
message: '请选择节点',
|
|
|
|
|
type: 'warning',
|
|
|
|
|
})
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
btnLoading.value = true;
|
|
|
|
|
try {
|
|
|
|
|
const node_names = nodeList.value.filter(e => nodeSelect.value.includes(e.nodeIp)).map(e => e.nodeName)
|
|
|
|
|
const res = await nodeApi.joinNodes({
|
|
|
|
|
node_names
|
|
|
|
|
})
|
|
|
|
|
if (res?.code === 200) {
|
|
|
|
|
getList();
|
|
|
|
|
dialogVisible.value = false;
|
|
|
|
|
}
|
|
|
|
|
} finally {
|
|
|
|
|
btnLoading.value = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 复选框变化
|
|
|
|
|
const handleCheckboxChange = (ip) => {
|
|
|
|
|
const index = nodeSelect.value.indexOf(ip);
|
|
|
|
|
if (index > -1) {
|
|
|
|
|
nodeSelect.value.splice(index, 1);
|
|
|
|
|
} else {
|
|
|
|
|
nodeSelect.value.push(ip);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 添加节点
|
|
|
|
|
const handleAdd = async () => {
|
|
|
|
|
dialogVisible.value = true
|
|
|
|
|
loading.value = true
|
|
|
|
|
const res = await nodeApi.discoveredNodes({})
|
|
|
|
|
nodeList.value = res?.list || []
|
|
|
|
|
loading.value = false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const columns = [
|
|
|
|
|
{
|
|
|
|
|
title: '节点名称',
|
|
|
|
@ -61,9 +126,9 @@ const columns = [
|
|
|
|
|
title: '节点状态',
|
|
|
|
|
dataIndex: 'isSchedulable',
|
|
|
|
|
render: ({ isSchedulable, isExternal }) => (
|
|
|
|
|
<el-tag disable-transitions type={isExternal ? 'warning' : (isSchedulable ? 'success' : 'danger')}>
|
|
|
|
|
{isExternal ? '未纳管' : (isSchedulable ? '可调度' : '禁止调度')}
|
|
|
|
|
</el-tag>
|
|
|
|
|
<el-tag disable-transitions type={isExternal ? 'warning' : (isSchedulable ? 'success' : 'danger')}>
|
|
|
|
|
{isExternal ? '未纳管' : (isSchedulable ? '可调度' : '禁止调度')}
|
|
|
|
|
</el-tag>
|
|
|
|
|
)
|
|
|
|
|
// filters: [
|
|
|
|
|
// {
|
|
|
|
@ -95,28 +160,28 @@ const columns = [
|
|
|
|
|
title: 'vGPU',
|
|
|
|
|
dataIndex: 'used',
|
|
|
|
|
render: ({ vgpuTotal, vgpuUsed, isExternal }) => (
|
|
|
|
|
<span>
|
|
|
|
|
{isExternal ? '--' : vgpuUsed}/{isExternal ? '--' : vgpuTotal}
|
|
|
|
|
</span>
|
|
|
|
|
<span>
|
|
|
|
|
{isExternal ? '--' : vgpuUsed}/{isExternal ? '--' : vgpuTotal}
|
|
|
|
|
</span>
|
|
|
|
|
),
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: '算力(已分配/总量)',
|
|
|
|
|
dataIndex: 'used',
|
|
|
|
|
render: ({ coreTotal, coreUsed, isExternal }) => (
|
|
|
|
|
<span>
|
|
|
|
|
{isExternal ? '--' : coreUsed}/{coreTotal}
|
|
|
|
|
</span>
|
|
|
|
|
<span>
|
|
|
|
|
{isExternal ? '--' : coreUsed}/{coreTotal}
|
|
|
|
|
</span>
|
|
|
|
|
),
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: '显存(已分配/总量)',
|
|
|
|
|
dataIndex: 'w',
|
|
|
|
|
render: ({ memoryTotal, memoryUsed, isExternal }) => (
|
|
|
|
|
<span>
|
|
|
|
|
{isExternal ? '--' : roundToDecimal(memoryUsed / 1024, 1)}/
|
|
|
|
|
{roundToDecimal(memoryTotal / 1024, 1)} GiB
|
|
|
|
|
</span>
|
|
|
|
|
<span>
|
|
|
|
|
{isExternal ? '--' : roundToDecimal(memoryUsed / 1024, 1)}/
|
|
|
|
|
{roundToDecimal(memoryTotal / 1024, 1)} GiB
|
|
|
|
|
</span>
|
|
|
|
|
),
|
|
|
|
|
},
|
|
|
|
|
];
|
|
|
|
|