main
youys 1 week ago
commit a25f046140

@ -111,6 +111,7 @@ onMounted(async () => {
query: v.query,
})
.then((res) => {
console.log(v.query, res, 'res')
currentConfig.value[i].data = res.data.map((item) => ({
name: item.metric[v.nameKey],
value: item.value,

@ -95,10 +95,11 @@ import {
} from './getOptions';
import Block from './Block.vue';
import './style.scss';
import { timeParse, getDaysInRange, getRandom } from '@/utils';
import { timeParse, getDaysInRange, getRandom, bytesToGB } from '@/utils';
import { useRouter } from 'vue-router';
import UserCard from '@/components/UserCard.vue';
import nodeApi from '~/vgpu/api/node';
import pollApi from '~/vgpu/api/poll';
import taskApi from '~/vgpu/api/task';
import monitorApi from '~/vgpu/api/monitor';
import cardApi from '~/vgpu/api/card';
@ -134,9 +135,9 @@ const cardGaugeConfig = useInstantVector([
{
title: 'CPU 使用率',
percent: 0,
query: `avg(sum (hami_container_vgpu_allocated) by (instance))`,
totalQuery: `avg(sum (hami_vgpu_count) by (instance))`,
percentQuery: `avg(sum (hami_container_vgpu_allocated) by (instance))/avg(sum (hami_vgpu_count) by (instance)) *100`,
query: `avg(count(node_cpu_seconds_total{mode="idle"}) by (instance)) * (1 - avg(rate(node_cpu_seconds_total{mode="idle"}[5m])))`,
totalQuery: `avg(count(node_cpu_seconds_total{mode="idle"}) by (instance))`,
percentQuery: ``,
total: 0,
used: 0,
unit: '核',
@ -144,9 +145,9 @@ const cardGaugeConfig = useInstantVector([
{
title: '内存 使用率',
percent: 0,
query: `avg(sum (hami_container_vgpu_allocated) by (instance))`,
totalQuery: `avg(sum (hami_vgpu_count) by (instance))`,
percentQuery: `avg(sum (hami_container_vgpu_allocated) by (instance))/avg(sum (hami_vgpu_count) by (instance)) *100`,
query: `avg(node_memory_MemTotal_bytes - node_memory_MemAvailable_bytes) / 1024 / 1024 / 1024`,
totalQuery: `avg(node_memory_MemTotal_bytes) / 1024 / 1024 / 1024`,
percentQuery: ``,
total: 0,
used: 0,
unit: 'GiB',
@ -154,12 +155,12 @@ const cardGaugeConfig = useInstantVector([
{
title: '磁盘 使用率',
percent: 0,
query: `avg(sum (hami_container_vgpu_allocated) by (instance))`,
totalQuery: `avg(sum (hami_vgpu_count) by (instance))`,
percentQuery: `avg(sum (hami_container_vgpu_allocated) by (instance))/avg(sum (hami_vgpu_count) by (instance)) *100`,
query: `avg(node_filesystem_size_bytes{fstype!~"tmpfs|overlay"} - node_filesystem_free_bytes{fstype!~"tmpfs|overlay"}) / 1024 / 1024 / 1024`,
totalQuery: `avg(node_filesystem_size_bytes{fstype!~"tmpfs|overlay"}) / 1024 / 1024 / 1024`,
percentQuery: ``,
total: 0,
used: 0,
unit: '',
unit: 'GiB',
},
{
title: 'vGPU 分配率',
@ -244,7 +245,7 @@ const resourceOverview = ref([
title: '磁盘',
count: 0,
icon: 'vgpu-disk',
unit: '',
unit: 'GIB',
},
{
title: '显卡',
@ -312,6 +313,8 @@ const nodeData = useFetchList(nodeApi.getNodeListReq({ filters: {} }));
const cardData = useFetchList(cardApi.getCardListReq({ filters: {} }));
const pollData = useFetchList(pollApi.getPollList(), 'data');
const cardDetail = useInstantVector([
{
title: 'vGPU',
@ -377,18 +380,18 @@ const nodeUsedTop = {
key: 'used',
config: [
{
tab: 'GPU',
key: 'gpu',
nameKey: 'node',
tab: 'CPU',
key: 'cpu',
nameKey: 'instance',
data: [],
query: 'topk(5, avg(hami_core_util_avg) by (node))',
query: 'topk(5, avg by (instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])))',
},
{
tab: '内存',
key: 'internal',
nameKey: 'node',
nameKey: 'instance',
data: [],
query: 'topk(5, avg(hami_core_util_avg) by (node))',
query: 'topk(5, ((node_memory_MemTotal_bytes - node_memory_MemAvailable_bytes) / node_memory_MemTotal_bytes))',
},
{
tab: '算力',
@ -491,7 +494,10 @@ const fetchRangeData = () => {
watchEffect(() => {
resourceOverview.value[0].count = nodeData.value.length;
resourceOverview.value[1].count = pollData.value.length;
resourceOverview.value[2].count = cardGaugeConfig.value[0].total;
resourceOverview.value[3].count = Math.round(cardGaugeConfig.value[1].total);
resourceOverview.value[4].count = Math.round(cardGaugeConfig.value[2].total);
resourceOverview.value[5].count = cardData.value.length;
resourceOverview.value[6].count = cardGaugeConfig.value[3].total;
resourceOverview.value[7].count = cardGaugeConfig.value[4].total;

@ -5,34 +5,40 @@
round>创建资源池</el-button>
</template>
</list-header>
<block-box
v-for="{ poolId, poolName, nodeNum, cpuCores, gpuNum, availableMemory, totalMemory, diskSize, nodeList }, index in list"
:key="poolId">
<el-row style="align-items: center;">
<div class="left">
<b class="title">{{ poolName }}</b>
<div class="tags">
<span>节点数量&nbsp;&nbsp;{{ nodeNum }}</span>
<span>CPU数&nbsp;&nbsp;{{ cpuCores }}</span>
<span>显卡数量&nbsp;&nbsp;{{ gpuNum }}</span>
<span>可用/总内存&nbsp;&nbsp;{{ bytesToGB(availableMemory) }}GB / {{ bytesToGB(totalMemory) }}GB</span>
<span>磁盘大小&nbsp;&nbsp;{{ bytesToGB(diskSize) }}GB</span>
<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">
<el-row style="align-items: center;">
<div class="left">
<b class="title">{{ poolName }}</b>
<div class="tags">
<span>节点数量&nbsp;&nbsp;{{ nodeNum }}</span>
<span>CPU数&nbsp;&nbsp;{{ cpuCores }}</span>
<span>显卡数量&nbsp;&nbsp;{{ gpuNum }}</span>
<span>可用/总内存&nbsp;&nbsp;{{ bytesToGB(availableMemory) }}GB / {{ bytesToGB(totalMemory) }}GB</span>
<span>磁盘大小&nbsp;&nbsp;{{ bytesToGB(diskSize) }}GB</span>
</div>
</div>
</div>
<div class="right">
<el-button type="text">查看详情</el-button>
<template v-if="index === 0">
<el-button type="text">配置</el-button>
</template>
<template v-else>
<el-button @click="dialogVisible = true; editId = poolId; nodeSelect = nodeList; input = poolName"
type="text">编辑</el-button>
<el-button @click="() => handleDelete(poolId)" type="text">删除</el-button>
</template>
</div>
</el-row>
</block-box>
<div class="right">
<el-button type="text">查看详情</el-button>
<template v-if="index === 0 && currentPage === 1">
<el-button type="text">配置</el-button>
</template>
<template v-else>
<el-button @click="dialogVisible = true; editId = poolId; nodeSelect = nodeList; input = poolName"
type="text">编辑</el-button>
<el-button @click="() => handleDelete(poolId)" type="text">删除</el-button>
</template>
</div>
</el-row>
</block-box>
</div>
<!-- 分页组件 -->
<el-pagination 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" />
<el-dialog @close="editId = null; input = ''; nodeSelect = []" v-model="dialogVisible"
:title="editId ? '编辑资源池' : '创建资源池'" width="1180" :before-close="handleClose">
@ -43,7 +49,7 @@
<div style="margin-top: 20px; margin-bottom: 10px;">
<span>选择节点</span>
<span style="float: right;">已选<span style="color: #3061D0; margin: 0 5px;">{{ nodeSelect.length
}}</span>个节点</span>
}}</span>个节点</span>
</div>
<div class="wrap">
<div class="wrap-left">
@ -61,11 +67,8 @@
<div>CPU<span>{{ cpuCores }}</span></div>
</div>
</div>
</div>
<div class="wrap-center">
</div>
<div class="wrap-center"></div>
<div class="wrap-right">
<div style="margin-top: 12px;"
v-for="{ nodeIp, cpuCores, gpuNum, gpuMemory, totalMemory, diskSize }, index in nodeList.filter(e => nodeSelect.includes(e.nodeIp))"
@ -93,28 +96,58 @@
</span>
</template>
</el-dialog>
</template>
<script setup lang="jsx">
import pollApi from '~/vgpu/api/poll';
import { ref, onMounted } from 'vue';
import { ref, onMounted, computed, watchEffect } from 'vue';
import BlockBox from '@/components/BlockBox.vue';
import { Remove } from '@element-plus/icons-vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { bytesToGB } from '@/utils';
//
const list = ref([])
const loading = ref(true)
//
const currentPage = ref(1)
const pageSize = ref(10)
const total = ref(0)
//
const dialogVisible = ref(false)
const editId = ref(null)
const nodeList = ref([])
const nodeSelect = ref([])
const input = ref('')
const btnLoading = ref(false)
const bytesToGB = (bytes) => {
return Math.round(bytes / (1024 * 1024 * 1024));
//
const nodeList = ref([])
const nodeSelect = ref([])
//
const paginatedList = computed(() => {
const start = (currentPage.value - 1) * pageSize.value
const end = start + pageSize.value
return list.value.slice(start, end)
})
// watchEffect(()=>{
// console.log(currentPage.value, pageSize.value, 88)
// })
//
const handleSizeChange = (val) => {
pageSize.value = val
currentPage.value = 1 //
}
//
const handleCurrentChange = (val) => {
currentPage.value = val
}
//
const handleOk = async () => {
if (!input.value) {
ElMessage({
@ -131,26 +164,33 @@ const handleOk = async () => {
return;
}
btnLoading.value = true;
const nodes = nodeList.value.filter(e => nodeSelect.value.includes(e.nodeIp)).map(e => ({ nodeIp: e.nodeIp, nodeName: e.nodeName }))
let res;
if (editId.value) {
res = await pollApi.update({
pool_id: editId.value,
pool_name: input.value,
nodes
})
} else {
res = await pollApi.create({
pool_name: input.value,
nodes
})
try {
const nodes = nodeList.value.filter(e => nodeSelect.value.includes(e.nodeIp)).map(e => ({ nodeIp: e.nodeIp, nodeName: e.nodeName }))
let res;
if (editId.value) {
res = await pollApi.update({
pool_id: editId.value,
pool_name: input.value,
nodes
})
} else {
res = await pollApi.create({
pool_name: input.value,
nodes
})
}
if (res?.code === 200) {
getList();
dialogVisible.value = false;
}
} finally {
btnLoading.value = false;
}
console.log(res, 'res')
getList();
btnLoading.value = false;
dialogVisible.value = false;
}
//
const handleCheckboxChange = (ip) => {
const index = nodeSelect.value.indexOf(ip);
if (index > -1) {
@ -160,33 +200,44 @@ const handleCheckboxChange = (ip) => {
}
}
//
const handleDelete = async (id) => {
ElMessageBox.confirm(`确定要删除当前资源池吗?`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}).then(async () => {
const res = await pollApi.delete({ pool_id: id })
if (res.code === 1) {
ElMessage.success('删除成功');
getList();
beforeClose: async (action, instance, done) => {
if (action === 'confirm') {
instance.confirmButtonLoading = true;
const res = await pollApi.delete({ pool_id: id });
if (res.code === 200) {
ElMessage.success('删除成功');
getList();
done();
}
instance.confirmButtonLoading = false;
} else {
done();
}
}
})
}
//
const getList = async () => {
loading.value = true
const res = await pollApi.getPollList()
loading.value = false
list.value = res.data
total.value = res.data.length
}
//
onMounted(async () => {
getList();
const res = await pollApi.getNodeList()
nodeList.value = res.data
});
</script>
<style scoped lang="scss">

@ -566,3 +566,8 @@ export const clearEdges = (items) =>
...item,
children: clearEdges(item.edges.children),
}));
// 字节转GB
export const bytesToGB = (bytes) => {
return Math.round(bytes / (1024 * 1024 * 1024));
}

Loading…
Cancel
Save