@@ -592,24 +592,36 @@ func runMultipleCPUContainersGuPod(ctx context.Context, f *framework.Framework)
592
592
waitForContainerRemoval (ctx , pod .Spec .Containers [1 ].Name , pod .Name , pod .Namespace )
593
593
}
594
594
595
- func runCfsQuotaGuPods (ctx context.Context , f * framework.Framework , disabledCPUQuotaWithExclusiveCPUs bool ) {
595
+ func runCfsQuotaGuPods (ctx context.Context , f * framework.Framework , disabledCPUQuotaWithExclusiveCPUs bool , cpuAlloc int64 ) {
596
596
var err error
597
597
var ctnAttrs []ctnAttribute
598
598
var pod1 , pod2 , pod3 * v1.Pod
599
- var cleanupPods []* v1.Pod
600
- ginkgo .DeferCleanup (func () {
599
+ podsToClean := make (map [string ]* v1.Pod ) // pod.UID -> pod
600
+
601
+ framework .Logf ("runCfsQuotaGuPods: disableQuota=%v, CPU Allocatable=%v" , disabledCPUQuotaWithExclusiveCPUs , cpuAlloc )
602
+
603
+ deleteTestPod := func (pod * v1.Pod ) {
601
604
// waitForContainerRemoval takes "long" to complete; if we use the parent ctx we get a
602
605
// 'deadline expired' message and the cleanup aborts, which we don't want.
603
- ctx2 := context .TODO ()
606
+ // So let's use a separate and more generous timeout (determined by trial and error)
607
+ ctx2 , cancel := context .WithTimeout (context .Background (), 10 * time .Minute )
608
+ defer cancel ()
609
+ deletePodSyncAndWait (ctx2 , f , pod .Namespace , pod .Name )
610
+ delete (podsToClean , string (pod .UID ))
611
+ }
612
+
613
+ // cleanup leftovers on test failure. The happy path is covered by `deleteTestPod` calls
614
+ ginkgo .DeferCleanup (func () {
604
615
ginkgo .By ("by deleting the pods and waiting for container removal" )
605
- for _ , cleanupPod := range cleanupPods {
606
- framework . Logf ( "deleting pod: %s/%s" , cleanupPod . Namespace , cleanupPod . Name )
607
- deletePodSyncByName ( ctx2 , f , cleanupPod . Name )
608
- waitForContainerRemoval ( ctx2 , cleanupPod . Spec . Containers [ 0 ]. Name , cleanupPod . Name , cleanupPod . Namespace )
609
- framework . Logf ( "deleted pod: %s/%s" , cleanupPod . Namespace , cleanupPod . Name )
610
- }
616
+ // waitForContainerRemoval takes "long" to complete; if we use the parent ctx we get a
617
+ // 'deadline expired' message and the cleanup aborts, which we don't want.
618
+ // So let's use a separate and more generous timeout (determined by trial and error )
619
+ ctx2 , cancel := context . WithTimeout ( context . Background (), 10 * time . Minute )
620
+ defer cancel ( )
621
+ deletePodsAsync ( ctx2 , f , podsToClean )
611
622
})
612
623
624
+ podCFSCheckCommand := []string {"sh" , "-c" , `cat $(find /sysfscgroup | grep "$(cat /podinfo/uid | sed 's/-/_/g').slice/cpu.max$") && sleep 1d` }
613
625
cfsCheckCommand := []string {"sh" , "-c" , "cat /sys/fs/cgroup/cpu.max && sleep 1d" }
614
626
defaultPeriod := "100000"
615
627
@@ -623,7 +635,7 @@ func runCfsQuotaGuPods(ctx context.Context, f *framework.Framework, disabledCPUQ
623
635
pod1 = makeCPUManagerPod ("gu-pod1" , ctnAttrs )
624
636
pod1 .Spec .Containers [0 ].Command = cfsCheckCommand
625
637
pod1 = e2epod .NewPodClient (f ).CreateSync (ctx , pod1 )
626
- cleanupPods = append ( cleanupPods , pod1 )
638
+ podsToClean [ string ( pod1 . UID )] = pod1
627
639
628
640
ginkgo .By ("checking if the expected cfs quota was assigned (GU pod, exclusive CPUs, unlimited)" )
629
641
@@ -635,6 +647,7 @@ func runCfsQuotaGuPods(ctx context.Context, f *framework.Framework, disabledCPUQ
635
647
err = e2epod .NewPodClient (f ).MatchContainerOutput (ctx , pod1 .Name , pod1 .Spec .Containers [0 ].Name , expCFSQuotaRegex )
636
648
framework .ExpectNoError (err , "expected log not found in container [%s] of pod [%s]" ,
637
649
pod1 .Spec .Containers [0 ].Name , pod1 .Name )
650
+ deleteTestPod (pod1 )
638
651
639
652
ctnAttrs = []ctnAttribute {
640
653
{
@@ -646,7 +659,7 @@ func runCfsQuotaGuPods(ctx context.Context, f *framework.Framework, disabledCPUQ
646
659
pod2 = makeCPUManagerPod ("gu-pod2" , ctnAttrs )
647
660
pod2 .Spec .Containers [0 ].Command = cfsCheckCommand
648
661
pod2 = e2epod .NewPodClient (f ).CreateSync (ctx , pod2 )
649
- cleanupPods = append ( cleanupPods , pod2 )
662
+ podsToClean [ string ( pod2 . UID )] = pod2
650
663
651
664
ginkgo .By ("checking if the expected cfs quota was assigned (GU pod, limited)" )
652
665
@@ -655,6 +668,7 @@ func runCfsQuotaGuPods(ctx context.Context, f *framework.Framework, disabledCPUQ
655
668
err = e2epod .NewPodClient (f ).MatchContainerOutput (ctx , pod2 .Name , pod2 .Spec .Containers [0 ].Name , expCFSQuotaRegex )
656
669
framework .ExpectNoError (err , "expected log not found in container [%s] of pod [%s]" ,
657
670
pod2 .Spec .Containers [0 ].Name , pod2 .Name )
671
+ deleteTestPod (pod2 )
658
672
659
673
ctnAttrs = []ctnAttribute {
660
674
{
@@ -666,7 +680,7 @@ func runCfsQuotaGuPods(ctx context.Context, f *framework.Framework, disabledCPUQ
666
680
pod3 = makeCPUManagerPod ("non-gu-pod3" , ctnAttrs )
667
681
pod3 .Spec .Containers [0 ].Command = cfsCheckCommand
668
682
pod3 = e2epod .NewPodClient (f ).CreateSync (ctx , pod3 )
669
- cleanupPods = append ( cleanupPods , pod3 )
683
+ podsToClean [ string ( pod3 . UID )] = pod3
670
684
671
685
ginkgo .By ("checking if the expected cfs quota was assigned (BU pod, limited)" )
672
686
@@ -675,73 +689,79 @@ func runCfsQuotaGuPods(ctx context.Context, f *framework.Framework, disabledCPUQ
675
689
err = e2epod .NewPodClient (f ).MatchContainerOutput (ctx , pod3 .Name , pod3 .Spec .Containers [0 ].Name , expCFSQuotaRegex )
676
690
framework .ExpectNoError (err , "expected log not found in container [%s] of pod [%s]" ,
677
691
pod3 .Spec .Containers [0 ].Name , pod3 .Name )
692
+ deleteTestPod (pod3 )
678
693
679
- ctnAttrs = []ctnAttribute {
680
- {
681
- ctnName : "gu-container-non-int-values" ,
682
- cpuRequest : "500m" ,
683
- cpuLimit : "500m" ,
684
- },
685
- {
686
- ctnName : "gu-container-int-values" ,
687
- cpuRequest : "1" ,
688
- cpuLimit : "1" ,
689
- },
690
- }
691
- pod4 := makeCPUManagerPod ("gu-pod4" , ctnAttrs )
692
- pod4 .Spec .Containers [0 ].Command = cfsCheckCommand
693
- pod4 .Spec .Containers [1 ].Command = cfsCheckCommand
694
- pod4 = e2epod .NewPodClient (f ).CreateSync (ctx , pod4 )
695
- cleanupPods = append (cleanupPods , pod4 )
694
+ if cpuAlloc >= 2 {
695
+ ctnAttrs = []ctnAttribute {
696
+ {
697
+ ctnName : "gu-container-non-int-values" ,
698
+ cpuRequest : "500m" ,
699
+ cpuLimit : "500m" ,
700
+ },
701
+ {
702
+ ctnName : "gu-container-int-values" ,
703
+ cpuRequest : "1" ,
704
+ cpuLimit : "1" ,
705
+ },
706
+ }
707
+ pod4 := makeCPUManagerPod ("gu-pod4" , ctnAttrs )
708
+ pod4 .Spec .Containers [0 ].Command = cfsCheckCommand
709
+ pod4 .Spec .Containers [1 ].Command = cfsCheckCommand
710
+ pod4 = e2epod .NewPodClient (f ).CreateSync (ctx , pod4 )
711
+ podsToClean [string (pod4 .UID )] = pod4
712
+
713
+ ginkgo .By ("checking if the expected cfs quota was assigned (GU pod, container 0 exclusive CPUs unlimited, container 1 limited)" )
714
+
715
+ expectedQuota = "50000"
716
+ expCFSQuotaRegex = fmt .Sprintf ("^%s %s\n $" , expectedQuota , defaultPeriod )
717
+ err = e2epod .NewPodClient (f ).MatchContainerOutput (ctx , pod4 .Name , pod4 .Spec .Containers [0 ].Name , expCFSQuotaRegex )
718
+ framework .ExpectNoError (err , "expected log not found in container [%s] of pod [%s]" ,
719
+ pod4 .Spec .Containers [0 ].Name , pod4 .Name )
720
+ expectedQuota = "100000"
721
+ if disabledCPUQuotaWithExclusiveCPUs {
722
+ expectedQuota = "max"
723
+ }
724
+ expCFSQuotaRegex = fmt .Sprintf ("^%s %s\n $" , expectedQuota , defaultPeriod )
725
+ err = e2epod .NewPodClient (f ).MatchContainerOutput (ctx , pod4 .Name , pod4 .Spec .Containers [1 ].Name , expCFSQuotaRegex )
726
+ framework .ExpectNoError (err , "expected log not found in container [%s] of pod [%s]" ,
727
+ pod4 .Spec .Containers [1 ].Name , pod4 .Name )
728
+ deleteTestPod (pod4 )
696
729
697
- ginkgo .By ("checking if the expected cfs quota was assigned (GU pod, container 0 exclusive CPUs unlimited, container 1 limited)" )
730
+ ctnAttrs = []ctnAttribute {
731
+ {
732
+ ctnName : "gu-container-non-int-values" ,
733
+ cpuRequest : "500m" ,
734
+ cpuLimit : "500m" ,
735
+ },
736
+ {
737
+ ctnName : "gu-container-int-values" ,
738
+ cpuRequest : "1" ,
739
+ cpuLimit : "1" ,
740
+ },
741
+ }
698
742
699
- expectedQuota = "50000"
700
- expCFSQuotaRegex = fmt .Sprintf ("^%s %s\n $" , expectedQuota , defaultPeriod )
701
- err = e2epod .NewPodClient (f ).MatchContainerOutput (ctx , pod4 .Name , pod4 .Spec .Containers [0 ].Name , expCFSQuotaRegex )
702
- framework .ExpectNoError (err , "expected log not found in container [%s] of pod [%s]" ,
703
- pod4 .Spec .Containers [0 ].Name , pod4 .Name )
704
- expectedQuota = "100000"
705
- if disabledCPUQuotaWithExclusiveCPUs {
706
- expectedQuota = "max"
707
- }
708
- expCFSQuotaRegex = fmt .Sprintf ("^%s %s\n $" , expectedQuota , defaultPeriod )
709
- err = e2epod .NewPodClient (f ).MatchContainerOutput (ctx , pod4 .Name , pod4 .Spec .Containers [1 ].Name , expCFSQuotaRegex )
710
- framework .ExpectNoError (err , "expected log not found in container [%s] of pod [%s]" ,
711
- pod4 .Spec .Containers [1 ].Name , pod4 .Name )
743
+ pod5 := makeCPUManagerPod ("gu-pod5" , ctnAttrs )
744
+ pod5 .Spec .Containers [0 ].Command = podCFSCheckCommand
745
+ pod5 = e2epod .NewPodClient (f ).CreateSync (ctx , pod5 )
746
+ podsToClean [string (pod5 .UID )] = pod5
712
747
713
- ctnAttrs = []ctnAttribute {
714
- {
715
- ctnName : "gu-container-non-int-values" ,
716
- cpuRequest : "500m" ,
717
- cpuLimit : "500m" ,
718
- },
719
- {
720
- ctnName : "gu-container-int-values" ,
721
- cpuRequest : "1" ,
722
- cpuLimit : "1" ,
723
- },
724
- }
748
+ ginkgo .By ("checking if the expected cfs quota was assigned to pod (GU pod, unlimited)" )
725
749
726
- podCFSCheckCommand := [] string { "sh" , "-c" , `cat $(find /sysfscgroup | grep "$(cat /podinfo/uid | sed 's/-/_/g').slice/cpu.max$") && sleep 1d` }
750
+ expectedQuota = "150000"
727
751
728
- pod5 := makeCPUManagerPod ("gu-pod5" , ctnAttrs )
729
- pod5 .Spec .Containers [0 ].Command = podCFSCheckCommand
730
- pod5 = e2epod .NewPodClient (f ).CreateSync (ctx , pod5 )
731
- cleanupPods = append (cleanupPods , pod5 )
732
- ginkgo .By ("checking if the expected cfs quota was assigned to pod (GU pod, unlimited)" )
752
+ if disabledCPUQuotaWithExclusiveCPUs {
753
+ expectedQuota = "max"
754
+ }
733
755
734
- expectedQuota = "150000"
756
+ expCFSQuotaRegex = fmt . Sprintf ( "^%s %s \n $" , expectedQuota , defaultPeriod )
735
757
736
- if disabledCPUQuotaWithExclusiveCPUs {
737
- expectedQuota = "max"
758
+ err = e2epod .NewPodClient (f ).MatchContainerOutput (ctx , pod5 .Name , pod5 .Spec .Containers [0 ].Name , expCFSQuotaRegex )
759
+ framework .ExpectNoError (err , "expected log not found in container [%s] of pod [%s]" , pod5 .Spec .Containers [0 ].Name , pod5 .Name )
760
+ deleteTestPod (pod5 )
761
+ } else {
762
+ ginkgo .By (fmt .Sprintf ("some cases SKIPPED - requests at least %d allocatable cores, got %d" , 2 , cpuAlloc ))
738
763
}
739
764
740
- expCFSQuotaRegex = fmt .Sprintf ("^%s %s\n $" , expectedQuota , defaultPeriod )
741
-
742
- err = e2epod .NewPodClient (f ).MatchContainerOutput (ctx , pod5 .Name , pod5 .Spec .Containers [0 ].Name , expCFSQuotaRegex )
743
- framework .ExpectNoError (err , "expected log not found in container [%s] of pod [%s]" , pod5 .Spec .Containers [0 ].Name , pod5 .Name )
744
-
745
765
ctnAttrs = []ctnAttribute {
746
766
{
747
767
ctnName : "gu-container" ,
@@ -753,15 +773,15 @@ func runCfsQuotaGuPods(ctx context.Context, f *framework.Framework, disabledCPUQ
753
773
pod6 := makeCPUManagerPod ("gu-pod6" , ctnAttrs )
754
774
pod6 .Spec .Containers [0 ].Command = podCFSCheckCommand
755
775
pod6 = e2epod .NewPodClient (f ).CreateSync (ctx , pod6 )
756
- cleanupPods = append ( cleanupPods , pod6 )
776
+ podsToClean [ string ( pod6 . UID )] = pod6
757
777
758
778
ginkgo .By ("checking if the expected cfs quota was assigned to pod (GU pod, limited)" )
759
779
760
780
expectedQuota = "10000"
761
781
expCFSQuotaRegex = fmt .Sprintf ("^%s %s\n $" , expectedQuota , defaultPeriod )
762
782
err = e2epod .NewPodClient (f ).MatchContainerOutput (ctx , pod6 .Name , pod6 .Spec .Containers [0 ].Name , expCFSQuotaRegex )
763
783
framework .ExpectNoError (err , "expected log not found in container [%s] of pod [%s]" , pod6 .Spec .Containers [0 ].Name , pod6 .Name )
764
-
784
+ deleteTestPod ( pod6 )
765
785
}
766
786
767
787
func runMultipleGuPods (ctx context.Context , f * framework.Framework ) {
@@ -921,6 +941,10 @@ func runCPUManagerTests(f *framework.Framework) {
921
941
if ! IsCgroup2UnifiedMode () {
922
942
e2eskipper .Skipf ("Skipping since CgroupV2 not used" )
923
943
}
944
+ _ , cpuAlloc , _ = getLocalNodeCPUDetails (ctx , f )
945
+ if cpuAlloc < 1 { // save expensive kubelet restart
946
+ e2eskipper .Skipf ("Skipping since not enough allocatable CPU got %d required 1" , cpuAlloc )
947
+ }
924
948
newCfg := configureCPUManagerInKubelet (oldCfg ,
925
949
& cpuManagerKubeletArguments {
926
950
policyName : string (cpumanager .PolicyStatic ),
@@ -929,13 +953,19 @@ func runCPUManagerTests(f *framework.Framework) {
929
953
},
930
954
)
931
955
updateKubeletConfig (ctx , f , newCfg , true )
932
- runCfsQuotaGuPods (ctx , f , true )
956
+
957
+ _ , cpuAlloc , _ = getLocalNodeCPUDetails (ctx , f ) // check again after we reserved 1 full CPU. Some tests require > 1 exclusive CPU
958
+ runCfsQuotaGuPods (ctx , f , true , cpuAlloc )
933
959
})
934
960
935
961
ginkgo .It ("should keep enforcing the CFS quota for containers with static CPUs assigned and feature gate disabled" , func (ctx context.Context ) {
936
962
if ! IsCgroup2UnifiedMode () {
937
963
e2eskipper .Skipf ("Skipping since CgroupV2 not used" )
938
964
}
965
+ _ , cpuAlloc , _ = getLocalNodeCPUDetails (ctx , f )
966
+ if cpuAlloc < 1 { // save expensive kubelet restart
967
+ e2eskipper .Skipf ("Skipping since not enough allocatable CPU got %d required 1" , cpuAlloc )
968
+ }
939
969
newCfg := configureCPUManagerInKubelet (oldCfg ,
940
970
& cpuManagerKubeletArguments {
941
971
policyName : string (cpumanager .PolicyStatic ),
@@ -945,7 +975,9 @@ func runCPUManagerTests(f *framework.Framework) {
945
975
)
946
976
947
977
updateKubeletConfig (ctx , f , newCfg , true )
948
- runCfsQuotaGuPods (ctx , f , false )
978
+
979
+ _ , cpuAlloc , _ = getLocalNodeCPUDetails (ctx , f ) // check again after we reserved 1 full CPU. Some tests require > 1 exclusive CPU
980
+ runCfsQuotaGuPods (ctx , f , false , cpuAlloc )
949
981
})
950
982
951
983
f .It ("should not reuse CPUs of restartable init containers" , feature .SidecarContainers , func (ctx context.Context ) {
0 commit comments