4949// than pod with 100M current memory and 150M recommendation (100% increase vs 50% increase)
5050type UpdatePriorityCalculator struct {
5151 vpa * vpa_types.VerticalPodAutoscaler
52- pods []PrioritizedPod
52+ pods []prioritizedPod
5353 config * UpdateConfig
5454 recommendationProcessor vpa_api_util.RecommendationProcessor
5555 priorityProcessor PriorityProcessor
@@ -117,8 +117,6 @@ func (calc *UpdatePriorityCalculator) AddPod(pod *apiv1.Pod, now time.Time) {
117117 }
118118 }
119119
120- disruptionlessRecommendation := calc .CalculateDisruptionFreeActions (pod , processedRecommendation )
121-
122120 // The update is allowed in following cases:
123121 // - the request is outside the recommended range for some container.
124122 // - the pod lives for at least 24h and the resource diff is >= MinChangePriority.
@@ -129,31 +127,12 @@ func (calc *UpdatePriorityCalculator) AddPod(pod *apiv1.Pod, now time.Time) {
129127 klog .V (4 ).InfoS ("Not updating pod, missing field pod.Status.StartTime" , "pod" , klog .KObj (pod ))
130128 return
131129 }
132- // TODO(maxcao13): hopefully this doesn't break anything but we switch the order so that significant change is checked first before lifetime
133- // this way we don't in-place scale it for insignificant change, else we would mark it disruptionless and still have an in-place update
134- if updatePriority .ResourceDiff < calc .config .MinChangePriority {
135- klog .V (4 ).InfoS ("Not updating pod, resource diff too low" , "pod" , klog .KObj (pod ), "updatePriority" , updatePriority )
130+ if now .Before (pod .Status .StartTime .Add (* podLifetimeUpdateThreshold )) {
131+ klog .V (4 ).InfoS ("Not updating a short-lived pod, request within recommended range" , "pod" , klog .KObj (pod ))
136132 return
137133 }
138- if now .Before (pod .Status .StartTime .Add (* podLifetimeUpdateThreshold )) {
139- // TODO(jkyros): do we need an in-place update threshold arg ?
140- // If our recommendations are disruptionless, we can bypass the threshold limit
141- if len (disruptionlessRecommendation .ContainerRecommendations ) > 0 {
142- klog .V (2 ).InfoS ("Short-lived, but pod still accepted for disruptionless in-place update" ,
143- "pod" , klog .KObj (pod ),
144- "numContainers" , len (pod .Spec .Containers ),
145- "resourceDiff" , updatePriority .ResourceDiff ,
146- "fractionOfDisruptionlessRecommendations" , len (disruptionlessRecommendation .ContainerRecommendations )/ len (processedRecommendation .ContainerRecommendations ),
147- )
148- updatePriority .Disruptionless = true
149- calc .pods = append (calc .pods , PrioritizedPod {
150- pod : pod ,
151- priority : updatePriority ,
152- recommendation : disruptionlessRecommendation })
153- } else {
154- // we cannot perform this update disruption-free, so do not update this pod's resources
155- klog .V (4 ).InfoS ("Not updating a short-lived pod, request within recommended range" , "pod" , klog .KObj (pod ))
156- }
134+ if updatePriority .ResourceDiff < calc .config .MinChangePriority {
135+ klog .V (4 ).InfoS ("Not updating pod, resource diff too low" , "pod" , klog .KObj (pod ), "updatePriority" , updatePriority )
157136 return
158137 }
159138 }
@@ -164,30 +143,12 @@ func (calc *UpdatePriorityCalculator) AddPod(pod *apiv1.Pod, now time.Time) {
164143 return
165144 }
166145 klog .V (2 ).InfoS ("Pod accepted for update" , "pod" , klog .KObj (pod ), "updatePriority" , updatePriority .ResourceDiff , "processedRecommendations" , calc .GetProcessedRecommendationTargets (processedRecommendation ))
167- calc .pods = append (calc .pods , PrioritizedPod {
146+ calc .pods = append (calc .pods , prioritizedPod {
168147 pod : pod ,
169148 priority : updatePriority ,
170149 recommendation : processedRecommendation })
171150}
172151
173- // GetSortedPrioritizedPods returns a list of prioritized pods ordered by update priority (highest update priority first). Used instead
174- // of GetSortedPods when we need access to the priority information
175- func (calc * UpdatePriorityCalculator ) GetSortedPrioritizedPods (admission PodEvictionAdmission ) []* PrioritizedPod {
176- sort .Sort (byPriorityDesc (calc .pods ))
177-
178- //result := []*apiv1.Pod{}
179- result := []* PrioritizedPod {}
180- for num , podPrio := range calc .pods {
181- if admission .Admit (podPrio .pod , podPrio .recommendation ) {
182- result = append (result , & calc .pods [num ])
183- } else {
184- klog .V (2 ).InfoS ("Pod removed from update queue by PodEvictionAdmission" , "pod" , klog .KObj (podPrio .Pod ()))
185- }
186- }
187-
188- return result
189- }
190-
191152// GetSortedPods returns a list of pods ordered by update priority (highest update priority first)
192153func (calc * UpdatePriorityCalculator ) GetSortedPods (admission PodEvictionAdmission ) []* apiv1.Pod {
193154 sort .Sort (byPriorityDesc (calc .pods ))
@@ -246,25 +207,12 @@ func parseVpaObservedContainers(pod *apiv1.Pod) (bool, sets.Set[string]) {
246207 return hasObservedContainers , vpaContainerSet
247208}
248209
249- // PrioritizedPod contains the priority and recommendation details for a pod.
250- // TODO(jkyros): I made this public, but there may be a cleaner way
251- type PrioritizedPod struct {
210+ type prioritizedPod struct {
252211 pod * apiv1.Pod
253212 priority PodPriority
254213 recommendation * vpa_types.RecommendedPodResources
255214}
256215
257- // IsDisruptionless returns the disruptionless status of the underlying pod priority
258- // TODO(jkyros): scope issues, maybe not the best place to put Disruptionless
259- func (p PrioritizedPod ) IsDisruptionless () bool {
260- return p .priority .Disruptionless
261- }
262-
263- // Pod returns the underlying private pod
264- func (p PrioritizedPod ) Pod () * apiv1.Pod {
265- return p .pod
266- }
267-
268216// PodPriority contains data for a pod update that can be used to prioritize between updates.
269217type PodPriority struct {
270218 // Is any container outside of the recommended range.
@@ -273,11 +221,9 @@ type PodPriority struct {
273221 ScaleUp bool
274222 // Relative difference between the total requested and total recommended resources.
275223 ResourceDiff float64
276- // Is this update disruptionless
277- Disruptionless bool
278224}
279225
280- type byPriorityDesc []PrioritizedPod
226+ type byPriorityDesc []prioritizedPod
281227
282228func (list byPriorityDesc ) Len () int {
283229 return len (list )
@@ -305,67 +251,3 @@ func (p PodPriority) Less(other PodPriority) bool {
305251 // 2. A pod with larger value of resourceDiff takes precedence.
306252 return p .ResourceDiff < other .ResourceDiff
307253}
308-
309- // CalculateDisruptionFreeActions calculates the set of actions we think we can perform without disruption based on the pod/container resize/restart
310- // policies and returns that set of actions.
311- func (calc * UpdatePriorityCalculator ) CalculateDisruptionFreeActions (pod * apiv1.Pod , recommendation * vpa_types.RecommendedPodResources ) * vpa_types.RecommendedPodResources {
312-
313- var disruptionlessRecommendation = & vpa_types.RecommendedPodResources {}
314-
315- for _ , container := range pod .Spec .Containers {
316- // If we don't have a resize policy, we can't check it
317- if len (container .ResizePolicy ) == 0 {
318- continue
319- }
320-
321- // So we get whatever the recommendation was for this container
322- resourceRec := getRecommendationForContainerName (container .Name , recommendation )
323- // If we didn't find a recommendation for this container, we don't have anything to do
324- if resourceRec == nil {
325- continue
326- }
327- // Then we go through all the resource recommendations it has
328- for resource := range resourceRec .Target {
329- // And we look up what the restart policy is for those resources
330- resourceRestartPolicy := getRestartPolicyForResource (resource , container .ResizePolicy )
331- // If we don't have one, that's probably bad
332- if resourceRestartPolicy == nil {
333- continue
334- }
335- // If we do have one, and it's disruptive, then we know this won't work
336- if * resourceRestartPolicy != apiv1 .NotRequired {
337- continue
338- }
339-
340- }
341-
342- // And if we made it here, we should theoretically be able to do this without disruption
343- disruptionlessRecommendation .ContainerRecommendations = append (disruptionlessRecommendation .ContainerRecommendations , * resourceRec )
344-
345- }
346-
347- return disruptionlessRecommendation
348- }
349-
350- // getRecommendationForContainerName searches through the list of ContainerRecommendations until it finds one matching the named container. Used
351- // to match up containers with their recommendations (we have container, we want resource recommendation)
352- func getRecommendationForContainerName (name string , recommendation * vpa_types.RecommendedPodResources ) * vpa_types.RecommendedContainerResources {
353- for _ , recommendationContainer := range recommendation .ContainerRecommendations {
354- if recommendationContainer .ContainerName == name {
355- return & recommendationContainer
356- }
357- }
358- return nil
359- }
360-
361- // getRestartPolicyForResource searches through the list of resources in the resize policy until it finds the one matching the named resource. Used
362- // to match up restart policies with our resource recommendations (we have resource, we want policy).
363- func getRestartPolicyForResource (resourceName apiv1.ResourceName , policy []apiv1.ContainerResizePolicy ) * apiv1.ResourceResizeRestartPolicy {
364- // TODO(jkyros): can there be duplicate policies for resources? we just take the first one now
365- for _ , resizePolicy := range policy {
366- if resizePolicy .ResourceName == resourceName {
367- return & resizePolicy .RestartPolicy
368- }
369- }
370- return nil
371- }
0 commit comments