sigs.k8s.io/kueue@v0.6.2/pkg/util/limitrange/limitrange.go (about) 1 /* 2 Copyright 2023 The Kubernetes 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 limitrange 18 19 import ( 20 "fmt" 21 "strings" 22 23 corev1 "k8s.io/api/core/v1" 24 "k8s.io/utils/field" 25 26 "sigs.k8s.io/kueue/pkg/util/resource" 27 ) 28 29 type Summary map[corev1.LimitType]corev1.LimitRangeItem 30 31 // Summarize summarizes the provides ranges by: 32 // 1. keeping the lowest values for Max and MaxLimitReqestRatio limits 33 // 2. keeping the highest values for Min limits 34 // 3. keeping the first encountered values for Default and DefaultRequests 35 func Summarize(ranges ...corev1.LimitRange) Summary { 36 ret := make(Summary, 3) 37 for i := range ranges { 38 for _, item := range ranges[i].Spec.Limits { 39 ret[item.Type] = addToSummary(ret[item.Type], item) 40 } 41 } 42 return ret 43 } 44 45 func addToSummary(summary, item corev1.LimitRangeItem) corev1.LimitRangeItem { 46 summary.Max = resource.MergeResourceListKeepMin(summary.Max, item.Max) 47 summary.Min = resource.MergeResourceListKeepMax(summary.Min, item.Min) 48 49 summary.Default = resource.MergeResourceListKeepFirst(summary.Default, item.Default) 50 summary.DefaultRequest = resource.MergeResourceListKeepFirst(summary.DefaultRequest, item.DefaultRequest) 51 52 summary.MaxLimitRequestRatio = resource.MergeResourceListKeepMin(summary.MaxLimitRequestRatio, item.MaxLimitRequestRatio) 53 return summary 54 } 55 56 func violateMaxMessage(path *field.Path, keys ...string) string { 57 return fmt.Sprintf("the requests of %s[%s] exceeds the limits", path.String(), strings.Join(keys, ", ")) 58 } 59 func violateMinMessage(path *field.Path, keys ...string) string { 60 return fmt.Sprintf("the requests of %s[%s] are less than the limits", path.String(), strings.Join(keys, ", ")) 61 } 62 63 func (s Summary) validatePodSpecContainers(containers []corev1.Container, path *field.Path) []string { 64 containerRange, found := s[corev1.LimitTypeContainer] 65 if !found { 66 return nil 67 } 68 reasons := []string{} 69 for i := range containers { 70 res := &containers[i].Resources 71 cMin := resource.MergeResourceListKeepMin(res.Requests, res.Limits) 72 cMax := resource.MergeResourceListKeepMax(res.Requests, res.Limits) 73 if list := resource.GetGreaterKeys(cMax, containerRange.Max); len(list) > 0 { 74 reasons = append(reasons, violateMaxMessage(path.Index(i), list...)) 75 } 76 if list := resource.GetGreaterKeys(containerRange.Min, cMin); len(list) > 0 { 77 reasons = append(reasons, violateMinMessage(path.Index(i), list...)) 78 } 79 } 80 return reasons 81 } 82 83 // TotalRequests computes the total resource requests of a pod. 84 // total = sum(max(sum(.containers[].requests), initContainers[].requests), overhead) 85 func TotalRequests(ps *corev1.PodSpec) corev1.ResourceList { 86 total := corev1.ResourceList{} 87 88 // add the resource from the main containers 89 for i := range ps.Containers { 90 total = resource.MergeResourceListKeepSum(total, ps.Containers[i].Resources.Requests) 91 } 92 93 // take into account the maximum of any init containers 94 for i := range ps.InitContainers { 95 total = resource.MergeResourceListKeepMax(total, ps.InitContainers[i].Resources.Requests) 96 } 97 98 // add the overhead 99 total = resource.MergeResourceListKeepSum(total, ps.Overhead) 100 return total 101 } 102 103 // ValidatePodSpec verifies if the provided podSpec (ps) first into the boundaries of the summary (s). 104 func (s Summary) ValidatePodSpec(ps *corev1.PodSpec, path *field.Path) []string { 105 reasons := []string{} 106 reasons = append(reasons, s.validatePodSpecContainers(ps.InitContainers, path.Child("initContainers"))...) 107 reasons = append(reasons, s.validatePodSpecContainers(ps.Containers, path.Child("containers"))...) 108 if containerRange, found := s[corev1.LimitTypePod]; found { 109 total := TotalRequests(ps) 110 if list := resource.GetGreaterKeys(total, containerRange.Max); len(list) > 0 { 111 reasons = append(reasons, violateMaxMessage(path, list...)) 112 } 113 if list := resource.GetGreaterKeys(containerRange.Min, total); len(list) > 0 { 114 reasons = append(reasons, violateMinMessage(path, list...)) 115 } 116 } 117 return reasons 118 }