diff --git a/src/locales/en-US/clusters.ts b/src/locales/en-US/clusters.ts index 5de8a34c..1cfdf03e 100644 --- a/src/locales/en-US/clusters.ts +++ b/src/locales/en-US/clusters.ts @@ -68,8 +68,12 @@ Same applies to the /opt/dtk directory.`, 'clusters.addworker.checkEnv': 'Check Environment', 'clusters.addworker.specifyArgs': 'Specify Arguments', 'clusters.addworker.runCommand': 'Run Command', - 'clusters.addworker.specifyWorkerIP': 'Specify Worker IP', - 'clusters.addworker.detectWorkerIP': 'Auto-detect Worker IP', + 'clusters.addworker.specifyWorkerIP': + 'Specify Worker IP {type}', + 'clusters.addworker.detectWorkerIP': + 'Auto-detect Worker IP {type}', + 'clusters.addworker.externalIP.tips': + 'Specify an external IP if the worker is in a VPC or private network.', 'clusters.addworker.enterWorkerIP': 'Enter worker IP', 'clusters.addworker.enterWorkerIP.error': 'Please enter the worker IP.', 'clusters.addworker.extraVolume': 'Additional Volume Mount', @@ -78,7 +82,8 @@ Same applies to the /opt/dtk directory.`, 'If you want to customize the model cache directory, you can specify the path to mount it.', 'clusters.addworker.configSummary': 'Configuration Summary', 'clusters.addworker.gpuVendor': 'GPU Vendor', - 'clusters.addworker.workerIP': 'Worker IP', + 'clusters.addworker.workerIP': + 'Worker IP {type}', 'clusters.addworker.notSpecified': 'Not Specified', 'clusters.addworker.autoDetect': 'Auto-detect', 'clusters.addworker.extraVolume.holder': diff --git a/src/locales/ja-JP/clusters.ts b/src/locales/ja-JP/clusters.ts index b9ba21fd..f3e39ca8 100644 --- a/src/locales/ja-JP/clusters.ts +++ b/src/locales/ja-JP/clusters.ts @@ -68,8 +68,12 @@ Same applies to the /opt/dtk directory.`, 'clusters.addworker.checkEnv': 'Check Environment', 'clusters.addworker.specifyArgs': 'Specify Arguments', 'clusters.addworker.runCommand': 'Run Command', - 'clusters.addworker.specifyWorkerIP': 'Specify Worker IP', - 'clusters.addworker.detectWorkerIP': 'Auto-detect Worker IP', + 'clusters.addworker.specifyWorkerIP': + 'Specify Worker IP {type}', + 'clusters.addworker.externalIP.tips': + 'Specify an external IP if the worker is in a VPC or private network.', + 'clusters.addworker.detectWorkerIP': + 'Auto-detect Worker IP {type}', 'clusters.addworker.enterWorkerIP': 'Enter worker IP', 'clusters.addworker.enterWorkerIP.error': 'Please enter the worker IP.', 'clusters.addworker.extraVolume': 'Additional Volume Mount', @@ -78,7 +82,8 @@ Same applies to the /opt/dtk directory.`, 'If you want to customize the model cache directory, you can specify the path to mount it.', 'clusters.addworker.configSummary': 'Configuration Summary', 'clusters.addworker.gpuVendor': 'GPU Vendor', - 'clusters.addworker.workerIP': 'Worker IP', + 'clusters.addworker.workerIP': + 'Worker IP {type}', 'clusters.addworker.notSpecified': 'Not Specified', 'clusters.addworker.autoDetect': 'Auto-detect', 'clusters.addworker.extraVolume.holder': @@ -171,7 +176,7 @@ Same applies to the /opt/dtk directory.`, // 61. 'clusters.addworker.extraVolume': 'Additional Volume Mount', // 62. 'clusters.addworker.configSummary': 'Configuration Summary', // 63. 'clusters.addworker.gpuVendor': 'GPU Vendor', -// 64. 'clusters.addworker.workerIP': 'Worker IP', +// 64. 'clusters.addworker.workerIP': 'Worker IP {type}', // 65. 'clusters.addworker.notSpecified': 'Not Specified', // 66. 'clusters.addworker.autoDetect': 'Auto-detect', // 67. 'clusters.addworker.extraVolume.holder': 'e.g. /data/models (path must start with /)' @@ -191,5 +196,6 @@ Same applies to the /opt/dtk directory.`, // 78. 'clusters.addworker.dataVolume.tips': 'Specify a data storage path for GPUStack.', // 79. 'clusters.table.ip.internal': 'Internal', // 80. 'clusters.table.ip.external': 'External', -// 81. 'clusters.form.serverUrl.tips': 'Specify the server URL accessible from your cloud provider.' +// 81. 'clusters.form.serverUrl.tips': 'Specify the server URL accessible from your cloud provider.', +// 82. 'clusters.addworker.externalIP.tips': 'Specify an external IP if the worker is in a VPC or private network.', // ========== End of To-Do List ========== diff --git a/src/locales/ru-RU/clusters.ts b/src/locales/ru-RU/clusters.ts index b66f94a5..bd3f7b9d 100644 --- a/src/locales/ru-RU/clusters.ts +++ b/src/locales/ru-RU/clusters.ts @@ -68,8 +68,12 @@ export default { 'clusters.addworker.checkEnv': 'Проверить окружение', 'clusters.addworker.specifyArgs': 'Указать аргументы', 'clusters.addworker.runCommand': 'Выполнить команду', - 'clusters.addworker.specifyWorkerIP': 'Указать IP воркера', - 'clusters.addworker.detectWorkerIP': 'Автоопределение IP воркера', + 'clusters.addworker.specifyWorkerIP': + 'Указать IP воркера {type}', + 'clusters.addworker.externalIP.tips': + 'Specify an external IP if the worker is in a VPC or private network.', + 'clusters.addworker.detectWorkerIP': + 'Автоопределение IP воркера {type}', 'clusters.addworker.enterWorkerIP': 'Введите IP воркера', 'clusters.addworker.enterWorkerIP.error': 'Пожалуйста, введите IP воркера.', 'clusters.addworker.extraVolume': 'Дополнительное монтирование тома', @@ -78,7 +82,8 @@ export default { 'If you want to customize the model cache directory, you can specify the path to mount it.', 'clusters.addworker.configSummary': 'Сводка конфигурации', 'clusters.addworker.gpuVendor': 'Производитель GPU', - 'clusters.addworker.workerIP': 'IP воркера', + 'clusters.addworker.workerIP': + 'IP воркера {type}', 'clusters.addworker.notSpecified': 'Не указано', 'clusters.addworker.autoDetect': 'Автоопределение', 'clusters.addworker.extraVolume.holder': @@ -123,4 +128,5 @@ export default { // 10. 'clusters.table.ip.internal': 'Internal', // 11. 'clusters.table.ip.external': 'External', // 12. 'clusters.form.serverUrl.tips': 'Specify the server URL accessible from your cloud provider.' +// 13. 'clusters.addworker.specifyWorkerIP': 'Specify Worker IP {type}', // ================================================================ diff --git a/src/locales/zh-CN/clusters.ts b/src/locales/zh-CN/clusters.ts index 324f72a9..e56a7891 100644 --- a/src/locales/zh-CN/clusters.ts +++ b/src/locales/zh-CN/clusters.ts @@ -66,8 +66,12 @@ export default { 'clusters.addworker.checkEnv': '检查环境', 'clusters.addworker.specifyArgs': '指定参数', 'clusters.addworker.runCommand': '运行指令', - 'clusters.addworker.specifyWorkerIP': '指定 Worker IP', - 'clusters.addworker.detectWorkerIP': '自动检测 Worker IP', + 'clusters.addworker.specifyWorkerIP': + '指定 Worker IP {type}', + 'clusters.addworker.detectWorkerIP': + '自动检测 Worker IP {type}', + 'clusters.addworker.externalIP.tips': + '当 worker 位于 VPC 或私有网络时,需要指定外部 IP。', 'clusters.addworker.enterWorkerIP': '输入节点 IP', 'clusters.addworker.enterWorkerIP.error': '请输入节点 IP', 'clusters.addworker.extraVolume': '额外卷挂载', @@ -76,7 +80,8 @@ export default { '如果你想自定义模型缓存目录,可以指定路径进行挂载。', 'clusters.addworker.configSummary': '配置摘要', 'clusters.addworker.gpuVendor': 'GPU 厂商', - 'clusters.addworker.workerIP': '节点 IP', + 'clusters.addworker.workerIP': + '节点 IP {type}', 'clusters.addworker.notSpecified': '未指定', 'clusters.addworker.autoDetect': '自动检测', 'clusters.addworker.extraVolume.holder': diff --git a/src/pages/cluster-management/cluster-create.tsx b/src/pages/cluster-management/cluster-create.tsx index 35bbab31..f80f49e7 100644 --- a/src/pages/cluster-management/cluster-create.tsx +++ b/src/pages/cluster-management/cluster-create.tsx @@ -54,6 +54,7 @@ const ClusterCreate = () => { image: string; server_url: string; cluster_id: number; + [key: string]: any; }>({ token: '', image: '', diff --git a/src/pages/cluster-management/components/add-worker-command.tsx b/src/pages/cluster-management/components/add-worker-command.tsx index 96e98400..95a0a17f 100644 --- a/src/pages/cluster-management/components/add-worker-command.tsx +++ b/src/pages/cluster-management/components/add-worker-command.tsx @@ -9,15 +9,18 @@ type ViewModalProps = { cacheDir?: string; containerName?: string; gpustackDataVolume?: string; + advertisAddress?: string; registrationInfo: { token: string; image: string; server_url: string; + [key: string]: any; }; }; const AddWorkerCommand: React.FC = ({ registrationInfo, + advertisAddress, workerIP, modelDir, cacheDir, @@ -29,9 +32,11 @@ const AddWorkerCommand: React.FC = ({ const commandCode = addWorkerGuide['all']; return commandCode ?.registerWorker({ + registrationInfo, gpu: currentGPU || '', server: registrationInfo.server_url || origin, tag: '', + advertisAddress: advertisAddress, workerIP: workerIP, modelDir: modelDir, cacheDir: cacheDir, @@ -50,7 +55,8 @@ const AddWorkerCommand: React.FC = ({ modelDir, cacheDir, containerName, - gpustackDataVolume + gpustackDataVolume, + advertisAddress ]); return ( diff --git a/src/pages/cluster-management/components/add-worker/add-worker-step.tsx b/src/pages/cluster-management/components/add-worker/add-worker-step.tsx index 3ca44dc7..5a0af073 100644 --- a/src/pages/cluster-management/components/add-worker/add-worker-step.tsx +++ b/src/pages/cluster-management/components/add-worker/add-worker-step.tsx @@ -42,6 +42,7 @@ type AddWorkerProps = { image: string; server_url: string; cluster_id: number; + [key: string]: any; }; }; diff --git a/src/pages/cluster-management/components/add-worker/config.ts b/src/pages/cluster-management/components/add-worker/config.ts index 447d61ec..d2ec6eb5 100644 --- a/src/pages/cluster-management/components/add-worker/config.ts +++ b/src/pages/cluster-management/components/add-worker/config.ts @@ -59,6 +59,11 @@ export interface SummaryDataKeys { enabled: boolean; path: string; }; + externalWorkerIPConfig: { + enable: boolean; + ip: string; + required: boolean; + }; } export type SummaryDataMap = { diff --git a/src/pages/cluster-management/components/add-worker/docker-run-command.tsx b/src/pages/cluster-management/components/add-worker/docker-run-command.tsx index b6ffb253..425f494d 100644 --- a/src/pages/cluster-management/components/add-worker/docker-run-command.tsx +++ b/src/pages/cluster-management/components/add-worker/docker-run-command.tsx @@ -9,13 +9,17 @@ import VendorNotes from './vendor-notes'; const DockerRunCommand = () => { const intl = useIntl(); - const { registrationInfo, stepList, summary, clusterList } = - useAddWorkerContext(); + const { registrationInfo, stepList, summary } = useAddWorkerContext(); const workerIPConfig = summary.get('workerIPConfig') || { enable: false, ip: '', required: false }; + const externalWorkerIPConfig = summary.get('externalWorkerIPConfig') || { + enable: false, + ip: '', + required: false + }; const modelDirConfig = summary.get('modelDirConfig') || { enable: false, path: '', @@ -62,6 +66,9 @@ const DockerRunCommand = () => { { ip: '', required: false }; + + const externalWorkerIPConfig = summary.get('externalWorkerIPConfig') || { + enable: false, + ip: '', + required: false + }; + const modelDirConfig = summary.get('modelDirConfig') || { enable: false, path: '' @@ -143,6 +150,15 @@ const SpecifyArguments = () => { return false; } + if (externalWorkerIPConfig.enable && !externalWorkerIPConfig.ip) { + updateField('externalWorkerIPConfig', { + ...externalWorkerIPConfig, + required: true + }); + + return false; + } + return true; }; @@ -189,6 +205,12 @@ const SpecifyArguments = () => { enable: true, path: 'gpustack-data' }); + + updateField('externalWorkerIPConfig', { + enable: false, + ip: '', + required: false + }); }, []); return ( @@ -213,13 +235,27 @@ const SpecifyArguments = () => { {/* worker IP config */} } placeholder={intl.formatMessage({ id: 'clusters.addworker.enterWorkerIP' @@ -274,6 +310,83 @@ const SpecifyArguments = () => { ) } > + {/* external worker ip config */} + + } + placeholder={intl.formatMessage({ + id: 'clusters.addworker.enterWorkerIP' + })} + value={externalWorkerIPConfig.ip} + checked={externalWorkerIPConfig.enable} + errorMessage={ + externalWorkerIPConfig.required && + !externalWorkerIPConfig.ip && + intl.formatMessage({ + id: 'clusters.addworker.enterWorkerIP.error' + }) + } + onChange={(checked) => + updateField('externalWorkerIPConfig', { + ...externalWorkerIPConfig, + enable: checked, + required: false + }) + } + onInputChange={(value) => + updateField('externalWorkerIPConfig', { + ...externalWorkerIPConfig, + ip: value + }) + } + extra={ + !externalWorkerIPConfig.enable && ( + } + message={ + +
  • + {intl.formatMessage({ + id: 'clusters.addworker.externalIP.tips' + })} +
  • +
    + } + >
    + ) + } + >
    {/* cache directory config */} { path: '' }; + const externalWorkerIPConfig = summary.get('externalWorkerIPConfig') || { + enable: false, + ip: '' + }; + return ( @@ -120,7 +125,18 @@ const SummaryData: React.FC = () => { ></DataItem> <DataItem - label={intl.formatMessage({ id: 'clusters.addworker.workerIP' })} + label={ + <span + dangerouslySetInnerHTML={{ + __html: intl.formatMessage( + { id: 'clusters.addworker.workerIP' }, + { + type: `(${intl.formatMessage({ id: 'clusters.table.ip.internal' })})` + } + ) + }} + ></span> + } tips={ workerIPConfig.enable ? workerIPConfig.ip @@ -133,6 +149,31 @@ const SummaryData: React.FC = () => { required={true} ></DataItem> + <DataItem + label={ + <span + dangerouslySetInnerHTML={{ + __html: intl.formatMessage( + { id: 'clusters.addworker.workerIP' }, + { + type: `(${intl.formatMessage({ id: 'clusters.table.ip.external' })})` + } + ) + }} + ></span> + } + tips={ + externalWorkerIPConfig.enable + ? externalWorkerIPConfig.ip + ? '' + : intl.formatMessage({ id: 'clusters.addworker.notSpecified' }) + : intl.formatMessage({ id: 'clusters.addworker.autoDetect' }) + } + enable={externalWorkerIPConfig.enable} + value={externalWorkerIPConfig.ip} + required={true} + ></DataItem> + <DataItem label={intl.formatMessage({ id: 'clusters.addworker.extraVolume' })} enable={modelDirConfig.enable} diff --git a/src/pages/cluster-management/hooks/use-pools-columns.tsx b/src/pages/cluster-management/hooks/use-pools-columns.tsx index 0821d896..0e21b713 100644 --- a/src/pages/cluster-management/hooks/use-pools-columns.tsx +++ b/src/pages/cluster-management/hooks/use-pools-columns.tsx @@ -73,8 +73,8 @@ const usePoolsColumns = ( } }} data={{ - vendor: record.instance_spec.vendor, - description: record.instance_spec.description, + vendor: record.instance_spec?.vendor, + description: record.instance_spec?.description, specInfo: _.omit(record.instance_spec, [ 'label', 'vendor', @@ -83,11 +83,11 @@ const usePoolsColumns = ( }} /> } - showTitle + SHOWTITLE ghost minWidth={20} > - {record.instance_spec.description || record.instance_spec.label} + {record.instance_spec?.description || record.instance_spec?.label} </AutoTooltip> ) }, diff --git a/src/pages/resources/config/gpu-driver.ts b/src/pages/resources/config/gpu-driver.ts index 82c57fc4..f7281038 100644 --- a/src/pages/resources/config/gpu-driver.ts +++ b/src/pages/resources/config/gpu-driver.ts @@ -143,9 +143,23 @@ interface AddWorkerCommandParams { cacheDir?: string; } +const generateEnvArgs = (params: any) => { + const registrationInfo = params.registrationInfo || {}; + // generate environment variables args from registrationInfo.env + let envArgs = ''; + if (registrationInfo.env && typeof registrationInfo.env === 'object') { + Object.keys(registrationInfo.env).forEach((key) => { + const value = registrationInfo.env[key]; + envArgs += `-e "${key}=${value}" \\\n `; + }); + } + return envArgs; +}; + const setNormalArgs = (params: any) => { return `sudo docker run -d --name ${params.containerName || 'gpustack-worker'} \\ -e "GPUSTACK_RUNTIME_DEPLOY_MIRRORED_NAME=${params.containerName || 'gpustack-worker'}" \\ + ${generateEnvArgs(params)} --restart=unless-stopped \\ --privileged \\ --network=host \\ @@ -155,6 +169,11 @@ const setNormalArgs = (params: any) => { ${params.cacheDir ? `--volume ${params.cacheDir}:/var/lib/gpustack/cache \\` : ''}`; }; +const setWorkerIPArg = (params: any) => { + return `${params.workerIP ? `--worker-ip ${params.workerIP} \\` : ''} + ${params.advertisAddress ? `--advertise-address ${params.advertisAddress} \\` : ''}`; +}; + const setImageArgs = (params: any) => { return `${params.image} \\ --server-url ${params.server} \\ @@ -171,7 +190,7 @@ const registerWorker = (params: AddWorkerCommandParams) => { return `${commonArgs} --runtime ${config.runtime} \\ ${imageArgs} - ${params.workerIP ? `--advertise-address ${params.workerIP} \\` : ''}`; + ${setWorkerIPArg(params)}`; }; // avaliable for AMD @@ -184,7 +203,7 @@ const registerAMDWorker = (params: AddWorkerCommandParams) => { --volume /opt/rocm:/opt/rocm:ro \\ --runtime ${config.runtime} \\ ${imageArgs} - ${params.workerIP ? `--advertise-address ${params.workerIP} \\` : ''}`; + ${setWorkerIPArg(params)}`; }; // avaliable for Ascend @@ -196,7 +215,7 @@ const registerAscendWorker = (params: AddWorkerCommandParams) => { --env "ASCEND_VISIBLE_DEVICES=$(sudo ls /dev/davinci* | head -1 | grep -o '[0-9]\\+' || echo "0")" \\ --runtime ${config.runtime} \\ ${imageArgs} - ${params.workerIP ? `--advertise-address ${params.workerIP} \\` : ''}`; + ${setWorkerIPArg(params)}`; }; const registerHygonWorker = (params: AddWorkerCommandParams) => { @@ -209,7 +228,7 @@ const registerHygonWorker = (params: AddWorkerCommandParams) => { --env ROCM_PATH=/opt/dtk \\ --env ROCM_SMI_LIB_PATH=/opt/hyhal/lib \\ ${imageArgs} - ${params.workerIP ? `--advertise-address ${params.workerIP} \\` : ''}`; + ${setWorkerIPArg(params)}`; }; const registerIluvatarWorker = (params: AddWorkerCommandParams) => { @@ -222,7 +241,7 @@ const registerIluvatarWorker = (params: AddWorkerCommandParams) => { --volume /usr/bin/ixsmi:/usr/bin/ixsmi \\ --runtime ${config.runtime} \\ ${imageArgs} - ${params.workerIP ? `--advertise-address ${params.workerIP} \\` : ''}`; + ${setWorkerIPArg(params)}`; }; const registerMetaXWorker = (params: AddWorkerCommandParams) => { @@ -233,7 +252,7 @@ const registerMetaXWorker = (params: AddWorkerCommandParams) => { --volume /opt/mxdriver:/opt/mxdriver:ro \\ --volume /opt/maca:/opt/maca:ro \\ ${imageArgs} - ${params.workerIP ? `--advertise-address ${params.workerIP} \\` : ''}`; + ${setWorkerIPArg(params)}`; }; const registerCambriconWorker = (params: AddWorkerCommandParams) => { @@ -244,7 +263,7 @@ const registerCambriconWorker = (params: AddWorkerCommandParams) => { --volume /usr/local/neuware:/usr/local/neuware:ro \\ --volume /usr/bin/cnmon:/usr/bin/cnmon \\ ${imageArgs} - ${params.workerIP ? `--advertise-address ${params.workerIP} \\` : ''}`; + ${setWorkerIPArg(params)}`; }; export const registerAddWokerCommandMap = { diff --git a/src/pages/resources/config/index.ts b/src/pages/resources/config/index.ts index 0fce6d88..79abc6a5 100644 --- a/src/pages/resources/config/index.ts +++ b/src/pages/resources/config/index.ts @@ -64,6 +64,7 @@ export const addWorkerGuide: Record<string, any> = { token: string; image: string; gpu: string; + [key: string]: any; }) { return registerAddWokerCommandMap[params.gpu]?.(params); },