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) => (
+
+ ))}
+
{isAdmin && (