diff --git a/public/static/locales/en/tools.json b/public/static/locales/en/tools.json index 48beb5317..9bde85cd3 100644 --- a/public/static/locales/en/tools.json +++ b/public/static/locales/en/tools.json @@ -54,12 +54,16 @@ "maxCPUCoresLbl": "Maximum CPU Cores", "memoryLimit": "Memory Limit", "memoryLimitLabel": "Memory Limit (bytes)", + "maxGPUs": "Max GPUs", + "maxGPUsLbl": "Maximum GPUs", "minCPUCores": "Min CPU Cores", "minCPUCoresLbl": "Minimum CPU Cores", "minDiskSpace": "Min Disk Space", "minDiskSpaceLbl": "Minimum Disk Space (bytes)", "minMemoryLimit": "Min Memory Limit", "minMemoryLimitLbl": "Minimum Memory", + "minGPUs": "Min GPUs", + "minGPUsLbl": "Minimum GPUs", "myTools": "Only my tools", "name": "Name", "namePrefix": "Name Prefix", @@ -141,8 +145,10 @@ "useToolInApp": "Use in app", "validationErrMaxCPUsLessThanMin": "Must be greater than Min CPU Cores", "validationErrMaxRAMLessThanMin": "Must be greater than Min Memory", + "validationErrMaxGPUsLessThanMin": "Must be greater than Min GPUs", "validationErrMinCPUsGreaterThanMax": "Must be less than Max CPU Cores", "validationErrMinRAMGreaterThanMax": "Must be less than Max Memory", + "validationErrMinGPUsGreaterThanMax": "Must be less than Max GPUs", "validationErrMustBePositive": "Must be at least 0", "versionLbl": "Version", "viewFilter": "View Filter", diff --git a/src/components/tools/details/ToolDetails.js b/src/components/tools/details/ToolDetails.js index 5b4d1056f..991ecf49e 100644 --- a/src/components/tools/details/ToolDetails.js +++ b/src/components/tools/details/ToolDetails.js @@ -78,6 +78,12 @@ export default function ToolDetails(props) { {tool.container.min_disk_space} + + {tool.container.min_gpus} + + + {tool.container.max_gpus} + {t("restrictionsLabel")} diff --git a/src/components/tools/edit/EditTool.js b/src/components/tools/edit/EditTool.js index 52b28afe6..01bcb4d11 100644 --- a/src/components/tools/edit/EditTool.js +++ b/src/components/tools/edit/EditTool.js @@ -86,6 +86,7 @@ function EditToolDialog(props) { const maxCPUCore = resourceConfigs?.max_cpu_limit; const maxMemory = resourceConfigs?.max_memory_limit; const maxDiskSpace = resourceConfigs?.max_disk_limit; + const maxGPU = resourceConfigs?.max_gpu_limit; // Get QueryClient from the context const queryClient = useQueryClient(); @@ -313,6 +314,7 @@ function EditToolDialog(props) { maxCPUCore={maxCPUCore} maxMemory={maxMemory} maxDiskSpace={maxDiskSpace} + maxGPU={maxGPU} values={values} /> )} @@ -428,6 +430,7 @@ function EditToolForm(props) { maxCPUCore, maxMemory, maxDiskSpace, + maxGPU, classes, values, } = props; @@ -628,6 +631,7 @@ function EditToolForm(props) { maxDiskSpace={maxDiskSpace} maxCPUCore={maxCPUCore} maxMemory={maxMemory} + maxGPU={maxGPU} component={Restrictions} /> diff --git a/src/components/tools/edit/ToolRestrictions.js b/src/components/tools/edit/ToolRestrictions.js index c4f0c3d3b..9cbdb68af 100644 --- a/src/components/tools/edit/ToolRestrictions.js +++ b/src/components/tools/edit/ToolRestrictions.js @@ -43,6 +43,7 @@ function Restrictions(props) { maxCPUCore, maxMemory, maxDiskSpace, + maxGPU, form: { values }, } = props; @@ -57,6 +58,7 @@ function Restrictions(props) { globalConstants.ONE_GiB, maxDiskSpace ); + const gpuLimitList = maxGPU === 0 ? [0] : buildLimitList(1, maxGPU ?? 8); const validateMinCPUs = (value) => { if (value && value < 0) { @@ -102,6 +104,28 @@ function Restrictions(props) { } }; + const validateMinGpus = (value) => { + if (value && value < 0) { + return t("validationErrMustBePositive"); + } + + const gpu_limit = getIn(values, "container.max_gpus"); + if (gpu_limit > 0 && value > gpu_limit) { + return t("validationErrMinGpusGreaterThanMax"); + } + }; + + const validateMaxGpus = (value) => { + if (value && value < 0) { + return t("validationErrMustBePositive"); + } + + const min_gpu_limit = getIn(values, "container.min_gpus"); + if (0 < value && value < min_gpu_limit) { + return t("validationErrMaxGpusLessThanMin"); + } + }; + return ( {isAdmin && ( @@ -173,6 +197,36 @@ function Restrictions(props) { ))} + {isAdmin && ( + + )} + + {gpuLimitList.map((size, index) => ( + + {size} + + ))} + {isAdmin && (