feat: extend cluster k8s_options with multi-vendor manifest support

- New k8s_pod_spec form sections (image credentials, node selector,
  gpu vendor overrides) under k8s_options, replacing the legacy flat
  k8s_volume_mounts list. UI keys aligned to the backend wire shape
  (snake_case k8s_options + camelCase inside).
- System default container registry is pre-filled into the first image
  credential when creating a new cluster; empty username/password are
  coerced to null on submit to match the Optional[str] backend schema.
- Register cluster flow supports multi-runtime selection gated by the
  cluster's gpuVendorOverrides: non-override vendors stay single-select
  with an inline hint; multi-add only opens once an override vendor is
  picked, and non-override cards become disabled in that state.
- Manifest URL emits multiple ?runtime= params; check-env step combines
  per-vendor commands; downstream steps are disabled when no vendor is
  selected.
- Pre-validate gpuVendorOverrides at save time (non-empty selector, no
  duplicates across vendors, no key clash with base nodeSelector) so
  the user sees the error before hitting the manifest endpoint.
- Misc: dark-mode background of the k8s_pod_spec / volume mount titles
  no longer clashes with the drawer; cluster Steps no longer leaks the
  internal showModules/showForms props to the DOM.
This commit is contained in:
Yuxing Deng
2026-05-26 16:54:14 +08:00
parent 91c3d0b814
commit acb90531b2
21 changed files with 1023 additions and 112 deletions
+24 -1
View File
@@ -69,6 +69,9 @@ export default {
'clusters.addworker.selectCluster.tips':
'Для <span class="bold-text">не-Docker</span> кластеров, пожалуйста, регистрируйте кластеры или управляйте пулами воркеров на странице Кластеры.',
'clusters.addworker.selectGPU': 'Выбрать производителя GPU',
'clusters.addworker.selectGPU.multiTag': 'Multi-select',
'clusters.addworker.selectGPU.singleOnly':
'The selected vendor is not in this clusters GPU vendor overrides — single-select only. Pick a vendor configured in the overrides to enable multi-select.',
'clusters.addworker.checkEnv': 'Проверить окружение',
'clusters.addworker.specifyArgs': 'Указать аргументы',
'clusters.addworker.runCommand': 'Выполнить команду',
@@ -161,7 +164,27 @@ export default {
'clusters.volume.pvc.readOnly': 'Read Only',
'clusters.volume.configMap.name': 'ConfigMap Name',
'clusters.volume.configMap.optional': 'Optional',
'clusters.volume.add': 'Add Volume Mount'
'clusters.volume.add': 'Add Volume Mount',
'clusters.imageCredentials.title': 'Image Credentials',
'clusters.imageCredentials.add': 'Add Credential',
'clusters.imageCredentials.registry': 'Registry',
'clusters.imageCredentials.username': 'Username',
'clusters.imageCredentials.password': 'Password',
'clusters.nodeSelector.title': 'Node Selector',
'clusters.nodeSelector.tip':
'Pod nodeSelector applied to every worker DaemonSet — only nodes whose labels match are eligible to run the worker.',
'clusters.gpuVendorOverrides.title': 'GPU Vendor Overrides',
'clusters.gpuVendorOverrides.validate.emptySelector':
'The override for {vendor} needs at least one nodeSelector entry — an empty override would leave the multi-vendor manifest unable to target nodes for this runtime.',
'clusters.gpuVendorOverrides.validate.duplicate':
'Overrides for {v1} and {v2} use the same nodeSelector. Each vendor must scope to a distinct node set, otherwise their worker DaemonSets would compete for the same nodes.',
'clusters.gpuVendorOverrides.validate.keyConflict':
'Override for {vendor} reuses key(s) {keys} from the base Node Selector — the CPU worker would simultaneously require and forbid the key and never schedule.',
'clusters.gpuVendorOverrides.tip':
'Required when running multiple GPU vendors in one cluster. Each entry pins that vendors worker DaemonSet to nodes matching its nodeSelector, and the CPU worker is steered away from those nodes via a DoesNotExist node-affinity.',
'clusters.gpuVendorOverrides.add': 'Add Override',
'clusters.gpuVendorOverrides.vendor': 'GPU Vendor',
'clusters.gpuVendorOverrides.nodeSelector': 'Node Selector'
};
// ========== To-Do: Translate Keys (Remove After Translation) ==========