main
youys 7 days ago
commit dbef1be45f

@ -6,7 +6,7 @@ const apiPrefix = '/api/vgpu';
class nodeApi {
getNodeList(data) {
return {
url: apiPrefix + '/v1/nodes',
url: apiPrefix + '/v1/nodes',
method: 'POST',
data,
};
@ -14,7 +14,7 @@ class nodeApi {
getNodes(data) {
return request({
url: apiPrefix + '/v1/nodes',
url: apiPrefix + '/v1/nodes',
method: 'POST',
data,
});
@ -22,7 +22,7 @@ class nodeApi {
getNodeDetail(params) {
return request({
url: apiPrefix + '/v1/node',
url: apiPrefix + '/v1/node',
method: 'GET',
params,
});
@ -31,6 +31,21 @@ class nodeApi {
getNodeListReq(data) {
return request(this.getNodeList(data));
}
discoveredNodes(data) {
return request({
url: apiPrefix + '/v1/node/discovered',
method: 'POST',
data,
});
}
joinNodes(data) {
return request({
url: apiPrefix + '/v1/node/join',
method: 'POST',
data,
});
}
}
export default new nodeApi();

@ -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>
),
},
];

@ -8,7 +8,7 @@
<div v-loading="loading" style="min-height: 90px;">
<block-box
v-for="{ poolId, poolName, nodeNum, cpuCores, gpuNum, availableMemory, totalMemory, diskSize, nodeList }, index in paginatedList"
:key="poolId">
:key="poolId" style="margin: 15px 0 0 0;">
<el-row style="align-items: center;">
<div class="left">
<b class="title">{{ poolName }}</b>
@ -36,7 +36,7 @@
</div>
<!-- 分页组件 -->
<el-pagination background v-model:current-page="currentPage" v-model:page-size="pageSize"
<el-pagination style="margin-top: 15px;" background v-model:current-page="currentPage" v-model:page-size="pageSize"
layout="total, ->, sizes, jumper, prev, next" :page-sizes="[10, 20, 50, 100]" :total="list.length"
@size-change="handleSizeChange" @current-change="handleCurrentChange" />
@ -90,10 +90,8 @@
</div>
</div>
<template #footer>
<span class="dialog-footer">
<el-button @click="dialogVisible = false">取消</el-button>
<el-button :loading="btnLoading" type="primary" @click="handleOk"></el-button>
</span>
<el-button @click="dialogVisible = false">取消</el-button>
<el-button :loading="btnLoading" type="primary" @click="handleOk"></el-button>
</template>
</el-dialog>
</template>

Loading…
Cancel
Save