@@ -993,3 +993,146 @@ func makeAllocationManager(t *testing.T, runtime *containertest.FakeRuntime, all
993
993
994
994
return allocationManager
995
995
}
996
+
997
+ // testPodAdmitHandler is a lifecycle.PodAdmitHandler for testing.
998
+ type testPodAdmitHandler struct {
999
+ // list of pods to reject.
1000
+ podsToReject []* v1.Pod
1001
+ }
1002
+
1003
+ // Admit rejects all pods in the podsToReject list with a matching UID.
1004
+ func (a * testPodAdmitHandler ) Admit (attrs * lifecycle.PodAdmitAttributes ) lifecycle.PodAdmitResult {
1005
+ for _ , podToReject := range a .podsToReject {
1006
+ if podToReject .UID == attrs .Pod .UID {
1007
+ return lifecycle.PodAdmitResult {Admit : false , Reason : "Rejected" , Message : "Pod is rejected" }
1008
+ }
1009
+ }
1010
+ return lifecycle.PodAdmitResult {Admit : true }
1011
+ }
1012
+
1013
+ func TestAllocationManagerAddPod (t * testing.T ) {
1014
+ if goruntime .GOOS == "windows" {
1015
+ t .Skip ("InPlacePodVerticalScaling is not currently supported for Windows" )
1016
+ }
1017
+ featuregatetesting .SetFeatureGateDuringTest (t , utilfeature .DefaultFeatureGate , features .InPlacePodVerticalScaling , true )
1018
+
1019
+ const containerName = "c1"
1020
+
1021
+ basePod1 := & v1.Pod {
1022
+ ObjectMeta : metav1.ObjectMeta {UID : "111" , Name : "pod1" , Namespace : "ns1" },
1023
+ Spec : v1.PodSpec {Containers : []v1.Container {{Name : containerName , Image : "i1" }}},
1024
+ }
1025
+ basePod2 := & v1.Pod {
1026
+ ObjectMeta : metav1.ObjectMeta {UID : "222" , Name : "pod2" , Namespace : "ns2" },
1027
+ Spec : v1.PodSpec {Containers : []v1.Container {{Name : containerName , Image : "i2" }}},
1028
+ }
1029
+
1030
+ cpu1Mem1G := v1.ResourceList {v1 .ResourceCPU : resource .MustParse ("1" ), v1 .ResourceMemory : resource .MustParse ("1Gi" )}
1031
+ cpu2Mem2G := v1.ResourceList {v1 .ResourceCPU : resource .MustParse ("2" ), v1 .ResourceMemory : resource .MustParse ("2Gi" )}
1032
+
1033
+ newPodWithResources := func (basePod * v1.Pod , resources v1.ResourceList ) * v1.Pod {
1034
+ podCopy := basePod .DeepCopy ()
1035
+ podCopy .Spec .Containers [0 ].Resources = v1.ResourceRequirements {Requests : resources }
1036
+ return podCopy
1037
+ }
1038
+
1039
+ pod1v1 := newPodWithResources (basePod1 , cpu1Mem1G ) // Pod1 with 1 CPU and 1G Memory
1040
+ pod1v2 := newPodWithResources (basePod1 , cpu2Mem2G ) // Pod1 with 2 CPU and 2G Memory
1041
+ pod2v1 := newPodWithResources (basePod2 , cpu1Mem1G ) // Pod2 with 1 CPU and 1G Memory
1042
+
1043
+ testCases := []struct {
1044
+ name string
1045
+ initialAllocatedResourcesState map [types.UID ]v1.ResourceList
1046
+ activePods []* v1.Pod
1047
+ podToAdd * v1.Pod
1048
+ admitPod bool
1049
+ expectedAllocatedResourcesState map [types.UID ]v1.ResourceList
1050
+ }{
1051
+ {
1052
+ name : "Pod added without resources changes" ,
1053
+ initialAllocatedResourcesState : map [types.UID ]v1.ResourceList {basePod1 .UID : cpu1Mem1G , basePod2 .UID : cpu1Mem1G },
1054
+ activePods : []* v1.Pod {pod1v1 , pod2v1 },
1055
+ podToAdd : pod1v1 ,
1056
+ admitPod : true ,
1057
+ // exppected state is the same as initial state
1058
+ expectedAllocatedResourcesState : map [types.UID ]v1.ResourceList {basePod1 .UID : cpu1Mem1G , basePod2 .UID : cpu1Mem1G },
1059
+ },
1060
+ {
1061
+ name : "Pod added with resources changes." ,
1062
+ initialAllocatedResourcesState : map [types.UID ]v1.ResourceList {basePod1 .UID : cpu1Mem1G , basePod2 .UID : cpu1Mem1G },
1063
+ activePods : []* v1.Pod {pod1v2 , pod2v1 },
1064
+ podToAdd : pod1v2 ,
1065
+ admitPod : true ,
1066
+ // Allocated Resources state must not be updated.
1067
+ expectedAllocatedResourcesState : map [types.UID ]v1.ResourceList {basePod1 .UID : cpu1Mem1G , basePod2 .UID : cpu1Mem1G },
1068
+ },
1069
+ {
1070
+ name : "allocated resources updated when pod is admitted" ,
1071
+ initialAllocatedResourcesState : map [types.UID ]v1.ResourceList {basePod1 .UID : cpu1Mem1G },
1072
+ activePods : []* v1.Pod {pod1v1 , pod2v1 },
1073
+ podToAdd : pod2v1 ,
1074
+ admitPod : true ,
1075
+ // pod2's resources added to allocated resources
1076
+ expectedAllocatedResourcesState : map [types.UID ]v1.ResourceList {basePod1 .UID : cpu1Mem1G , basePod2 .UID : cpu1Mem1G },
1077
+ },
1078
+ {
1079
+ name : "allocated resources not modified when pod is not admitted" ,
1080
+ initialAllocatedResourcesState : map [types.UID ]v1.ResourceList {basePod1 .UID : cpu1Mem1G , basePod2 .UID : cpu1Mem1G },
1081
+ activePods : []* v1.Pod {pod1v1 , pod2v1 },
1082
+ podToAdd : pod1v2 ,
1083
+ admitPod : false ,
1084
+ // pod1's allocated resources not modified
1085
+ expectedAllocatedResourcesState : map [types.UID ]v1.ResourceList {basePod1 .UID : cpu1Mem1G , basePod2 .UID : cpu1Mem1G },
1086
+ },
1087
+ }
1088
+
1089
+ for _ , tc := range testCases {
1090
+ t .Run (tc .name , func (t * testing.T ) {
1091
+ allocationManager := makeAllocationManager (t , & containertest.FakeRuntime {}, []* v1.Pod {})
1092
+
1093
+ podForAllocation := func (uid types.UID , resources v1.ResourceList ) * v1.Pod {
1094
+ return & v1.Pod {
1095
+ ObjectMeta : metav1.ObjectMeta {UID : uid },
1096
+ Spec : v1.PodSpec {
1097
+ Containers : []v1.Container {{
1098
+ Name : containerName ,
1099
+ Resources : v1.ResourceRequirements {Requests : resources },
1100
+ }},
1101
+ },
1102
+ }
1103
+ }
1104
+
1105
+ for podUID , resources := range tc .initialAllocatedResourcesState {
1106
+ err := allocationManager .SetAllocatedResources (podForAllocation (podUID , resources ))
1107
+ require .NoError (t , err )
1108
+ }
1109
+
1110
+ if ! tc .admitPod {
1111
+ allocationManager .AddPodAdmitHandlers (lifecycle.PodAdmitHandlers {& testPodAdmitHandler {podsToReject : []* v1.Pod {tc .podToAdd }}})
1112
+ }
1113
+ ok , _ , _ := allocationManager .AddPod (tc .activePods , tc .podToAdd )
1114
+ require .Equal (t , tc .admitPod , ok )
1115
+
1116
+ for podUID , resources := range tc .expectedAllocatedResourcesState {
1117
+ pod := podForAllocation (podUID , resources )
1118
+ for _ , container := range pod .Spec .Containers {
1119
+ allocatedResources , found := allocationManager .GetContainerResourceAllocation (pod .UID , container .Name )
1120
+ if pod .UID == tc .podToAdd .UID {
1121
+ if tc .admitPod && ! found {
1122
+ t .Fatalf ("resource allocation should exis for pod: %s" , tc .podToAdd .Name )
1123
+ }
1124
+ if ! tc .admitPod && found {
1125
+ initialResources := tc .initialAllocatedResourcesState [pod .UID ]
1126
+ // allocated resources should not be modified when the pod is not admitted
1127
+ assert .Equal (t , initialResources , allocatedResources .Requests , tc .name )
1128
+ }
1129
+ }
1130
+ assert .Equal (t , container .Resources , allocatedResources , tc .name )
1131
+ }
1132
+ }
1133
+
1134
+ // Undo current modifications
1135
+ allocationManager .RemovePod (tc .podToAdd .UID )
1136
+ })
1137
+ }
1138
+ }
0 commit comments