feat(cluster): update K8s cluster form for new k8s_options API
Align the Kubernetes cluster create/edit page with the backend's promotion of operator/K8s knobs out of worker_config and the removal of gpuVendorOverrides. - k8s_options: drop gpuVendorOverrides; add operatorImage, namespace, and gpuInstanceOptions (presence = GPU instances enabled, carrying an optional gpuInstancesAccessStaticAddress). - Add a top-level system_default_container_registry to the cluster type (promoted out of worker_config on the backend). - Group all k8s_options fields into a new top-level "K8s Deployment Options" collapsible section (sibling of Advanced, rendered above it), with namespace first followed by volume mounts, image credentials, node selector, operator image, and GPU instances. - Drive the GPU instances toggle from local state instead of Form.useWatch (an unregistered nested path never re-rendered, leaving the switch unresponsive); use antd's borderless Switch and keep the label/switch grouped together. Namespace gains a gpustack-system placeholder. - Remove the gpuVendorOverrides validation from the form and the stale operator_image / namespace / gpu_instances_access_static_address hints from the worker_config YAML template and JSON schema. - Add-worker GPU picker: always allow multi-select for K8s clusters (runtime node selectors are now auto-derived), dropping the override-gating, cluster fetch, and single-only hint. - Update locales (en/zh/ja/ru/tr) for the removed and added keys.
This commit is contained in:
@@ -3,13 +3,10 @@ import {
|
||||
GPUDriverMap,
|
||||
GPUsConfigs
|
||||
} from '@/pages/resources/config/gpu-driver';
|
||||
import { BulbOutlined } from '@ant-design/icons';
|
||||
import { useIntl } from '@umijs/max';
|
||||
import { Alert, Tag } from 'antd';
|
||||
import React, { useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { queryClusterItem } from '../../apis';
|
||||
import { Tag } from 'antd';
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import { ProviderValueMap } from '../../config';
|
||||
import { ClusterListItem } from '../../config/types';
|
||||
import SupportedGPUs from '../support-gpus';
|
||||
import { useAddWorkerContext } from './add-worker-context';
|
||||
import { AddWorkerStepProps, StepNamesMap } from './config';
|
||||
@@ -26,75 +23,25 @@ const buildWorkerCommand = (
|
||||
});
|
||||
|
||||
const SelectVendor: React.FC<AddWorkerStepProps> = ({ disabled }) => {
|
||||
const { stepList, registerField, updateField, provider, registrationInfo } =
|
||||
const { stepList, registerField, updateField, provider } =
|
||||
useAddWorkerContext();
|
||||
const intl = useIntl();
|
||||
|
||||
const stepIndex = stepList.indexOf(StepNamesMap.SelectGPU) + 1;
|
||||
|
||||
// Pull the cluster so we know whether gpuVendorOverrides was configured.
|
||||
// The K8s register flow gates multi-select on that being present, and
|
||||
// restricts available runtimes to its keys.
|
||||
const [overrideRuntimes, setOverrideRuntimes] = useState<string[]>([]);
|
||||
useEffect(() => {
|
||||
const id = registrationInfo?.cluster_id;
|
||||
if (!id) {
|
||||
// Reset when the cluster context goes away so we don't leak the
|
||||
// previous cluster's overrides into the next session.
|
||||
setOverrideRuntimes([]);
|
||||
return;
|
||||
}
|
||||
let cancelled = false;
|
||||
queryClusterItem({ id })
|
||||
.then((c) => {
|
||||
if (cancelled) return;
|
||||
const overrides = (c as ClusterListItem)?.k8s_options
|
||||
?.gpuVendorOverrides;
|
||||
setOverrideRuntimes(overrides ? Object.keys(overrides) : []);
|
||||
})
|
||||
.catch((err) => {
|
||||
if (cancelled) return;
|
||||
console.error('Failed to query cluster for vendor overrides:', err);
|
||||
setOverrideRuntimes([]);
|
||||
});
|
||||
return () => {
|
||||
cancelled = true;
|
||||
};
|
||||
}, [registrationInfo?.cluster_id]);
|
||||
|
||||
// Set of GPU *driver keys* (e.g. "cuda", "cann") that match the cluster's
|
||||
// override runtimes. Used to detect when multi-add becomes available.
|
||||
const overrideKeys = useMemo(() => {
|
||||
const set = new Set<string>();
|
||||
if (!overrideRuntimes.length) return set;
|
||||
Object.values(GPUsConfigs).forEach((cfg) => {
|
||||
if (cfg.gpuVendor && overrideRuntimes.includes(cfg.gpuVendor)) {
|
||||
set.add(cfg.value);
|
||||
}
|
||||
});
|
||||
return set;
|
||||
}, [overrideRuntimes]);
|
||||
|
||||
// Multi-add is only meaningful when the cluster has 2+ vendor overrides
|
||||
// AND the current selection already includes one. Until both hold, the
|
||||
// picker behaves like a single-select (so the user can freely land on
|
||||
// any vendor — including ones outside the override list).
|
||||
const multiCapable =
|
||||
provider === ProviderValueMap.Kubernetes && overrideKeys.size >= 2;
|
||||
// K8s clusters render one worker DaemonSet per requested GPU runtime and
|
||||
// derive each DaemonSet's nodeSelector from the vendor's PCI-presence label
|
||||
// at manifest time, so multiple vendors can be registered without any
|
||||
// per-cluster override config. Multi-select is therefore always available
|
||||
// for the Kubernetes provider; other providers stay single-select.
|
||||
const multiCapable = provider === ProviderValueMap.Kubernetes;
|
||||
|
||||
const [selectedKeys, setSelectedKeys] = useState<string[]>([
|
||||
GPUDriverMap.NVIDIA
|
||||
]);
|
||||
|
||||
const isMultiActive = useMemo(
|
||||
() => multiCapable && selectedKeys.some((k) => overrideKeys.has(k)),
|
||||
[multiCapable, selectedKeys, overrideKeys]
|
||||
);
|
||||
|
||||
// In multi-active mode, non-override vendors are disabled — picking one
|
||||
// would break the backend invariant that a multi-vendor manifest must
|
||||
// only target configured runtimes. Otherwise everything stays enabled.
|
||||
const availableKeys = isMultiActive ? overrideKeys : undefined;
|
||||
// No vendor is gated anymore — every card stays selectable.
|
||||
const availableKeys = undefined;
|
||||
|
||||
// Cache vendor metadata (label/link from SupportedGPUs items) so we can
|
||||
// rebuild workerCommand on toggle without re-clicking the card.
|
||||
@@ -126,10 +73,6 @@ const SelectVendor: React.FC<AddWorkerStepProps> = ({ disabled }) => {
|
||||
}, []);
|
||||
|
||||
const handleSelect = (key: string, item: any) => {
|
||||
// Disabled cards are already blocked by TemplateCard; this is a
|
||||
// defensive check for the multi-active case (only override runtimes
|
||||
// can be added once multi-add is open).
|
||||
if (availableKeys && !availableKeys.has(key)) return;
|
||||
if (item) {
|
||||
itemMetaRef.current[key] = {
|
||||
label: item.label,
|
||||
@@ -142,21 +85,13 @@ const SelectVendor: React.FC<AddWorkerStepProps> = ({ disabled }) => {
|
||||
// Clicking a selected card always toggles it off.
|
||||
return prev.filter((v) => v !== key);
|
||||
}
|
||||
// Multi-add only when the current state already includes an override
|
||||
// pick. Otherwise (still in single-select land), replace.
|
||||
if (isMultiActive) return [...prev, key];
|
||||
// K8s clusters support multiple GPU runtimes, so accumulate picks.
|
||||
// Other providers stay single-select and replace the current pick.
|
||||
if (multiCapable) return [...prev, key];
|
||||
return [key];
|
||||
});
|
||||
};
|
||||
|
||||
// Warn when multi-select is possible on this cluster but the user's
|
||||
// current pick lands outside the override list — they're effectively
|
||||
// locked into single-select until they switch to an override vendor.
|
||||
const showSingleOnlyHint =
|
||||
multiCapable &&
|
||||
selectedKeys.length > 0 &&
|
||||
selectedKeys.every((k) => !overrideKeys.has(k));
|
||||
|
||||
return (
|
||||
<StepCollapse
|
||||
disabled={disabled}
|
||||
@@ -182,17 +117,6 @@ const SelectVendor: React.FC<AddWorkerStepProps> = ({ disabled }) => {
|
||||
</Title>
|
||||
}
|
||||
>
|
||||
{showSingleOnlyHint && (
|
||||
<Alert
|
||||
type="info"
|
||||
showIcon
|
||||
icon={<BulbOutlined />}
|
||||
style={{ marginBottom: 8 }}
|
||||
message={intl.formatMessage({
|
||||
id: 'clusters.addworker.selectGPU.singleOnly'
|
||||
})}
|
||||
/>
|
||||
)}
|
||||
<SupportedGPUs
|
||||
onSelect={handleSelect}
|
||||
current={selectedKeys}
|
||||
|
||||
Reference in New Issue
Block a user