@@ -301,7 +301,7 @@ func checkWorkloadPodSpecs(tr *evalTracker, input *CheckInput) []Finding {
301301 for _ , w := range specs {
302302 findings = append (findings , checkPodSpecSecurity (tr , w .kind , w .namespace , w .name , w .spec , saByKey , saCovers (w .namespace ))... )
303303 findings = append (findings , checkPodSpecReliability (tr , w .kind , w .namespace , w .name , w .spec )... )
304- findings = append (findings , checkPodSpecEfficiency (tr , w .kind , w .namespace , w .name , w .spec , limitsByNs [w .namespace ], lrAuthoritative )... )
304+ findings = append (findings , checkPodSpecEfficiency (tr , w .kind , w .namespace , w .name , w .spec , limitsByNs [w .namespace ], lrAuthoritative , input . ClusterVersion )... )
305305 findings = append (findings , checkPodSpecVolumes (tr , w .kind , w .namespace , w .name , w .spec )... )
306306 }
307307 return findings
@@ -359,40 +359,6 @@ func indexLimitRangesByNamespace(lrs []*corev1.LimitRange) map[string][]*corev1.
359359 return m
360360}
361361
362- // containerDefaultsFromLimitRanges reports which container resource types
363- // (cpu/memory requests/limits) would be filled in by admission based on the
364- // namespace's LimitRange defaults. Only LimitRange items with Type=Container
365- // contribute to container defaults.
366- type containerDefaults struct {
367- cpuRequest , memoryRequest bool
368- cpuLimit , memoryLimit bool
369- }
370-
371- func containerDefaultsFromLimitRanges (lrs []* corev1.LimitRange ) containerDefaults {
372- var d containerDefaults
373- for _ , lr := range lrs {
374- for _ , item := range lr .Spec .Limits {
375- if item .Type != corev1 .LimitTypeContainer {
376- continue
377- }
378- // DefaultRequest covers requests; Default covers limits.
379- if _ , ok := item .DefaultRequest [corev1 .ResourceCPU ]; ok {
380- d .cpuRequest = true
381- }
382- if _ , ok := item .DefaultRequest [corev1 .ResourceMemory ]; ok {
383- d .memoryRequest = true
384- }
385- if _ , ok := item .Default [corev1 .ResourceCPU ]; ok {
386- d .cpuLimit = true
387- }
388- if _ , ok := item .Default [corev1 .ResourceMemory ]; ok {
389- d .memoryLimit = true
390- }
391- }
392- }
393- return d
394- }
395-
396362// ============================================================================
397363// Security checks
398364// ============================================================================
@@ -851,42 +817,55 @@ func checkMissingPDB(tr *evalTracker, deployments []*appsv1.Deployment, stateful
851817// Efficiency checks
852818// ============================================================================
853819
854- func checkPodSpecEfficiency (tr * evalTracker , kind , namespace , name string , spec corev1.PodSpec , lrs []* corev1.LimitRange , lrAuthoritative bool ) []Finding {
855- if ! lrAuthoritative {
856- // LimitRange defaults suppress these findings; without the inventory
857- // every emission would be a potential false positive. Skip the whole
858- // family rather than report on data Radar couldn't see.
820+ func checkPodSpecEfficiency (tr * evalTracker , kind , namespace , name string , spec corev1.PodSpec , lrs []* corev1.LimitRange , lrAuthoritative bool , version string ) []Finding {
821+ if kind != "Pod" && ! lrAuthoritative {
859822 return nil
860823 }
861- tr .recordAll (podSpecEfficiencyCheckIDs , namespace )
862- var findings []Finding
863- f := func (checkID , severity , msg string ) {
864- findings = append (findings , Finding {
865- Kind : kind , Namespace : namespace , Name : name ,
866- CheckID : checkID , Category : CategoryEfficiency , Severity : severity , Message : msg ,
867- })
824+ candidates := podResourceCandidates (spec , kind == "Pod" , version , lrs )
825+ containerSets := make ([][]corev1.Container , len (candidates ))
826+ for i , candidate := range candidates {
827+ containerSets [i ] = efficiencyContainers (candidate )
868828 }
869-
870- // LimitRange defaults in the namespace are applied by admission — skip
871- // flagging missing values that would be filled in automatically.
872- defaults := containerDefaultsFromLimitRanges (lrs )
873-
874- for _ , c := range spec .Containers {
875- res := c .Resources
876- if (res .Requests .Cpu () == nil || res .Requests .Cpu ().IsZero ()) && ! defaults .cpuRequest {
877- f ("cpuRequestMissing" , SeverityWarning , fmt .Sprintf ("Container %q has no CPU request" , c .Name ))
878- }
879- if (res .Requests .Memory () == nil || res .Requests .Memory ().IsZero ()) && ! defaults .memoryRequest {
880- f ("memoryRequestMissing" , SeverityWarning , fmt .Sprintf ("Container %q has no memory request" , c .Name ))
881- }
882- if (res .Limits .Cpu () == nil || res .Limits .Cpu ().IsZero ()) && ! defaults .cpuLimit {
883- f ("cpuLimitMissing" , SeverityWarning , fmt .Sprintf ("Container %q has no CPU limit" , c .Name ))
829+ var findings []Finding
830+ for _ , check := range []struct {
831+ id , label string
832+ resource corev1.ResourceName
833+ request bool
834+ }{
835+ {"cpuRequestMissing" , "CPU request" , corev1 .ResourceCPU , true },
836+ {"memoryRequestMissing" , "memory request" , corev1 .ResourceMemory , true },
837+ {"cpuLimitMissing" , "CPU limit" , corev1 .ResourceCPU , false },
838+ {"memoryLimitMissing" , "memory limit" , corev1 .ResourceMemory , false },
839+ } {
840+ allCovered , failed := true , false
841+ for i , c := range efficiencyContainers (spec ) {
842+ alwaysMissing := true
843+ for j , candidate := range candidates {
844+ if resourceConfigured (candidate , containerSets [j ][i ], check .resource , check .request ) {
845+ alwaysMissing = false
846+ } else {
847+ allCovered = false
848+ }
849+ }
850+ if alwaysMissing {
851+ label := "Container"
852+ if i >= len (spec .Containers ) {
853+ label = "Sidecar"
854+ }
855+ findings = append (findings , Finding {
856+ Kind : kind , Namespace : namespace , Name : name ,
857+ CheckID : check .id , Category : CategoryEfficiency , Severity : SeverityWarning ,
858+ Message : fmt .Sprintf ("%s %q has no %s" , label , c .Name , check .label ),
859+ })
860+ failed = true
861+ }
884862 }
885- if (res .Limits .Memory () == nil || res .Limits .Memory ().IsZero ()) && ! defaults .memoryLimit {
886- f ("memoryLimitMissing" , SeverityWarning , fmt .Sprintf ("Container %q has no memory limit" , c .Name ))
863+ if allCovered || failed {
864+ tr .record (check .id , namespace )
865+ } else {
866+ tr .skip ("pod-resource-defaulting" )
887867 }
888868 }
889-
890869 return findings
891870}
892871
0 commit comments