Skip to content

Commit 940c0ee

Browse files
committed
Enhance OpenAPI descriptions for resource sizing with Kubernetes syntax references and add handling for QuantityFormatException.
1 parent eecfe03 commit 940c0ee

16 files changed

Lines changed: 505 additions & 140 deletions

File tree

api/src/integrationTest/kotlin/com/cosmotech/api/home/dataset/DatasetControllerTests.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,8 @@ class DatasetControllerTests : ControllerTestBase() {
8484

8585
val runTemplateRunSizing =
8686
RunTemplateResourceSizing(
87-
com.cosmotech.solution.domain.ResourceSizeInfo("cpu_requests", "memory_requests"),
88-
com.cosmotech.solution.domain.ResourceSizeInfo("cpu_limits", "memory_limits"),
87+
com.cosmotech.solution.domain.ResourceSizeInfo("1", "2G"),
88+
com.cosmotech.solution.domain.ResourceSizeInfo("1", "2G"),
8989
)
9090

9191
val runTemplates =

api/src/integrationTest/kotlin/com/cosmotech/api/home/run/RunControllerTests.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,8 +108,8 @@ class RunControllerTests : ControllerTestBase() {
108108

109109
val runTemplateRunSizing =
110110
RunTemplateResourceSizing(
111-
com.cosmotech.solution.domain.ResourceSizeInfo("cpu_requests", "memory_requests"),
112-
com.cosmotech.solution.domain.ResourceSizeInfo("cpu_limits", "memory_limits"),
111+
com.cosmotech.solution.domain.ResourceSizeInfo("1", "2G"),
112+
com.cosmotech.solution.domain.ResourceSizeInfo("1", "2G"),
113113
)
114114

115115
val runTemplates =

api/src/integrationTest/kotlin/com/cosmotech/api/home/runner/RunnerControllerTests.kt

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,8 @@ class RunnerControllerTests : ControllerTestBase() {
8686
val parameterLabels = mutableMapOf("fr" to "this_is_a_label")
8787
val runTemplateRunSizing =
8888
RunTemplateResourceSizing(
89-
com.cosmotech.solution.domain.ResourceSizeInfo("cpu_requests", "memory_requests"),
90-
com.cosmotech.solution.domain.ResourceSizeInfo("cpu_limits", "memory_limits"),
89+
com.cosmotech.solution.domain.ResourceSizeInfo("1", "2G"),
90+
com.cosmotech.solution.domain.ResourceSizeInfo("1", "2G"),
9191
)
9292

9393
val parametersList =
@@ -288,13 +288,13 @@ class RunnerControllerTests : ControllerTestBase() {
288288
RunnerResourceSizing(
289289
requests =
290290
ResourceSizeInfo(
291-
cpu = "cpu_requests",
292-
memory = "memory_requests",
291+
cpu = "1",
292+
memory = "2G",
293293
),
294294
limits =
295295
ResourceSizeInfo(
296-
cpu = "cpu_limits",
297-
memory = "memory_limits",
296+
cpu = "1",
297+
memory = "2G",
298298
),
299299
),
300300
additionalData = additionalData,
@@ -335,10 +335,10 @@ class RunnerControllerTests : ControllerTestBase() {
335335
.andExpect(jsonPath("$.datasets.parameters[0].sourceName").value(TEST_FILE_NAME))
336336
.andExpect(jsonPath("$.datasets.parameters[0].type").value(DatasetPartTypeEnum.File.name))
337337
.andExpect(jsonPath("$.security.default").value(ROLE_NONE))
338-
.andExpect(jsonPath("$.runSizing.requests.cpu").value("cpu_requests"))
339-
.andExpect(jsonPath("$.runSizing.requests.memory").value("memory_requests"))
340-
.andExpect(jsonPath("$.runSizing.limits.cpu").value("cpu_limits"))
341-
.andExpect(jsonPath("$.runSizing.limits.memory").value("memory_limits"))
338+
.andExpect(jsonPath("$.runSizing.requests.cpu").value("1"))
339+
.andExpect(jsonPath("$.runSizing.requests.memory").value("2G"))
340+
.andExpect(jsonPath("$.runSizing.limits.cpu").value("1"))
341+
.andExpect(jsonPath("$.runSizing.limits.memory").value("2G"))
342342
.andExpect(jsonPath("$.parametersValues[0].parameterId").value(solutionParameterId1))
343343
.andExpect(jsonPath("$.parametersValues[0].value").value(runnerParameterValue))
344344
.andExpect(jsonPath("$.parametersValues[0].varType").value(solutionParameterVarType1))
@@ -399,13 +399,13 @@ class RunnerControllerTests : ControllerTestBase() {
399399
RunnerResourceSizing(
400400
requests =
401401
ResourceSizeInfo(
402-
cpu = "cpu_requests",
403-
memory = "memory_requests",
402+
cpu = "1",
403+
memory = "2G",
404404
),
405405
limits =
406406
ResourceSizeInfo(
407-
cpu = "cpu_limits",
408-
memory = "memory_limits",
407+
cpu = "1",
408+
memory = "2G",
409409
),
410410
),
411411
additionalData = additionalData,
@@ -446,10 +446,10 @@ class RunnerControllerTests : ControllerTestBase() {
446446
.andExpect(jsonPath("$.datasets.parameters[0].type").value(DatasetPartTypeEnum.File.name))
447447
.andExpect(jsonPath("$.datasets.parameters[0].sourceName").value(TEST_FILE_NAME))
448448
.andExpect(jsonPath("$.security.default").value(ROLE_NONE))
449-
.andExpect(jsonPath("$.runSizing.requests.cpu").value("cpu_requests"))
450-
.andExpect(jsonPath("$.runSizing.requests.memory").value("memory_requests"))
451-
.andExpect(jsonPath("$.runSizing.limits.cpu").value("cpu_limits"))
452-
.andExpect(jsonPath("$.runSizing.limits.memory").value("memory_limits"))
449+
.andExpect(jsonPath("$.runSizing.requests.cpu").value("1"))
450+
.andExpect(jsonPath("$.runSizing.requests.memory").value("2G"))
451+
.andExpect(jsonPath("$.runSizing.limits.cpu").value("1"))
452+
.andExpect(jsonPath("$.runSizing.limits.memory").value("2G"))
453453
.andExpect(jsonPath("$.parametersValues[0].parameterId").value(solutionParameterId1))
454454
.andExpect(jsonPath("$.parametersValues[0].value").value(solutionParameterDefaultValue1))
455455
.andExpect(jsonPath("$.parametersValues[0].varType").value(solutionParameterVarType1))
@@ -499,13 +499,13 @@ class RunnerControllerTests : ControllerTestBase() {
499499
RunnerResourceSizing(
500500
requests =
501501
ResourceSizeInfo(
502-
cpu = "cpu_requests",
503-
memory = "memory_requests",
502+
cpu = "1",
503+
memory = "2G",
504504
),
505505
limits =
506506
ResourceSizeInfo(
507-
cpu = "cpu_limits",
508-
memory = "memory_limits",
507+
cpu = "1",
508+
memory = "2G",
509509
),
510510
),
511511
additionalData = additionalData,
@@ -547,10 +547,10 @@ class RunnerControllerTests : ControllerTestBase() {
547547
.andExpect(jsonPath("$.datasets.parameters[0].sourceName").value(TEST_FILE_NAME))
548548
.andExpect(jsonPath("$.datasets.parameters[0].type").value(DatasetPartTypeEnum.File.name))
549549
.andExpect(jsonPath("$.security.default").value(ROLE_NONE))
550-
.andExpect(jsonPath("$.runSizing.requests.cpu").value("cpu_requests"))
551-
.andExpect(jsonPath("$.runSizing.requests.memory").value("memory_requests"))
552-
.andExpect(jsonPath("$.runSizing.limits.cpu").value("cpu_limits"))
553-
.andExpect(jsonPath("$.runSizing.limits.memory").value("memory_limits"))
550+
.andExpect(jsonPath("$.runSizing.requests.cpu").value("1"))
551+
.andExpect(jsonPath("$.runSizing.requests.memory").value("2G"))
552+
.andExpect(jsonPath("$.runSizing.limits.cpu").value("1"))
553+
.andExpect(jsonPath("$.runSizing.limits.memory").value("2G"))
554554
.andExpect(jsonPath("$.parametersValues[0].parameterId").value(solutionParameterId1))
555555
.andExpect(jsonPath("$.parametersValues[0].value").value(runnerParameterValue))
556556
.andExpect(jsonPath("$.parametersValues[0].varType").value(solutionParameterVarType1))

api/src/integrationTest/kotlin/com/cosmotech/api/home/solution/SolutionControllerTests.kt

Lines changed: 40 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -200,8 +200,8 @@ class SolutionControllerTests : ControllerTestBase() {
200200
val runTemplateComputeSize = "this_is_a_compute_size"
201201
val runTemplateRunSizing =
202202
RunTemplateResourceSizing(
203-
ResourceSizeInfo("cpu_requests", "memory_requests"),
204-
ResourceSizeInfo("cpu_limits", "memory_limits"),
203+
ResourceSizeInfo("1", "2G"),
204+
ResourceSizeInfo("1", "2G"),
205205
)
206206
val runTemplates =
207207
mutableListOf(
@@ -275,10 +275,10 @@ class SolutionControllerTests : ControllerTestBase() {
275275
.andExpect(jsonPath("$.runTemplates[0].description").value(description))
276276
.andExpect(jsonPath("$.runTemplates[0].tags").value(tags))
277277
.andExpect(jsonPath("$.runTemplates[0].computeSize").value(runTemplateComputeSize))
278-
.andExpect(jsonPath("$.runTemplates[0].runSizing.requests.cpu").value("cpu_requests"))
279-
.andExpect(jsonPath("$.runTemplates[0].runSizing.requests.memory").value("memory_requests"))
280-
.andExpect(jsonPath("$.runTemplates[0].runSizing.limits.cpu").value("cpu_limits"))
281-
.andExpect(jsonPath("$.runTemplates[0].runSizing.limits.memory").value("memory_limits"))
278+
.andExpect(jsonPath("$.runTemplates[0].runSizing.requests.cpu").value("1"))
279+
.andExpect(jsonPath("$.runTemplates[0].runSizing.requests.memory").value("2G"))
280+
.andExpect(jsonPath("$.runTemplates[0].runSizing.limits.cpu").value("1"))
281+
.andExpect(jsonPath("$.runTemplates[0].runSizing.limits.memory").value("2G"))
282282
.andExpect(
283283
jsonPath("$.runTemplates[0].parameterGroups").value(mutableListOf(parameterGroupId))
284284
)
@@ -343,8 +343,8 @@ class SolutionControllerTests : ControllerTestBase() {
343343
val runTemplateComputeSize = "this_is_a_compute_size"
344344
val runTemplateRunSizing =
345345
RunTemplateResourceSizing(
346-
ResourceSizeInfo("cpu_requests", "memory_requests"),
347-
ResourceSizeInfo("cpu_limits", "memory_limits"),
346+
ResourceSizeInfo("1", "2G"),
347+
ResourceSizeInfo("1", "2G"),
348348
)
349349
val runTemplates =
350350
mutableListOf(
@@ -434,10 +434,10 @@ class SolutionControllerTests : ControllerTestBase() {
434434
.andExpect(jsonPath("$.runTemplates[0].description").value(description))
435435
.andExpect(jsonPath("$.runTemplates[0].tags").value(tags))
436436
.andExpect(jsonPath("$.runTemplates[0].computeSize").value(runTemplateComputeSize))
437-
.andExpect(jsonPath("$.runTemplates[0].runSizing.requests.cpu").value("cpu_requests"))
438-
.andExpect(jsonPath("$.runTemplates[0].runSizing.requests.memory").value("memory_requests"))
439-
.andExpect(jsonPath("$.runTemplates[0].runSizing.limits.cpu").value("cpu_limits"))
440-
.andExpect(jsonPath("$.runTemplates[0].runSizing.limits.memory").value("memory_limits"))
437+
.andExpect(jsonPath("$.runTemplates[0].runSizing.requests.cpu").value("1"))
438+
.andExpect(jsonPath("$.runTemplates[0].runSizing.requests.memory").value("2G"))
439+
.andExpect(jsonPath("$.runTemplates[0].runSizing.limits.cpu").value("1"))
440+
.andExpect(jsonPath("$.runTemplates[0].runSizing.limits.memory").value("2G"))
441441
.andExpect(
442442
jsonPath("$.runTemplates[0].parameterGroups").value(mutableListOf(parameterGroupId))
443443
)
@@ -1087,8 +1087,8 @@ class SolutionControllerTests : ControllerTestBase() {
10871087
runTemplateTags,
10881088
runTemplateComputeSize,
10891089
RunTemplateResourceSizing(
1090-
ResourceSizeInfo("cpu_requests", "memory_requests"),
1091-
ResourceSizeInfo("cpu_limits", "memory_limits"),
1090+
ResourceSizeInfo("1", "2G"),
1091+
ResourceSizeInfo("1", "2G"),
10921092
),
10931093
runTemplateParameterGroups,
10941094
10,
@@ -1114,10 +1114,10 @@ class SolutionControllerTests : ControllerTestBase() {
11141114
.andExpect(jsonPath("$[0].description").value(runTemplateDescription))
11151115
.andExpect(jsonPath("$[0].tags").value(runTemplateTags))
11161116
.andExpect(jsonPath("$[0].computeSize").value(runTemplateComputeSize))
1117-
.andExpect(jsonPath("$[0].runSizing.requests.cpu").value("cpu_requests"))
1118-
.andExpect(jsonPath("$[0].runSizing.requests.memory").value("memory_requests"))
1119-
.andExpect(jsonPath("$[0].runSizing.limits.cpu").value("cpu_limits"))
1120-
.andExpect(jsonPath("$[0].runSizing.limits.memory").value("memory_limits"))
1117+
.andExpect(jsonPath("$[0].runSizing.requests.cpu").value("1"))
1118+
.andExpect(jsonPath("$[0].runSizing.requests.memory").value("2G"))
1119+
.andExpect(jsonPath("$[0].runSizing.limits.cpu").value("1"))
1120+
.andExpect(jsonPath("$[0].runSizing.limits.memory").value("2G"))
11211121
.andExpect(jsonPath("$[0].parameterGroups").value(runTemplateParameterGroups))
11221122
.andExpect(jsonPath("$[0].executionTimeout").value(10))
11231123
.andDo(MockMvcResultHandlers.print())
@@ -1136,8 +1136,8 @@ class SolutionControllerTests : ControllerTestBase() {
11361136
val runTemplateComputeSize = "this_is_a_compute_size"
11371137
val runTemplateRunSizing =
11381138
RunTemplateResourceSizing(
1139-
ResourceSizeInfo("cpu_requests", "memory_requests"),
1140-
ResourceSizeInfo("cpu_limits", "memory_limits"),
1139+
ResourceSizeInfo("1", "2G"),
1140+
ResourceSizeInfo("1", "2G"),
11411141
)
11421142
val runTemplate =
11431143
RunTemplateCreateRequest(
@@ -1169,10 +1169,10 @@ class SolutionControllerTests : ControllerTestBase() {
11691169
.andExpect(jsonPath("$.description").value(description))
11701170
.andExpect(jsonPath("$.tags").value(tags))
11711171
.andExpect(jsonPath("$.computeSize").value(runTemplateComputeSize))
1172-
.andExpect(jsonPath("$.runSizing.requests.cpu").value("cpu_requests"))
1173-
.andExpect(jsonPath("$.runSizing.requests.memory").value("memory_requests"))
1174-
.andExpect(jsonPath("$.runSizing.limits.cpu").value("cpu_limits"))
1175-
.andExpect(jsonPath("$.runSizing.limits.memory").value("memory_limits"))
1172+
.andExpect(jsonPath("$.runSizing.requests.cpu").value("1"))
1173+
.andExpect(jsonPath("$.runSizing.requests.memory").value("2G"))
1174+
.andExpect(jsonPath("$.runSizing.limits.cpu").value("1"))
1175+
.andExpect(jsonPath("$.runSizing.limits.memory").value("2G"))
11761176
.andExpect(jsonPath("$.parameterGroups").value(mutableListOf(parameterGroupId)))
11771177
.andExpect(jsonPath("$.executionTimeout").value(10))
11781178
.andDo(MockMvcResultHandlers.print())
@@ -1201,8 +1201,8 @@ class SolutionControllerTests : ControllerTestBase() {
12011201
runTemplateTags,
12021202
runTemplateComputeSize,
12031203
RunTemplateResourceSizing(
1204-
ResourceSizeInfo("cpu_requests", "memory_requests"),
1205-
ResourceSizeInfo("cpu_limits", "memory_limits"),
1204+
ResourceSizeInfo("1", "2G"),
1205+
ResourceSizeInfo("1", "2G"),
12061206
),
12071207
runTemplateParameterGroups,
12081208
10,
@@ -1228,10 +1228,10 @@ class SolutionControllerTests : ControllerTestBase() {
12281228
.andExpect(jsonPath("$.description").value(runTemplateDescription))
12291229
.andExpect(jsonPath("$.tags").value(runTemplateTags))
12301230
.andExpect(jsonPath("$.computeSize").value(runTemplateComputeSize))
1231-
.andExpect(jsonPath("$.runSizing.requests.cpu").value("cpu_requests"))
1232-
.andExpect(jsonPath("$.runSizing.requests.memory").value("memory_requests"))
1233-
.andExpect(jsonPath("$.runSizing.limits.cpu").value("cpu_limits"))
1234-
.andExpect(jsonPath("$.runSizing.limits.memory").value("memory_limits"))
1231+
.andExpect(jsonPath("$.runSizing.requests.cpu").value("1"))
1232+
.andExpect(jsonPath("$.runSizing.requests.memory").value("2G"))
1233+
.andExpect(jsonPath("$.runSizing.limits.cpu").value("1"))
1234+
.andExpect(jsonPath("$.runSizing.limits.memory").value("2G"))
12351235
.andExpect(jsonPath("$.parameterGroups").value(runTemplateParameterGroups))
12361236
.andExpect(jsonPath("$.executionTimeout").value(10))
12371237
.andDo(MockMvcResultHandlers.print())
@@ -1256,8 +1256,8 @@ class SolutionControllerTests : ControllerTestBase() {
12561256
mutableListOf("tag1", "tag2"),
12571257
"this_is_a_compute_size",
12581258
RunTemplateResourceSizing(
1259-
ResourceSizeInfo("cpu_requests", "memory_requests"),
1260-
ResourceSizeInfo("cpu_limits", "memory_limits"),
1259+
ResourceSizeInfo("1", "2G"),
1260+
ResourceSizeInfo("1", "2G"),
12611261
),
12621262
mutableListOf("parameterGroup1"),
12631263
10,
@@ -1279,8 +1279,8 @@ class SolutionControllerTests : ControllerTestBase() {
12791279
val runTemplateComputeSize = "this_is_a_compute_size2"
12801280
val runTemplateRunSizing =
12811281
RunTemplateResourceSizing(
1282-
ResourceSizeInfo("cpu_requests2", "memory_requests2"),
1283-
ResourceSizeInfo("cpu_limits2", "memory_limits2"),
1282+
ResourceSizeInfo("2", "3G"),
1283+
ResourceSizeInfo("2", "3G"),
12841284
)
12851285
val newRunTemplate =
12861286
RunTemplateUpdateRequest(
@@ -1310,10 +1310,10 @@ class SolutionControllerTests : ControllerTestBase() {
13101310
.andExpect(jsonPath("$.description").value(description))
13111311
.andExpect(jsonPath("$.tags").value(tags))
13121312
.andExpect(jsonPath("$.computeSize").value(runTemplateComputeSize))
1313-
.andExpect(jsonPath("$.runSizing.requests.cpu").value("cpu_requests2"))
1314-
.andExpect(jsonPath("$.runSizing.requests.memory").value("memory_requests2"))
1315-
.andExpect(jsonPath("$.runSizing.limits.cpu").value("cpu_limits2"))
1316-
.andExpect(jsonPath("$.runSizing.limits.memory").value("memory_limits2"))
1313+
.andExpect(jsonPath("$.runSizing.requests.cpu").value("2"))
1314+
.andExpect(jsonPath("$.runSizing.requests.memory").value("3G"))
1315+
.andExpect(jsonPath("$.runSizing.limits.cpu").value("2"))
1316+
.andExpect(jsonPath("$.runSizing.limits.memory").value("3G"))
13171317
.andExpect(jsonPath("$.parameterGroups").value(mutableListOf(parameterGroupId)))
13181318
.andExpect(jsonPath("$.executionTimeout").value(100))
13191319
.andDo(MockMvcResultHandlers.print())
@@ -1336,8 +1336,8 @@ class SolutionControllerTests : ControllerTestBase() {
13361336
val runTemplateComputeSize = "this_is_a_compute_size"
13371337
val runTemplateRunSizing =
13381338
RunTemplateResourceSizing(
1339-
ResourceSizeInfo("cpu_requests", "memory_requests"),
1340-
ResourceSizeInfo("cpu_limits", "memory_limits"),
1339+
ResourceSizeInfo("1", "2G"),
1340+
ResourceSizeInfo("1", "2G"),
13411341
)
13421342
val runTemplates =
13431343
mutableListOf(

common/src/main/kotlin/com/cosmotech/common/exceptions/CsmExceptionHandling.kt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
package com.cosmotech.common.exceptions
44

55
import io.awspring.cloud.s3.S3Exception
6+
import io.kubernetes.client.custom.QuantityFormatException
67
import jakarta.validation.ConstraintViolationException
78
import java.net.URI
89
import org.apache.commons.lang3.NotImplementedException
@@ -199,4 +200,15 @@ open class CsmExceptionHandling : ResponseEntityExceptionHandler() {
199200
}
200201
return response
201202
}
203+
204+
@ExceptionHandler
205+
fun handleQuantityFormatException(exception: QuantityFormatException): ProblemDetail {
206+
val badRequestStatus = HttpStatus.BAD_REQUEST
207+
val response = ProblemDetail.forStatus(badRequestStatus)
208+
response.type = URI.create(httpStatusCodeTypePrefix + badRequestStatus.value())
209+
if (exception.message != null) {
210+
response.detail = exception.message
211+
}
212+
return response
213+
}
202214
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// Copyright (c) Cosmo Tech.
2+
// Licensed under the MIT license.
3+
package com.cosmotech.common.utils
4+
5+
import io.kubernetes.client.custom.QuantityFormatException
6+
import io.kubernetes.client.custom.QuantityFormatter
7+
8+
/** Validates resource sizing by parsing quantity values */
9+
fun validateResourceSizing(
10+
propertyName: String,
11+
requestCpu: String,
12+
requestMemory: String,
13+
limitsCpu: String,
14+
limitsMemory: String,
15+
) {
16+
val valuesToParse =
17+
mapOf(
18+
"requests.cpu" to requestCpu,
19+
"requests.memory" to requestMemory,
20+
"limits.cpu" to limitsCpu,
21+
"limits.memory" to limitsMemory,
22+
)
23+
24+
try {
25+
valuesToParse.values.forEach { QuantityFormatter().parse(it) }
26+
} catch (e: QuantityFormatException) {
27+
throw IllegalArgumentException(
28+
"Invalid quantity format. Please check $propertyName values $valuesToParse",
29+
e,
30+
)
31+
}
32+
}

0 commit comments

Comments
 (0)