sigs.k8s.io/kueue@v0.6.2/pkg/workload/resources_test.go (about) 1 /* 2 Copyright 2023 The Kubernetes Authors. 3 Licensed under the Apache License, Version 2.0 (the "License"); 4 you may not use this file except in compliance with the License. 5 You may obtain a copy of the License at 6 http://www.apache.org/licenses/LICENSE-2.0 7 Unless required by applicable law or agreed to in writing, software 8 distributed under the License is distributed on an "AS IS" BASIS, 9 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 See the License for the specific language governing permissions and 11 limitations under the License. 12 */ 13 14 package workload 15 16 import ( 17 "testing" 18 19 "github.com/google/go-cmp/cmp" 20 corev1 "k8s.io/api/core/v1" 21 nodev1 "k8s.io/api/node/v1" 22 "k8s.io/apimachinery/pkg/api/resource" 23 24 kueue "sigs.k8s.io/kueue/apis/kueue/v1beta1" 25 "sigs.k8s.io/kueue/pkg/controller/core/indexer" 26 utiltesting "sigs.k8s.io/kueue/pkg/util/testing" 27 ) 28 29 func TestAdjustResources(t *testing.T) { 30 cases := map[string]struct { 31 runtimeClasses []nodev1.RuntimeClass 32 limitranges []corev1.LimitRange 33 wl *kueue.Workload 34 wantWl *kueue.Workload 35 }{ 36 "Handle runtimeClass with podOverHead": { 37 runtimeClasses: []nodev1.RuntimeClass{ 38 utiltesting.MakeRuntimeClass("runtime-a", "handler-a"). 39 PodOverhead(corev1.ResourceList{ 40 corev1.ResourceCPU: ResourceQuantity(corev1.ResourceCPU, 1), 41 corev1.ResourceMemory: ResourceQuantity(corev1.ResourceMemory, 1024), 42 }). 43 RuntimeClass, 44 }, 45 wl: utiltesting.MakeWorkload("foo", ""). 46 PodSets( 47 *utiltesting.MakePodSet("a", 1). 48 RuntimeClass("runtime-a"). 49 Obj(), 50 *utiltesting.MakePodSet("b", 1). 51 Obj(), 52 *utiltesting.MakePodSet("c", 1). 53 RuntimeClass("runtime-a"). 54 PodOverHead( 55 corev1.ResourceList{ 56 corev1.ResourceCPU: ResourceQuantity(corev1.ResourceCPU, 2), 57 corev1.ResourceMemory: ResourceQuantity(corev1.ResourceMemory, 2048), 58 }). 59 Obj(), 60 *utiltesting.MakePodSet("d", 1). 61 RuntimeClass("runtime-d"). 62 Obj(), 63 *utiltesting.MakePodSet("e", 1). 64 RuntimeClass("runtime-e"). 65 PodOverHead( 66 corev1.ResourceList{ 67 corev1.ResourceCPU: ResourceQuantity(corev1.ResourceCPU, 2), 68 corev1.ResourceMemory: ResourceQuantity(corev1.ResourceMemory, 2048), 69 }). 70 Obj(), 71 ). 72 Obj(), 73 wantWl: utiltesting.MakeWorkload("foo", ""). 74 PodSets( 75 *utiltesting.MakePodSet("a", 1). 76 RuntimeClass("runtime-a"). 77 PodOverHead( 78 corev1.ResourceList{ 79 corev1.ResourceCPU: ResourceQuantity(corev1.ResourceCPU, 1), 80 corev1.ResourceMemory: ResourceQuantity(corev1.ResourceMemory, 1024), 81 }). 82 Obj(), 83 *utiltesting.MakePodSet("b", 1). 84 Obj(), 85 *utiltesting.MakePodSet("c", 1). 86 RuntimeClass("runtime-a"). 87 PodOverHead( 88 corev1.ResourceList{ 89 corev1.ResourceCPU: ResourceQuantity(corev1.ResourceCPU, 2), 90 corev1.ResourceMemory: ResourceQuantity(corev1.ResourceMemory, 2048), 91 }). 92 Obj(), 93 *utiltesting.MakePodSet("d", 1). 94 RuntimeClass("runtime-d"). 95 Obj(), 96 *utiltesting.MakePodSet("e", 1). 97 RuntimeClass("runtime-e"). 98 PodOverHead( 99 corev1.ResourceList{ 100 corev1.ResourceCPU: ResourceQuantity(corev1.ResourceCPU, 2), 101 corev1.ResourceMemory: ResourceQuantity(corev1.ResourceMemory, 2048), 102 }). 103 Obj(), 104 ). 105 Obj(), 106 }, 107 "Handle runtimeClass without podOverHead": { 108 runtimeClasses: []nodev1.RuntimeClass{ 109 utiltesting.MakeRuntimeClass("runtime-a", "handler-a"). 110 RuntimeClass, 111 }, 112 wl: utiltesting.MakeWorkload("foo", ""). 113 PodSets( 114 *utiltesting.MakePodSet("a", 1). 115 RuntimeClass("runtime-a"). 116 Obj(), 117 *utiltesting.MakePodSet("b", 1). 118 Obj(), 119 *utiltesting.MakePodSet("c", 1). 120 RuntimeClass("runtime-a"). 121 PodOverHead( 122 corev1.ResourceList{ 123 corev1.ResourceCPU: ResourceQuantity(corev1.ResourceCPU, 1), 124 corev1.ResourceMemory: ResourceQuantity(corev1.ResourceMemory, 1024), 125 }). 126 Obj(), 127 *utiltesting.MakePodSet("d", 1). 128 RuntimeClass("runtime-d"). 129 Obj(), 130 *utiltesting.MakePodSet("e", 1). 131 RuntimeClass("runtime-e"). 132 PodOverHead( 133 corev1.ResourceList{ 134 corev1.ResourceCPU: ResourceQuantity(corev1.ResourceCPU, 1), 135 corev1.ResourceMemory: ResourceQuantity(corev1.ResourceMemory, 1024), 136 }). 137 Obj(), 138 ). 139 Obj(), 140 wantWl: utiltesting.MakeWorkload("foo", ""). 141 PodSets( 142 *utiltesting.MakePodSet("a", 1). 143 RuntimeClass("runtime-a"). 144 Obj(), 145 *utiltesting.MakePodSet("b", 1). 146 Obj(), 147 *utiltesting.MakePodSet("c", 1). 148 RuntimeClass("runtime-a"). 149 PodOverHead( 150 corev1.ResourceList{ 151 corev1.ResourceCPU: ResourceQuantity(corev1.ResourceCPU, 1), 152 corev1.ResourceMemory: ResourceQuantity(corev1.ResourceMemory, 1024), 153 }). 154 Obj(), 155 *utiltesting.MakePodSet("d", 1). 156 RuntimeClass("runtime-d"). 157 Obj(), 158 *utiltesting.MakePodSet("e", 1). 159 RuntimeClass("runtime-e"). 160 PodOverHead( 161 corev1.ResourceList{ 162 corev1.ResourceCPU: ResourceQuantity(corev1.ResourceCPU, 1), 163 corev1.ResourceMemory: ResourceQuantity(corev1.ResourceMemory, 1024), 164 }). 165 Obj(), 166 ). 167 Obj(), 168 }, 169 "Handle container limit range": { 170 limitranges: []corev1.LimitRange{ 171 utiltesting.MakeLimitRange("foo", ""). 172 WithType(corev1.LimitTypeContainer). 173 WithValue( 174 "Default", corev1.ResourceCPU, "4", 175 ). 176 WithValue( 177 "DefaultRequest", corev1.ResourceCPU, "3", 178 ). 179 WithValue( 180 "Max", corev1.ResourceCPU, "5", 181 ). 182 WithValue( 183 "Min", corev1.ResourceCPU, "2", 184 ). 185 LimitRange, 186 }, 187 wl: utiltesting.MakeWorkload("foo", ""). 188 PodSets( 189 *utiltesting.MakePodSet("a", 1). 190 InitContainers(corev1.Container{}). 191 Obj(), 192 *utiltesting.MakePodSet("b", 1). 193 InitContainers(corev1.Container{}). 194 Limit(corev1.ResourceCPU, "6"). 195 Obj(), 196 *utiltesting.MakePodSet("c", 1). 197 InitContainers(corev1.Container{}). 198 Request(corev1.ResourceCPU, "1"). 199 Obj(), 200 ). 201 Obj(), 202 wantWl: utiltesting.MakeWorkload("foo", ""). 203 PodSets( 204 *utiltesting.MakePodSet("a", 1). 205 Limit(corev1.ResourceCPU, "4"). 206 Request(corev1.ResourceCPU, "3"). 207 InitContainers(corev1.Container{ 208 Resources: corev1.ResourceRequirements{ 209 Limits: corev1.ResourceList{ 210 corev1.ResourceCPU: *resource.NewQuantity(4, resource.DecimalSI), 211 }, 212 Requests: corev1.ResourceList{ 213 corev1.ResourceCPU: *resource.NewQuantity(3, resource.DecimalSI), 214 }, 215 }, 216 }). 217 Obj(), 218 *utiltesting.MakePodSet("b", 1). 219 Limit(corev1.ResourceCPU, "6"). 220 Request(corev1.ResourceCPU, "3"). 221 InitContainers(corev1.Container{ 222 Resources: corev1.ResourceRequirements{ 223 Limits: corev1.ResourceList{ 224 corev1.ResourceCPU: *resource.NewQuantity(4, resource.DecimalSI), 225 }, 226 Requests: corev1.ResourceList{ 227 corev1.ResourceCPU: *resource.NewQuantity(3, resource.DecimalSI), 228 }, 229 }, 230 }). 231 Obj(), 232 *utiltesting.MakePodSet("c", 1). 233 Limit(corev1.ResourceCPU, "4"). 234 Request(corev1.ResourceCPU, "1"). 235 InitContainers(corev1.Container{ 236 Resources: corev1.ResourceRequirements{ 237 Limits: corev1.ResourceList{ 238 corev1.ResourceCPU: *resource.NewQuantity(4, resource.DecimalSI), 239 }, 240 Requests: corev1.ResourceList{ 241 corev1.ResourceCPU: *resource.NewQuantity(3, resource.DecimalSI), 242 }, 243 }, 244 }). 245 Obj(), 246 ). 247 Obj(), 248 }, 249 "Handle pod limit range": { 250 limitranges: []corev1.LimitRange{ 251 utiltesting.MakeLimitRange("foo", ""). 252 WithType(corev1.LimitTypePod). 253 WithValue( 254 "Default", corev1.ResourceCPU, "4", 255 ). 256 WithValue( 257 "DefaultRequest", corev1.ResourceCPU, "3", 258 ). 259 WithValue( 260 "Max", corev1.ResourceCPU, "5", 261 ). 262 WithValue( 263 "Min", corev1.ResourceCPU, "2", 264 ). 265 LimitRange, 266 }, 267 wl: utiltesting.MakeWorkload("foo", ""). 268 PodSets( 269 *utiltesting.MakePodSet("a", 1). 270 Obj(), 271 *utiltesting.MakePodSet("b", 1). 272 Limit(corev1.ResourceCPU, "6"). 273 Request(corev1.ResourceCPU, "1"). 274 Obj(), 275 ). 276 Obj(), 277 wantWl: utiltesting.MakeWorkload("foo", ""). 278 PodSets( 279 *utiltesting.MakePodSet("a", 1). 280 Obj(), 281 *utiltesting.MakePodSet("b", 1). 282 Limit(corev1.ResourceCPU, "6"). 283 Request(corev1.ResourceCPU, "1"). 284 Obj(), 285 ). 286 Obj(), 287 }, 288 "Handle empty container limit range": { 289 limitranges: []corev1.LimitRange{ 290 utiltesting.MakeLimitRange("foo", ""). 291 WithType(corev1.LimitTypeContainer). 292 LimitRange, 293 }, 294 wl: utiltesting.MakeWorkload("foo", ""). 295 PodSets( 296 *utiltesting.MakePodSet("a", 1). 297 Obj(), 298 *utiltesting.MakePodSet("b", 1). 299 Limit(corev1.ResourceCPU, "6"). 300 Request(corev1.ResourceCPU, "1"). 301 Obj(), 302 ). 303 Obj(), 304 wantWl: utiltesting.MakeWorkload("foo", ""). 305 PodSets( 306 *utiltesting.MakePodSet("a", 1). 307 Obj(), 308 *utiltesting.MakePodSet("b", 1). 309 Limit(corev1.ResourceCPU, "6"). 310 Request(corev1.ResourceCPU, "1"). 311 Obj(), 312 ). 313 Obj(), 314 }, 315 "Apply limits to requests": { 316 wl: utiltesting.MakeWorkload("foo", ""). 317 PodSets( 318 *utiltesting.MakePodSet("a", 1). 319 Limit(corev1.ResourceCPU, "1"). 320 Limit(corev1.ResourceMemory, "1Gi"). 321 InitContainers(corev1.Container{ 322 Resources: corev1.ResourceRequirements{ 323 Limits: corev1.ResourceList{ 324 corev1.ResourceCPU: *resource.NewQuantity(1, resource.DecimalSI), 325 corev1.ResourceMemory: *resource.NewQuantity(1, resource.BinarySI), 326 }, 327 }, 328 }). 329 Obj(), 330 *utiltesting.MakePodSet("b", 1). 331 Request(corev1.ResourceCPU, "2"). 332 Limit(corev1.ResourceCPU, "3"). 333 Limit(corev1.ResourceMemory, "1Gi"). 334 InitContainers(corev1.Container{ 335 Resources: corev1.ResourceRequirements{ 336 Limits: corev1.ResourceList{ 337 corev1.ResourceCPU: *resource.NewQuantity(3, resource.DecimalSI), 338 corev1.ResourceMemory: *resource.NewQuantity(1, resource.BinarySI), 339 }, 340 Requests: corev1.ResourceList{ 341 corev1.ResourceCPU: *resource.NewQuantity(2, resource.DecimalSI), 342 }, 343 }, 344 }). 345 Obj(), 346 *utiltesting.MakePodSet("c", 1). 347 Request(corev1.ResourceMemory, "1Gi"). 348 Limit(corev1.ResourceCPU, "1"). 349 Limit(corev1.ResourceMemory, "3Gi"). 350 InitContainers(corev1.Container{ 351 Resources: corev1.ResourceRequirements{ 352 Limits: corev1.ResourceList{ 353 corev1.ResourceCPU: *resource.NewQuantity(1, resource.DecimalSI), 354 corev1.ResourceMemory: *resource.NewQuantity(3, resource.BinarySI), 355 }, 356 Requests: corev1.ResourceList{ 357 corev1.ResourceMemory: *resource.NewQuantity(1, resource.BinarySI), 358 }, 359 }, 360 }). 361 Obj(), 362 *utiltesting.MakePodSet("d", 1). 363 Limit(corev1.ResourceCPU, "1"). 364 InitContainers(corev1.Container{ 365 Resources: corev1.ResourceRequirements{ 366 Limits: corev1.ResourceList{ 367 corev1.ResourceCPU: *resource.NewQuantity(1, resource.DecimalSI), 368 }, 369 }, 370 }). 371 Obj(), 372 *utiltesting.MakePodSet("e", 1). 373 Request(corev1.ResourceMemory, "1Gi"). 374 InitContainers(corev1.Container{ 375 Resources: corev1.ResourceRequirements{ 376 Requests: corev1.ResourceList{ 377 corev1.ResourceMemory: *resource.NewQuantity(1, resource.BinarySI), 378 }, 379 }, 380 }). 381 Obj(), 382 ). 383 Obj(), 384 wantWl: utiltesting.MakeWorkload("foo", ""). 385 PodSets( 386 *utiltesting.MakePodSet("a", 1). 387 Limit(corev1.ResourceCPU, "1"). 388 Limit(corev1.ResourceMemory, "1Gi"). 389 Request(corev1.ResourceCPU, "1"). 390 Request(corev1.ResourceMemory, "1Gi"). 391 InitContainers(corev1.Container{ 392 Resources: corev1.ResourceRequirements{ 393 Limits: corev1.ResourceList{ 394 corev1.ResourceCPU: *resource.NewQuantity(1, resource.DecimalSI), 395 corev1.ResourceMemory: *resource.NewQuantity(1, resource.BinarySI), 396 }, 397 Requests: corev1.ResourceList{ 398 corev1.ResourceCPU: *resource.NewQuantity(1, resource.DecimalSI), 399 corev1.ResourceMemory: *resource.NewQuantity(1, resource.BinarySI), 400 }, 401 }, 402 }). 403 Obj(), 404 *utiltesting.MakePodSet("b", 1). 405 Limit(corev1.ResourceCPU, "3"). 406 Limit(corev1.ResourceMemory, "1Gi"). 407 Request(corev1.ResourceCPU, "2"). 408 Request(corev1.ResourceMemory, "1Gi"). 409 InitContainers(corev1.Container{ 410 Resources: corev1.ResourceRequirements{ 411 Limits: corev1.ResourceList{ 412 corev1.ResourceCPU: *resource.NewQuantity(3, resource.DecimalSI), 413 corev1.ResourceMemory: *resource.NewQuantity(1, resource.BinarySI), 414 }, 415 Requests: corev1.ResourceList{ 416 corev1.ResourceCPU: *resource.NewQuantity(2, resource.DecimalSI), 417 corev1.ResourceMemory: *resource.NewQuantity(1, resource.BinarySI), 418 }, 419 }, 420 }). 421 Obj(), 422 *utiltesting.MakePodSet("c", 1). 423 Limit(corev1.ResourceCPU, "1"). 424 Limit(corev1.ResourceMemory, "3Gi"). 425 Request(corev1.ResourceCPU, "1"). 426 Request(corev1.ResourceMemory, "1Gi"). 427 InitContainers(corev1.Container{ 428 Resources: corev1.ResourceRequirements{ 429 Limits: corev1.ResourceList{ 430 corev1.ResourceCPU: *resource.NewQuantity(1, resource.DecimalSI), 431 corev1.ResourceMemory: *resource.NewQuantity(3, resource.BinarySI), 432 }, 433 Requests: corev1.ResourceList{ 434 corev1.ResourceCPU: *resource.NewQuantity(1, resource.DecimalSI), 435 corev1.ResourceMemory: *resource.NewQuantity(1, resource.BinarySI), 436 }, 437 }, 438 }). 439 Obj(), 440 *utiltesting.MakePodSet("d", 1). 441 Limit(corev1.ResourceCPU, "1"). 442 Request(corev1.ResourceCPU, "1"). 443 InitContainers(corev1.Container{ 444 Resources: corev1.ResourceRequirements{ 445 Limits: corev1.ResourceList{ 446 corev1.ResourceCPU: *resource.NewQuantity(1, resource.DecimalSI), 447 }, 448 Requests: corev1.ResourceList{ 449 corev1.ResourceCPU: *resource.NewQuantity(1, resource.DecimalSI), 450 }, 451 }, 452 }). 453 Obj(), 454 *utiltesting.MakePodSet("e", 1). 455 Request(corev1.ResourceMemory, "1Gi"). 456 InitContainers(corev1.Container{ 457 Resources: corev1.ResourceRequirements{ 458 Requests: corev1.ResourceList{ 459 corev1.ResourceMemory: *resource.NewQuantity(1, resource.BinarySI), 460 }, 461 }, 462 }). 463 Obj(), 464 ). 465 Obj(), 466 }, 467 } 468 for name, tc := range cases { 469 t.Run(name, func(t *testing.T) { 470 cl := utiltesting.NewClientBuilder().WithLists( 471 &nodev1.RuntimeClassList{Items: tc.runtimeClasses}, 472 &corev1.LimitRangeList{Items: tc.limitranges}, 473 ).WithIndex(&corev1.LimitRange{}, indexer.LimitRangeHasContainerType, indexer.IndexLimitRangeHasContainerType). 474 Build() 475 ctx, _ := utiltesting.ContextWithLog(t) 476 AdjustResources(ctx, cl, tc.wl) 477 if diff := cmp.Diff(tc.wl, tc.wantWl); diff != "" { 478 t.Errorf("Unexpected resources after adjusting (-want,+got): %s", diff) 479 } 480 }) 481 } 482 }