From 01f66085abd31298d153cb1f2fe14297f77e7b4e Mon Sep 17 00:00:00 2001 From: jialin Date: Fri, 12 Jun 2026 15:26:26 +0800 Subject: [PATCH] fix: only keep the max count cpu instance type --- config/proxy.ts | 1 + .../instances/components/add-modal.tsx | 90 +-- .../components/instance-type-item.tsx | 8 +- .../gpu-service/instances/config/mock-data.ts | 648 ++++++++++++++++++ .../services/use-query-instance-types.ts | 24 +- 5 files changed, 683 insertions(+), 88 deletions(-) create mode 100644 src/pages/gpu-service/instances/config/mock-data.ts diff --git a/config/proxy.ts b/config/proxy.ts index 279a76f3..93753a31 100644 --- a/config/proxy.ts +++ b/config/proxy.ts @@ -31,5 +31,6 @@ export default function createProxyTable(target?: string) { }, {} ); + return proxyTable; } diff --git a/src/pages/gpu-service/instances/components/add-modal.tsx b/src/pages/gpu-service/instances/components/add-modal.tsx index fa18d25c..cc7979d4 100644 --- a/src/pages/gpu-service/instances/components/add-modal.tsx +++ b/src/pages/gpu-service/instances/components/add-modal.tsx @@ -8,11 +8,10 @@ import { AlertBlockInfo, ColumnWrapper, GSDrawer, - IconFont, ModalFooter } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; -import { Empty, Flex, Input, Segmented, Typography } from 'antd'; +import { Empty, Input, Typography } from 'antd'; import _ from 'lodash'; import { useEffect, useMemo, useRef, useState } from 'react'; import { ListItem as TemplateItem } from '../../templates/config/types'; @@ -90,7 +89,6 @@ const AddModal: React.FC = ({ manufacturer: undefined }); const [templateId, setTemplateId] = useState(); - const [resourceType, setResourceType] = useState<'gpu' | 'cpu'>('gpu'); const [instanceKeyword, setInstanceKeyword] = useState(''); const [templateKeyword, setTemplateKeyword] = useState(''); const { loading, guard, run, release } = useSubmitLock(); @@ -189,14 +187,6 @@ const AddModal: React.FC = ({ const manufacturerOf = (instanceType: InstanceTypeItem) => instanceType.spec.acceleratable ? instanceType.spec?.manufacturer : 'cpu'; - const matchesResourceType = ( - instanceType: InstanceTypeItem, - type: 'gpu' | 'cpu' - ) => - type === 'gpu' - ? !!instanceType.spec.acceleratable - : !instanceType.spec.acceleratable; - // apply the selection of instance type and template const applySelection = ( instanceType: InstanceTypeItem, @@ -300,8 +290,6 @@ const AddModal: React.FC = ({ instanceType: aggregate.name, manufacturer: manufacturerOf(aggregate) }); - // Surface the persisted pick under the matching segment. - setResourceType(aggregate.spec.acceleratable ? 'gpu' : 'cpu'); } return; } @@ -309,23 +297,9 @@ const AddModal: React.FC = ({ // Scope to clusters the chosen org owns (admin "All" view). const owned = filterTypesByOwner(instanceTypes, clusters || [], orgId); - // Prefer the active segment, but fall back to the other kind when it has - // no enabled candidate so the drawer never opens on an empty list. - const hasEnabled = (type: 'gpu' | 'cpu') => - owned.some((it) => matchesResourceType(it, type) && !it.disabled); - const other = resourceType === 'gpu' ? 'cpu' : 'gpu'; - const nextType = hasEnabled(resourceType) - ? resourceType - : hasEnabled(other) - ? other - : resourceType; - setResourceType(nextType); - - // On create, auto-select the first instance type of the chosen kind. - autoSelectFirst( - owned.filter((it) => matchesResourceType(it, nextType)), - templates - ); + // On create, auto-select the first available instance type (clears the + // selection when the chosen org has none). + autoSelectFirst(owned, templates); }; // Fetch the (tenant-scoped) instance types + templates and auto-select. @@ -383,7 +357,6 @@ const AddModal: React.FC = ({ manufacturer: undefined }); setTemplateId(undefined); - setResourceType('gpu'); setInstanceKeyword(''); setTemplateKeyword(''); setScopeOrgId(undefined); @@ -395,20 +368,10 @@ const AddModal: React.FC = ({ } }, [open, shouldAutoSelectResource, action]); - // Which kinds the chosen org actually offers — drives the GPU/CPU segment - // availability so a user can't switch to an empty list. - const hasGPUTypes = ownedInstanceTypes.some( - (item) => item.spec.acceleratable + // filter instance types (already scoped to the chosen org's clusters) + const filteredInstanceTypes = ownedInstanceTypes.filter((item) => + matchKeyword([item.name], instanceKeyword) ); - const hasCPUTypes = ownedInstanceTypes.some( - (item) => !item.spec.acceleratable - ); - - // filter instance types (already scoped to the chosen org's clusters) by the - // active GPU/CPU segment, then by the search keyword. - const filteredInstanceTypes = ownedInstanceTypes - .filter((item) => matchesResourceType(item, resourceType)) - .filter((item) => matchKeyword([item.name], instanceKeyword)); // No instance types for the chosen org (e.g. it owns no clusters), and not // mid-fetch — drives the "no available instance type" message in the form. @@ -477,14 +440,6 @@ const AddModal: React.FC = ({ }); }; - const handleOnTypeChange = (next: 'gpu' | 'cpu') => { - setResourceType(next); - autoSelectFirst( - ownedInstanceTypes.filter((item) => matchesResourceType(item, next)), - templateList - ); - }; - return ( = ({ }} > - - - {intl.formatMessage({ - id: 'gpuservice.instance.types' - })} - - , - disabled: !hasGPUTypes - }, - { - label: 'CPU', - value: 'cpu', - icon: , - disabled: !hasCPUTypes - } - ]} - > - + {intl.formatMessage({ + id: 'gpuservice.instance.types' + })} = ({ item }) => { const manufacturerColor = manufactureColorMap[manufacturer] ?? 'purple'; const showManufacturerTag = acceleratable && !!manufacturer; - const showCPUManufacturerTag = !acceleratable && !!cpuManufacturer; return ( = ({ item }) => { {manufacturer?.toUpperCase()} )} - {showCPUManufacturerTag && ( - - )} diff --git a/src/pages/gpu-service/instances/config/mock-data.ts b/src/pages/gpu-service/instances/config/mock-data.ts new file mode 100644 index 00000000..3026565b --- /dev/null +++ b/src/pages/gpu-service/instances/config/mock-data.ts @@ -0,0 +1,648 @@ +export default { + items: [ + { + name: 'gpustack--amd-epyc-7r32-ln-x64-4c-16g--nvidia-a10g-1d', + spec: { + memory: '22Gi', + cores: '10240', + computeCapability: '8.6', + sliced: null, + cpu: { + physicalCores: '2', + threadsPerPhysicalCore: '2', + logicalCores: '4', + stepping: null, + clockSpeed: null, + maxClockSpeed: null, + cacheLine: '64', + cache: { + l1i: '32768', + l1d: '32768', + l2: '524288', + l3: '8388608' + }, + manufacturer: 'amd', + product: 'AMD EPYC 7R32', + family: '23' + }, + physicalCores: null, + threadsPerPhysicalCore: null, + logicalCores: null, + stepping: null, + clockSpeed: null, + maxClockSpeed: null, + cacheLine: null, + cache: { + l1i: null, + l1d: null, + l2: null, + l3: null + }, + group: 'gpustack--amd-epyc-7r32-ln-x64-4c-16g--nvidia-a10g-1d', + acceleratable: true, + manufacturer: 'nvidia', + product: 'NVIDIA-A10G', + family: 'Ampere', + os: 'linux', + arch: 'amd64', + unitResources: { + cpu: '4', + ram: '16Gi' + } + }, + status: { + onceMaxRequest: { + accelerator: '1', + cpu: '4', + ram: '16Gi', + localStorage: '98Gi' + }, + remaining: { + accelerator: '1', + cpu: '4', + ram: '16Gi', + localStorage: '98Gi' + }, + tiers: [ + { + onceMaxRequest: { + accelerator: '1', + cpu: '4', + ram: '16Gi', + localStorage: '98Gi' + }, + remaining: { + accelerator: '1', + cpu: '4', + ram: '16Gi', + localStorage: '98Gi' + }, + candidates: [ + { + cluster: '1', + name: 'gpustack--amd-epyc-7r32-ln-x64-4c-16g--nvidia-a10g-1d', + accelerator: { + onceMaxRequest: '1', + remaining: '1', + capacity: '1' + }, + cpu: { + onceMaxRequest: '4', + remaining: '4', + capacity: '4' + }, + ram: { + onceMaxRequest: '16Gi', + remaining: '16Gi', + capacity: '16Gi' + }, + localStorage: { + onceMaxRequest: '98Gi', + remaining: '98Gi', + capacity: '98Gi' + } + } + ] + } + ] + } + }, + { + name: 'gpustack--intel-xeon-platinum-8259cl-ln-x64-12c-46g--nvidia-tesla-t4-1d', + spec: { + memory: '15Gi', + cores: '2560', + computeCapability: '7.5', + sliced: null, + cpu: { + physicalCores: '24', + threadsPerPhysicalCore: '2', + logicalCores: '48', + stepping: '7', + clockSpeed: '2500000000', + maxClockSpeed: null, + cacheLine: '64', + cache: { + l1i: '32768', + l1d: '32768', + l2: '1048576', + l3: '37486592' + }, + manufacturer: 'intel', + product: 'Intel(R) Xeon(R) Platinum 8259CL CPU @ 2.50GHz', + family: '6' + }, + physicalCores: null, + threadsPerPhysicalCore: null, + logicalCores: null, + stepping: null, + clockSpeed: null, + maxClockSpeed: null, + cacheLine: null, + cache: { + l1i: null, + l1d: null, + l2: null, + l3: null + }, + group: + 'gpustack--intel-xeon-platinum-8259cl-ln-x64-12c-46g--nvidia-tesla-t4-1d', + acceleratable: true, + manufacturer: 'nvidia', + product: 'Tesla-T4', + family: 'Turing', + os: 'linux', + arch: 'amd64', + unitResources: { + cpu: '12', + ram: '46Gi' + } + }, + status: { + onceMaxRequest: { + accelerator: '4', + cpu: '48', + ram: '186Gi', + localStorage: '98Gi' + }, + remaining: { + accelerator: '4', + cpu: '48', + ram: '186Gi', + localStorage: '98Gi' + }, + tiers: [ + { + onceMaxRequest: { + accelerator: '4', + cpu: '48', + ram: '186Gi', + localStorage: '98Gi' + }, + remaining: { + accelerator: '4', + cpu: '48', + ram: '186Gi', + localStorage: '98Gi' + }, + candidates: [ + { + cluster: '1', + name: 'gpustack--intel-xeon-platinum-8259cl-ln-x64-12c-46g--nvidia-tesla-t4-1d', + accelerator: { + onceMaxRequest: '4', + remaining: '4', + capacity: '4' + }, + cpu: { + onceMaxRequest: '48', + remaining: '48', + capacity: '48' + }, + ram: { + onceMaxRequest: '186Gi', + remaining: '186Gi', + capacity: '186Gi' + }, + localStorage: { + onceMaxRequest: '98Gi', + remaining: '98Gi', + capacity: '98Gi' + } + } + ] + } + ] + } + }, + { + name: 'gpustack--intel-xeon-platinum-8259cl-ln-x64-4c-16g--nvidia-tesla-t4-1d', + spec: { + memory: '15Gi', + cores: '2560', + computeCapability: '7.5', + sliced: null, + cpu: { + physicalCores: '2', + threadsPerPhysicalCore: '2', + logicalCores: '4', + stepping: '7', + clockSpeed: '2500000000', + maxClockSpeed: null, + cacheLine: '64', + cache: { + l1i: '32768', + l1d: '32768', + l2: '1048576', + l3: '37486592' + }, + manufacturer: 'intel', + product: 'Intel(R) Xeon(R) Platinum 8259CL CPU @ 2.50GHz', + family: '6' + }, + physicalCores: null, + threadsPerPhysicalCore: null, + logicalCores: null, + stepping: null, + clockSpeed: null, + maxClockSpeed: null, + cacheLine: null, + cache: { + l1i: null, + l1d: null, + l2: null, + l3: null + }, + group: + 'gpustack--intel-xeon-platinum-8259cl-ln-x64-4c-16g--nvidia-tesla-t4-1d', + acceleratable: true, + manufacturer: 'nvidia', + product: 'Tesla-T4', + family: 'Turing', + os: 'linux', + arch: 'amd64', + unitResources: { + cpu: '4', + ram: '16Gi' + } + }, + status: { + onceMaxRequest: { + accelerator: '1', + cpu: '4', + ram: '16Gi', + localStorage: '98Gi' + }, + remaining: { + accelerator: '1', + cpu: '4', + ram: '16Gi', + localStorage: '98Gi' + }, + tiers: [ + { + onceMaxRequest: { + accelerator: '1', + cpu: '4', + ram: '16Gi', + localStorage: '98Gi' + }, + remaining: { + accelerator: '1', + cpu: '4', + ram: '16Gi', + localStorage: '98Gi' + }, + candidates: [ + { + cluster: '1', + name: 'gpustack--intel-xeon-platinum-8259cl-ln-x64-4c-16g--nvidia-tesla-t4-1d', + accelerator: { + onceMaxRequest: '1', + remaining: '1', + capacity: '1' + }, + cpu: { + onceMaxRequest: '4', + remaining: '4', + capacity: '4' + }, + ram: { + onceMaxRequest: '16Gi', + remaining: '16Gi', + capacity: '16Gi' + }, + localStorage: { + onceMaxRequest: '98Gi', + remaining: '98Gi', + capacity: '98Gi' + } + } + ] + } + ] + } + }, + { + name: 'gpustack--amd-epyc-7r13-processor-ln-x64-1c-2g', + spec: { + memory: null, + cores: null, + computeCapability: null, + sliced: null, + cpu: { + physicalCores: null, + threadsPerPhysicalCore: null, + logicalCores: null, + stepping: null, + clockSpeed: null, + maxClockSpeed: null, + cacheLine: null, + cache: { + l1i: null, + l1d: null, + l2: null, + l3: null + }, + manufacturer: null, + product: null, + family: null + }, + physicalCores: '8', + threadsPerPhysicalCore: '2', + logicalCores: '16', + stepping: '1', + clockSpeed: null, + maxClockSpeed: null, + cacheLine: '64', + cache: { + l1i: '32768', + l1d: '32768', + l2: '524288', + l3: '33554432' + }, + group: 'gpustack--amd-epyc-7r13-processor-ln-x64-1c-2g', + acceleratable: false, + manufacturer: 'amd', + product: 'AMD EPYC 7R13 Processor', + family: '25', + os: 'linux', + arch: 'amd64', + unitResources: { + cpu: '1', + ram: '2Gi' + } + }, + status: { + onceMaxRequest: { + accelerator: '0', + cpu: '16', + ram: '32Gi', + localStorage: '98Gi' + }, + remaining: { + accelerator: '0', + cpu: '16', + ram: '32Gi', + localStorage: '98Gi' + }, + tiers: [ + { + onceMaxRequest: { + accelerator: '0', + cpu: '16', + ram: '32Gi', + localStorage: '98Gi' + }, + remaining: { + accelerator: '0', + cpu: '16', + ram: '32Gi', + localStorage: '98Gi' + }, + candidates: [ + { + cluster: '1', + name: 'gpustack--amd-epyc-7r13-processor-ln-x64-1c-2g', + accelerator: { + onceMaxRequest: '0', + remaining: '0', + capacity: '0' + }, + cpu: { + onceMaxRequest: '16', + remaining: '16', + capacity: '16' + }, + ram: { + onceMaxRequest: '32Gi', + remaining: '32Gi', + capacity: '32Gi' + }, + localStorage: { + onceMaxRequest: '98Gi', + remaining: '98Gi', + capacity: '98Gi' + } + } + ] + } + ] + } + }, + { + name: 'gpustack--amd-epyc-7r32-ln-x64-1c-2g', + spec: { + memory: null, + cores: null, + computeCapability: null, + sliced: null, + cpu: { + physicalCores: null, + threadsPerPhysicalCore: null, + logicalCores: null, + stepping: null, + clockSpeed: null, + maxClockSpeed: null, + cacheLine: null, + cache: { + l1i: null, + l1d: null, + l2: null, + l3: null + }, + manufacturer: null, + product: null, + family: null + }, + physicalCores: '2', + threadsPerPhysicalCore: '2', + logicalCores: '4', + stepping: null, + clockSpeed: null, + maxClockSpeed: null, + cacheLine: '64', + cache: { + l1i: '32768', + l1d: '32768', + l2: '524288', + l3: '8388608' + }, + group: 'gpustack--amd-epyc-7r32-ln-x64-1c-2g', + acceleratable: false, + manufacturer: 'amd', + product: 'AMD EPYC 7R32', + family: '23', + os: 'linux', + arch: 'amd64', + unitResources: { + cpu: '1', + ram: '2Gi' + } + }, + status: { + onceMaxRequest: { + accelerator: '0', + cpu: '4', + ram: '8Gi', + localStorage: '98Gi' + }, + remaining: { + accelerator: '0', + cpu: '4', + ram: '8Gi', + localStorage: '98Gi' + }, + tiers: [ + { + onceMaxRequest: { + accelerator: '0', + cpu: '4', + ram: '8Gi', + localStorage: '98Gi' + }, + remaining: { + accelerator: '0', + cpu: '4', + ram: '8Gi', + localStorage: '98Gi' + }, + candidates: [ + { + cluster: '1', + name: 'gpustack--amd-epyc-7r32-ln-x64-1c-2g', + accelerator: { + onceMaxRequest: '0', + remaining: '0', + capacity: '0' + }, + cpu: { + onceMaxRequest: '4', + remaining: '4', + capacity: '4' + }, + ram: { + onceMaxRequest: '8Gi', + remaining: '8Gi', + capacity: '8Gi' + }, + localStorage: { + onceMaxRequest: '98Gi', + remaining: '98Gi', + capacity: '98Gi' + } + } + ] + } + ] + } + }, + { + name: 'gpustack--intel-xeon-platinum-8259cl-ln-x64-1c-2g', + spec: { + memory: null, + cores: null, + computeCapability: null, + sliced: null, + cpu: { + physicalCores: null, + threadsPerPhysicalCore: null, + logicalCores: null, + stepping: null, + clockSpeed: null, + maxClockSpeed: null, + cacheLine: null, + cache: { + l1i: null, + l1d: null, + l2: null, + l3: null + }, + manufacturer: null, + product: null, + family: null + }, + physicalCores: '24', + threadsPerPhysicalCore: '2', + logicalCores: '48', + stepping: '7', + clockSpeed: '2500000000', + maxClockSpeed: null, + cacheLine: '64', + cache: { + l1i: '32768', + l1d: '32768', + l2: '1048576', + l3: '37486592' + }, + group: 'gpustack--intel-xeon-platinum-8259cl-ln-x64-1c-2g', + acceleratable: false, + manufacturer: 'intel', + product: 'Intel(R) Xeon(R) Platinum 8259CL CPU @ 2.50GHz', + family: '6', + os: 'linux', + arch: 'amd64', + unitResources: { + cpu: '1', + ram: '2Gi' + } + }, + status: { + onceMaxRequest: { + accelerator: '0', + cpu: '48', + ram: '96Gi', + localStorage: '98Gi' + }, + remaining: { + accelerator: '0', + cpu: '52', + ram: '104Gi', + localStorage: '196Gi' + }, + tiers: [ + { + onceMaxRequest: { + accelerator: '0', + cpu: '48', + ram: '96Gi', + localStorage: '98Gi' + }, + remaining: { + accelerator: '0', + cpu: '52', + ram: '104Gi', + localStorage: '196Gi' + }, + candidates: [ + { + cluster: '1', + name: 'gpustack--intel-xeon-platinum-8259cl-ln-x64-1c-2g', + accelerator: { + onceMaxRequest: '0', + remaining: '0', + capacity: '0' + }, + cpu: { + onceMaxRequest: '48', + remaining: '52', + capacity: '52' + }, + ram: { + onceMaxRequest: '96Gi', + remaining: '104Gi', + capacity: '104Gi' + }, + localStorage: { + onceMaxRequest: '98Gi', + remaining: '196Gi', + capacity: '196Gi' + } + } + ] + } + ] + } + } + ] +}; diff --git a/src/pages/gpu-service/instances/services/use-query-instance-types.ts b/src/pages/gpu-service/instances/services/use-query-instance-types.ts index 04367365..04583ee0 100644 --- a/src/pages/gpu-service/instances/services/use-query-instance-types.ts +++ b/src/pages/gpu-service/instances/services/use-query-instance-types.ts @@ -47,7 +47,7 @@ export default function useQueryInstanceTypes() { ) => { const res = await fetchData(params); - const list = (res?.items || []).map((item) => { + const mappedList = (res?.items || []).map((item) => { const remainingData = isAvailable(item); const rawMax = item.status?.onceMaxRequest; @@ -81,6 +81,28 @@ export default function useQueryInstanceTypes() { }; }); + // Keep all acceleratable instance types directly; for the + // non-acceleratable (CPU) ones only keep the entry with the largest + // spec.maxComputeUnitCount. + let maxCpuItem: (typeof mappedList)[number] | undefined; + const list = mappedList.filter((item) => { + if (item.spec.acceleratable) { + return true; + } + if ( + !maxCpuItem || + (item.spec.maxComputeUnitCount || 0) > + (maxCpuItem.spec.maxComputeUnitCount || 0) + ) { + maxCpuItem = item; + } + return false; + }); + + if (maxCpuItem) { + list.push(maxCpuItem); + } + setDataList(list); return list; };