diff --git a/src/locales/en-US/clusters.ts b/src/locales/en-US/clusters.ts index 892ec7ec..254d4995 100644 --- a/src/locales/en-US/clusters.ts +++ b/src/locales/en-US/clusters.ts @@ -162,6 +162,9 @@ export default { 'clusters.volume.configMap.name': 'ConfigMap Name', 'clusters.volume.configMap.optional': 'Optional', 'clusters.volume.add': 'Add Volume Mount', + 'clusters.systemDefaultContainerRegistry.title': 'Default Container Registry', + 'clusters.systemDefaultContainerRegistry.tip': + 'Default registry used to resolve GPUStack images for this cluster. Falls back to the server default when unset.', 'clusters.k8sOptions.title': 'K8s Deployment Options', 'clusters.imageCredentials.title': 'Image Credentials', 'clusters.imageCredentials.add': 'Add Credential', diff --git a/src/locales/ja-JP/clusters.ts b/src/locales/ja-JP/clusters.ts index 9475e831..c48e9f50 100644 --- a/src/locales/ja-JP/clusters.ts +++ b/src/locales/ja-JP/clusters.ts @@ -162,6 +162,9 @@ export default { 'clusters.volume.configMap.name': 'ConfigMap Name', 'clusters.volume.configMap.optional': 'Optional', 'clusters.volume.add': 'Add Volume Mount', + 'clusters.systemDefaultContainerRegistry.title': 'Default Container Registry', + 'clusters.systemDefaultContainerRegistry.tip': + 'Default registry used to resolve GPUStack images for this cluster. Falls back to the server default when unset.', 'clusters.k8sOptions.title': 'K8s Deployment Options', 'clusters.imageCredentials.title': 'Image Credentials', 'clusters.imageCredentials.add': 'Add Credential', diff --git a/src/locales/ru-RU/clusters.ts b/src/locales/ru-RU/clusters.ts index 565a8171..74751b2a 100644 --- a/src/locales/ru-RU/clusters.ts +++ b/src/locales/ru-RU/clusters.ts @@ -163,6 +163,9 @@ export default { 'clusters.volume.configMap.name': 'ConfigMap Name', 'clusters.volume.configMap.optional': 'Optional', 'clusters.volume.add': 'Add Volume Mount', + 'clusters.systemDefaultContainerRegistry.title': 'Default Container Registry', + 'clusters.systemDefaultContainerRegistry.tip': + 'Default registry used to resolve GPUStack images for this cluster. Falls back to the server default when unset.', 'clusters.k8sOptions.title': 'K8s Deployment Options', 'clusters.imageCredentials.title': 'Image Credentials', 'clusters.imageCredentials.add': 'Add Credential', diff --git a/src/locales/tr-TR/clusters.ts b/src/locales/tr-TR/clusters.ts index d46ecfdc..eb02c863 100644 --- a/src/locales/tr-TR/clusters.ts +++ b/src/locales/tr-TR/clusters.ts @@ -163,6 +163,9 @@ export default { 'clusters.volume.configMap.name': 'ConfigMap Name', 'clusters.volume.configMap.optional': 'Optional', 'clusters.volume.add': 'Add Volume Mount', + 'clusters.systemDefaultContainerRegistry.title': 'Default Container Registry', + 'clusters.systemDefaultContainerRegistry.tip': + 'Default registry used to resolve GPUStack images for this cluster. Falls back to the server default when unset.', 'clusters.k8sOptions.title': 'K8s Deployment Options', 'clusters.imageCredentials.title': 'Image Credentials', 'clusters.imageCredentials.add': 'Add Credential', diff --git a/src/locales/zh-CN/clusters.ts b/src/locales/zh-CN/clusters.ts index acd07485..698336d2 100644 --- a/src/locales/zh-CN/clusters.ts +++ b/src/locales/zh-CN/clusters.ts @@ -155,6 +155,9 @@ export default { 'clusters.volume.configMap.name': '配置名称', 'clusters.volume.configMap.optional': '可选', 'clusters.volume.add': '添加卷挂载', + 'clusters.systemDefaultContainerRegistry.title': '默认容器镜像仓库', + 'clusters.systemDefaultContainerRegistry.tip': + '用于解析该集群 GPUStack 镜像的默认镜像仓库。未设置时回退到服务端默认值。', 'clusters.k8sOptions.title': 'K8s 部署选项', 'clusters.imageCredentials.title': '镜像仓库凭证', 'clusters.imageCredentials.add': '添加凭证', diff --git a/src/pages/cluster-management/components/cluster-form.tsx b/src/pages/cluster-management/components/cluster-form.tsx index 710964c7..85d46526 100644 --- a/src/pages/cluster-management/components/cluster-form.tsx +++ b/src/pages/cluster-management/components/cluster-form.tsx @@ -64,8 +64,18 @@ const ClusterForm: React.FC = forwardRef( // "no auth". Coerce empty form values to null before sending so a blank // input is unambiguous rather than an empty string that defeats fallbacks. const normalizeOutgoing = (values: any): any => { - const opts = values?.k8s_options; - if (!opts) return values; + const base: any = { ...values }; + // Top-level cluster field shared by Docker and K8s. Trim then coerce a + // blank input to null so clearing it on edit (or a whitespace-only + // value) falls back to the server default rather than persisting an + // empty string. + if (base.system_default_container_registry !== undefined) { + base.system_default_container_registry = + base.system_default_container_registry?.trim() || null; + } + + const opts = base.k8s_options; + if (!opts) return base; const next: any = { ...opts }; @@ -90,7 +100,7 @@ const ClusterForm: React.FC = forwardRef( }; } - return { ...values, k8s_options: next }; + return { ...base, k8s_options: next }; }; const handleOnFinish = (_values: FormData) => { diff --git a/src/pages/cluster-management/config/yaml-template.ts b/src/pages/cluster-management/config/yaml-template.ts index b9b2b6ee..75b4a41d 100644 --- a/src/pages/cluster-management/config/yaml-template.ts +++ b/src/pages/cluster-management/config/yaml-template.ts @@ -9,7 +9,6 @@ export const dockerConfig = `# This is a template for worker_config. # ========= container & image =========== -# system_default_container_registry: "docker.io" # image_name_override: "gpustack/gpustack:dev" # image_repo: "gpustack/gpustack" @@ -53,7 +52,6 @@ export const kubernetesConfig = `# This is a template for worker_config. # ========= container & image =========== -# system_default_container_registry: "docker.io" # image_name_override: "gpustack/gpustack:dev" # image_repo: "gpustack/gpustack" diff --git a/src/pages/cluster-management/step-forms/advance-config.tsx b/src/pages/cluster-management/step-forms/advance-config.tsx index 76e5f9a9..69bf13ff 100644 --- a/src/pages/cluster-management/step-forms/advance-config.tsx +++ b/src/pages/cluster-management/step-forms/advance-config.tsx @@ -88,6 +88,24 @@ const ClusterAdvanceConfig: React.FC<{ > + {/* Default container registry used to resolve images for this cluster. + A top-level cluster field shared by both Docker and Kubernetes + providers (the backend hoists any legacy worker_config value onto + this column). */} + + name="system_default_container_registry" + style={{ marginBottom: 16 }} + > + + {intl.formatMessage({ id: 'clusters.create.workerConfig' })}