github.com/kubewharf/katalyst-core@v0.5.3/pkg/scheduler/plugins/nodeovercommitment/fit_test.go (about) 1 /* 2 Copyright 2022 The Katalyst Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package nodeovercommitment 18 19 import ( 20 "context" 21 "testing" 22 23 "github.com/stretchr/testify/assert" 24 v1 "k8s.io/api/core/v1" 25 "k8s.io/apimachinery/pkg/api/resource" 26 v12 "k8s.io/apimachinery/pkg/apis/meta/v1" 27 "k8s.io/kubernetes/pkg/scheduler/framework" 28 29 "github.com/kubewharf/katalyst-api/pkg/apis/node/v1alpha1" 30 "github.com/kubewharf/katalyst-core/pkg/scheduler/plugins/nodeovercommitment/cache" 31 ) 32 33 func TestPreFilter(t *testing.T) { 34 t.Parallel() 35 36 testCases := []struct { 37 name string 38 pod *v1.Pod 39 expectCPU int64 40 expectGuaranteedCPU int 41 }{ 42 { 43 name: "burstable pod", 44 pod: &v1.Pod{ 45 Spec: v1.PodSpec{ 46 Containers: []v1.Container{ 47 { 48 Resources: v1.ResourceRequirements{ 49 Limits: map[v1.ResourceName]resource.Quantity{ 50 v1.ResourceCPU: resource.MustParse("4"), 51 v1.ResourceMemory: resource.MustParse("8Gi"), 52 }, 53 Requests: map[v1.ResourceName]resource.Quantity{ 54 v1.ResourceCPU: resource.MustParse("2"), 55 v1.ResourceMemory: resource.MustParse("4Gi"), 56 }, 57 }, 58 }, 59 }, 60 }, 61 }, 62 expectCPU: 2000, 63 expectGuaranteedCPU: 0, 64 }, 65 { 66 name: "guaranteed pod", 67 pod: &v1.Pod{ 68 Spec: v1.PodSpec{ 69 Containers: []v1.Container{ 70 { 71 Resources: v1.ResourceRequirements{ 72 Limits: map[v1.ResourceName]resource.Quantity{ 73 v1.ResourceCPU: resource.MustParse("4"), 74 v1.ResourceMemory: resource.MustParse("8Gi"), 75 }, 76 Requests: map[v1.ResourceName]resource.Quantity{ 77 v1.ResourceCPU: resource.MustParse("4"), 78 v1.ResourceMemory: resource.MustParse("8Gi"), 79 }, 80 }, 81 }, 82 }, 83 }, 84 }, 85 expectCPU: 0, 86 expectGuaranteedCPU: 4, 87 }, 88 { 89 name: "guaranteed pod with init container", 90 pod: &v1.Pod{ 91 Spec: v1.PodSpec{ 92 InitContainers: []v1.Container{ 93 { 94 Resources: v1.ResourceRequirements{ 95 Limits: map[v1.ResourceName]resource.Quantity{ 96 v1.ResourceCPU: resource.MustParse("4"), 97 v1.ResourceMemory: resource.MustParse("8Gi"), 98 }, 99 Requests: map[v1.ResourceName]resource.Quantity{ 100 v1.ResourceCPU: resource.MustParse("4"), 101 v1.ResourceMemory: resource.MustParse("8Gi"), 102 }, 103 }, 104 }, 105 }, 106 Containers: []v1.Container{ 107 { 108 Resources: v1.ResourceRequirements{ 109 Limits: map[v1.ResourceName]resource.Quantity{ 110 v1.ResourceCPU: resource.MustParse("2"), 111 v1.ResourceMemory: resource.MustParse("8Gi"), 112 }, 113 Requests: map[v1.ResourceName]resource.Quantity{ 114 v1.ResourceCPU: resource.MustParse("2"), 115 v1.ResourceMemory: resource.MustParse("8Gi"), 116 }, 117 }, 118 }, 119 }, 120 }, 121 }, 122 expectCPU: 0, 123 expectGuaranteedCPU: 4, 124 }, 125 } 126 127 for _, tc := range testCases { 128 t.Run(tc.name, func(t *testing.T) { 129 n := &NodeOvercommitment{} 130 cs := framework.NewCycleState() 131 res, stat := n.PreFilter(context.TODO(), cs, tc.pod) 132 assert.Nil(t, res) 133 assert.Nil(t, stat) 134 135 fs, err := getPreFilterState(cs) 136 assert.NoError(t, err) 137 assert.Equal(t, tc.expectGuaranteedCPU, fs.GuaranteedCPUs) 138 assert.Equal(t, tc.expectCPU, fs.MilliCPU) 139 }) 140 } 141 } 142 143 func TestFilter(t *testing.T) { 144 t.Parallel() 145 146 testCases := []struct { 147 name string 148 node *v1.Node 149 cnrs []*v1alpha1.CustomNodeResource 150 existPods []*v1.Pod 151 pod *v1.Pod 152 requested *framework.Resource 153 expectRes *framework.Status 154 }{ 155 { 156 name: "node cpumanager off", 157 node: &v1.Node{ 158 ObjectMeta: v12.ObjectMeta{ 159 Name: "node1", 160 Annotations: map[string]string{ 161 "katalyst.kubewharf.io/cpu_overcommit_ratio": "2.0", 162 "katalyst.kubewharf.io/memory_overcommit_ratio": "1.0", 163 "katalyst.kubewharf.io/original_allocatable_cpu": "16000", 164 }, 165 }, 166 Status: v1.NodeStatus{ 167 Allocatable: map[v1.ResourceName]resource.Quantity{ 168 v1.ResourceCPU: resource.MustParse("32"), 169 v1.ResourceMemory: resource.MustParse("32Gi"), 170 }, 171 }, 172 }, 173 cnrs: []*v1alpha1.CustomNodeResource{ 174 { 175 ObjectMeta: v12.ObjectMeta{ 176 Name: "node1", 177 Annotations: map[string]string{ 178 "katalyst.kubewharf.io/overcommit_cpu_manager": "none", 179 "katalyst.kubewharf.io/overcommit_memory_manager": "None", 180 "katalyst.kubewharf.io/guaranteed_cpus": "0", 181 }, 182 }, 183 }, 184 }, 185 existPods: []*v1.Pod{}, 186 requested: &framework.Resource{ 187 MilliCPU: 24000, 188 }, 189 pod: &v1.Pod{ 190 ObjectMeta: v12.ObjectMeta{ 191 Name: "pod1", 192 }, 193 Spec: v1.PodSpec{ 194 Containers: []v1.Container{ 195 { 196 Name: "testContainer", 197 Resources: v1.ResourceRequirements{ 198 Requests: map[v1.ResourceName]resource.Quantity{ 199 v1.ResourceCPU: resource.MustParse("4"), 200 v1.ResourceMemory: resource.MustParse("8Gi"), 201 }, 202 }, 203 }, 204 }, 205 }, 206 }, 207 expectRes: nil, 208 }, 209 { 210 name: "node cpumanager on", 211 node: &v1.Node{ 212 ObjectMeta: v12.ObjectMeta{ 213 Name: "node1", 214 Annotations: map[string]string{ 215 "katalyst.kubewharf.io/cpu_overcommit_ratio": "2.0", 216 "katalyst.kubewharf.io/memory_overcommit_ratio": "1.0", 217 "katalyst.kubewharf.io/original_allocatable_cpu": "16000", 218 }, 219 }, 220 Status: v1.NodeStatus{ 221 Allocatable: map[v1.ResourceName]resource.Quantity{ 222 v1.ResourceCPU: resource.MustParse("32"), 223 v1.ResourceMemory: resource.MustParse("32Gi"), 224 }, 225 }, 226 }, 227 cnrs: []*v1alpha1.CustomNodeResource{ 228 { 229 ObjectMeta: v12.ObjectMeta{ 230 Name: "node1", 231 Annotations: map[string]string{ 232 "katalyst.kubewharf.io/overcommit_cpu_manager": "static", 233 "katalyst.kubewharf.io/overcommit_memory_manager": "None", 234 "katalyst.kubewharf.io/guaranteed_cpus": "4", 235 }, 236 }, 237 }, 238 }, 239 requested: &framework.Resource{ 240 MilliCPU: 24000, 241 }, 242 existPods: []*v1.Pod{ 243 { 244 ObjectMeta: v12.ObjectMeta{ 245 Name: "pod01", 246 UID: "pod01", 247 }, 248 Spec: v1.PodSpec{ 249 NodeName: "node1", 250 Containers: []v1.Container{ 251 { 252 Name: "testContainer", 253 Resources: v1.ResourceRequirements{ 254 Requests: map[v1.ResourceName]resource.Quantity{ 255 v1.ResourceCPU: resource.MustParse("4"), 256 v1.ResourceMemory: resource.MustParse("8Gi"), 257 }, 258 Limits: map[v1.ResourceName]resource.Quantity{ 259 v1.ResourceCPU: resource.MustParse("4"), 260 v1.ResourceMemory: resource.MustParse("8Gi"), 261 }, 262 }, 263 }, 264 }, 265 }, 266 }, 267 }, 268 pod: &v1.Pod{ 269 ObjectMeta: v12.ObjectMeta{ 270 Name: "pod1", 271 }, 272 Spec: v1.PodSpec{ 273 Containers: []v1.Container{ 274 { 275 Name: "testContainer", 276 Resources: v1.ResourceRequirements{ 277 Requests: map[v1.ResourceName]resource.Quantity{ 278 v1.ResourceCPU: resource.MustParse("4"), 279 v1.ResourceMemory: resource.MustParse("8Gi"), 280 }, 281 }, 282 }, 283 }, 284 }, 285 }, 286 expectRes: nil, 287 }, 288 { 289 name: "node cpumanager on with recommend", 290 node: &v1.Node{ 291 ObjectMeta: v12.ObjectMeta{ 292 Name: "node1", 293 Annotations: map[string]string{ 294 "katalyst.kubewharf.io/cpu_overcommit_ratio": "3.0", 295 "katalyst.kubewharf.io/memory_overcommit_ratio": "1.0", 296 "katalyst.kubewharf.io/recommend_cpu_overcommit_ratio": "2.0", 297 "katalyst.kubewharf.io/original_allocatable_cpu": "16000", 298 }, 299 }, 300 Status: v1.NodeStatus{ 301 Allocatable: map[v1.ResourceName]resource.Quantity{ 302 v1.ResourceCPU: resource.MustParse("32"), 303 v1.ResourceMemory: resource.MustParse("32Gi"), 304 }, 305 }, 306 }, 307 cnrs: []*v1alpha1.CustomNodeResource{ 308 { 309 ObjectMeta: v12.ObjectMeta{ 310 Name: "node1", 311 Annotations: map[string]string{ 312 "katalyst.kubewharf.io/overcommit_cpu_manager": "static", 313 "katalyst.kubewharf.io/overcommit_memory_manager": "None", 314 "katalyst.kubewharf.io/guaranteed_cpus": "4", 315 }, 316 }, 317 }, 318 }, 319 requested: &framework.Resource{ 320 MilliCPU: 24000, 321 }, 322 existPods: []*v1.Pod{ 323 { 324 ObjectMeta: v12.ObjectMeta{ 325 Name: "pod01", 326 UID: "pod01", 327 }, 328 Spec: v1.PodSpec{ 329 NodeName: "node1", 330 Containers: []v1.Container{ 331 { 332 Name: "testContainer", 333 Resources: v1.ResourceRequirements{ 334 Requests: map[v1.ResourceName]resource.Quantity{ 335 v1.ResourceCPU: resource.MustParse("4"), 336 v1.ResourceMemory: resource.MustParse("8Gi"), 337 }, 338 Limits: map[v1.ResourceName]resource.Quantity{ 339 v1.ResourceCPU: resource.MustParse("4"), 340 v1.ResourceMemory: resource.MustParse("8Gi"), 341 }, 342 }, 343 }, 344 }, 345 }, 346 }, 347 }, 348 pod: &v1.Pod{ 349 ObjectMeta: v12.ObjectMeta{ 350 Name: "pod1", 351 }, 352 Spec: v1.PodSpec{ 353 Containers: []v1.Container{ 354 { 355 Name: "testContainer", 356 Resources: v1.ResourceRequirements{ 357 Requests: map[v1.ResourceName]resource.Quantity{ 358 v1.ResourceCPU: resource.MustParse("4"), 359 v1.ResourceMemory: resource.MustParse("8Gi"), 360 }, 361 }, 362 }, 363 }, 364 }, 365 }, 366 expectRes: nil, 367 }, 368 { 369 name: "node cpumanager on 2", 370 node: &v1.Node{ 371 ObjectMeta: v12.ObjectMeta{ 372 Name: "node1", 373 Annotations: map[string]string{ 374 "katalyst.kubewharf.io/cpu_overcommit_ratio": "2.0", 375 "katalyst.kubewharf.io/memory_overcommit_ratio": "1.0", 376 "katalyst.kubewharf.io/original_allocatable_cpu": "16000m", 377 }, 378 }, 379 Status: v1.NodeStatus{ 380 Allocatable: map[v1.ResourceName]resource.Quantity{ 381 v1.ResourceCPU: resource.MustParse("32"), 382 v1.ResourceMemory: resource.MustParse("32Gi"), 383 }, 384 }, 385 }, 386 cnrs: []*v1alpha1.CustomNodeResource{ 387 { 388 ObjectMeta: v12.ObjectMeta{ 389 Name: "node1", 390 Annotations: map[string]string{ 391 "katalyst.kubewharf.io/overcommit_cpu_manager": "static", 392 "katalyst.kubewharf.io/overcommit_memory_manager": "None", 393 "katalyst.kubewharf.io/guaranteed_cpus": "8", 394 }, 395 }, 396 }, 397 }, 398 requested: &framework.Resource{ 399 MilliCPU: 24000, 400 }, 401 existPods: []*v1.Pod{ 402 { 403 ObjectMeta: v12.ObjectMeta{ 404 Name: "pod01", 405 UID: "pod01", 406 }, 407 Spec: v1.PodSpec{ 408 NodeName: "node1", 409 Containers: []v1.Container{ 410 { 411 Name: "testContainer", 412 Resources: v1.ResourceRequirements{ 413 Requests: map[v1.ResourceName]resource.Quantity{ 414 v1.ResourceCPU: resource.MustParse("8"), 415 v1.ResourceMemory: resource.MustParse("8Gi"), 416 }, 417 Limits: map[v1.ResourceName]resource.Quantity{ 418 v1.ResourceCPU: resource.MustParse("8"), 419 v1.ResourceMemory: resource.MustParse("8Gi"), 420 }, 421 }, 422 }, 423 }, 424 }, 425 }, 426 }, 427 pod: &v1.Pod{ 428 ObjectMeta: v12.ObjectMeta{ 429 Name: "pod1", 430 }, 431 Spec: v1.PodSpec{ 432 Containers: []v1.Container{ 433 { 434 Name: "testContainer", 435 Resources: v1.ResourceRequirements{ 436 Requests: map[v1.ResourceName]resource.Quantity{ 437 v1.ResourceCPU: resource.MustParse("4"), 438 v1.ResourceMemory: resource.MustParse("8Gi"), 439 }, 440 }, 441 }, 442 }, 443 }, 444 }, 445 expectRes: framework.NewStatus(framework.Unschedulable), 446 }, 447 { 448 name: "node cpumanager on 3", 449 node: &v1.Node{ 450 ObjectMeta: v12.ObjectMeta{ 451 Name: "node1", 452 Annotations: map[string]string{ 453 "katalyst.kubewharf.io/cpu_overcommit_ratio": "2.0", 454 "katalyst.kubewharf.io/memory_overcommit_ratio": "1.0", 455 "katalyst.kubewharf.io/original_allocatable_cpu": "16000m", 456 }, 457 }, 458 Status: v1.NodeStatus{ 459 Allocatable: map[v1.ResourceName]resource.Quantity{ 460 v1.ResourceCPU: resource.MustParse("32"), 461 v1.ResourceMemory: resource.MustParse("32Gi"), 462 }, 463 }, 464 }, 465 cnrs: []*v1alpha1.CustomNodeResource{ 466 { 467 ObjectMeta: v12.ObjectMeta{ 468 Name: "node1", 469 Annotations: map[string]string{ 470 "katalyst.kubewharf.io/overcommit_cpu_manager": "static", 471 "katalyst.kubewharf.io/overcommit_memory_manager": "None", 472 "katalyst.kubewharf.io/guaranteed_cpus": "4", 473 }, 474 }, 475 }, 476 }, 477 requested: &framework.Resource{ 478 MilliCPU: 24000, 479 }, 480 existPods: []*v1.Pod{ 481 { 482 ObjectMeta: v12.ObjectMeta{ 483 Name: "pod01", 484 UID: "pod01", 485 }, 486 Spec: v1.PodSpec{ 487 NodeName: "node1", 488 Containers: []v1.Container{ 489 { 490 Name: "testContainer", 491 Resources: v1.ResourceRequirements{ 492 Requests: map[v1.ResourceName]resource.Quantity{ 493 v1.ResourceCPU: resource.MustParse("4"), 494 v1.ResourceMemory: resource.MustParse("8Gi"), 495 }, 496 Limits: map[v1.ResourceName]resource.Quantity{ 497 v1.ResourceCPU: resource.MustParse("4"), 498 v1.ResourceMemory: resource.MustParse("8Gi"), 499 }, 500 }, 501 }, 502 }, 503 }, 504 }, 505 }, 506 pod: &v1.Pod{ 507 ObjectMeta: v12.ObjectMeta{ 508 Name: "pod1", 509 }, 510 Spec: v1.PodSpec{ 511 Containers: []v1.Container{ 512 { 513 Name: "testContainer", 514 Resources: v1.ResourceRequirements{ 515 Requests: map[v1.ResourceName]resource.Quantity{ 516 v1.ResourceCPU: resource.MustParse("4"), 517 v1.ResourceMemory: resource.MustParse("8Gi"), 518 }, 519 Limits: map[v1.ResourceName]resource.Quantity{ 520 v1.ResourceCPU: resource.MustParse("4"), 521 v1.ResourceMemory: resource.MustParse("8Gi"), 522 }, 523 }, 524 }, 525 }, 526 }, 527 }, 528 expectRes: framework.NewStatus(framework.Unschedulable), 529 }, 530 { 531 name: "node memorymanager on, overcommit not allowed", 532 node: &v1.Node{ 533 ObjectMeta: v12.ObjectMeta{ 534 Name: "node1", 535 Annotations: map[string]string{ 536 "katalyst.kubewharf.io/cpu_overcommit_ratio": "2.0", 537 "katalyst.kubewharf.io/memory_overcommit_ratio": "1.5", 538 "katalyst.kubewharf.io/original_allocatable_cpu": "16000", 539 }, 540 }, 541 Status: v1.NodeStatus{ 542 Allocatable: map[v1.ResourceName]resource.Quantity{ 543 v1.ResourceCPU: resource.MustParse("32"), 544 v1.ResourceMemory: resource.MustParse("32Gi"), 545 }, 546 }, 547 }, 548 cnrs: []*v1alpha1.CustomNodeResource{ 549 { 550 ObjectMeta: v12.ObjectMeta{ 551 Name: "node1", 552 Annotations: map[string]string{ 553 "katalyst.kubewharf.io/overcommit_cpu_manager": "none", 554 "katalyst.kubewharf.io/overcommit_memory_manager": "Static", 555 "katalyst.kubewharf.io/guaranteed_cpus": "0", 556 }, 557 }, 558 }, 559 }, 560 requested: &framework.Resource{ 561 MilliCPU: 0, 562 }, 563 existPods: []*v1.Pod{}, 564 pod: &v1.Pod{ 565 ObjectMeta: v12.ObjectMeta{ 566 Name: "pod1", 567 }, 568 Spec: v1.PodSpec{ 569 Containers: []v1.Container{ 570 { 571 Name: "testContainer", 572 Resources: v1.ResourceRequirements{ 573 Requests: map[v1.ResourceName]resource.Quantity{ 574 v1.ResourceCPU: resource.MustParse("4"), 575 v1.ResourceMemory: resource.MustParse("8Gi"), 576 }, 577 }, 578 }, 579 }, 580 }, 581 }, 582 expectRes: framework.NewStatus(framework.Unschedulable), 583 }, 584 } 585 586 for _, tc := range testCases { 587 t.Run(tc.name, func(t *testing.T) { 588 cnrs := tc.cnrs 589 for _, cnr := range cnrs { 590 cache.GetCache().AddOrUpdateCNR(cnr) 591 } 592 for _, pod := range tc.existPods { 593 cache.GetCache().AddPod(pod) 594 } 595 defer func() { 596 for _, cnr := range cnrs { 597 cache.GetCache().RemoveCNR(cnr) 598 } 599 }() 600 601 nodeInfo := framework.NewNodeInfo() 602 nodeInfo.SetNode(tc.node) 603 nodeInfo.Requested = tc.requested 604 605 n := &NodeOvercommitment{} 606 cs := framework.NewCycleState() 607 res, stat := n.PreFilter(context.TODO(), cs, tc.pod) 608 assert.Nil(t, res) 609 assert.Nil(t, stat) 610 611 status := n.Filter(context.TODO(), cs, tc.pod, nodeInfo) 612 assert.Equal(t, tc.expectRes.Code(), status.Code()) 613 }) 614 } 615 }