fix: handle nil ResourceList in max() to prevent panic

This commit is contained in:
Daniel Maizel
2026-01-28 16:07:25 +02:00
parent f4eedc41b8
commit 7d5b4710bd
2 changed files with 102 additions and 1 deletions

View File

@@ -152,7 +152,12 @@ func determineContainerReqs(pod *corev1.Pod, container *corev1.Container, cs *co
// max returns the result of max(a, b...) for each named resource and is only used if we can't
// accumulate into an existing resource list
func max(a corev1.ResourceList, b ...corev1.ResourceList) corev1.ResourceList {
result := a.DeepCopy()
var result corev1.ResourceList
if a != nil {
result = a.DeepCopy()
} else {
result = corev1.ResourceList{}
}
for _, other := range b {
maxResourceList(result, other)
}

View File

@@ -0,0 +1,96 @@
/*
Copyright The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package resource
import (
"testing"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
)
func TestMaxWithNilResourceList(t *testing.T) {
tests := []struct {
name string
a corev1.ResourceList
b []corev1.ResourceList
want corev1.ResourceList
}{
{
name: "nil first argument with non-nil second",
a: nil,
b: []corev1.ResourceList{{corev1.ResourceCPU: resource.MustParse("100m")}},
want: corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("100m")},
},
{
name: "nil first argument with nil second",
a: nil,
b: []corev1.ResourceList{nil},
want: corev1.ResourceList{},
},
{
name: "nil first argument with empty second",
a: nil,
b: []corev1.ResourceList{{}},
want: corev1.ResourceList{},
},
{
name: "nil first argument with no second arguments",
a: nil,
b: nil,
want: corev1.ResourceList{},
},
{
name: "empty first argument with non-nil second",
a: corev1.ResourceList{},
b: []corev1.ResourceList{{corev1.ResourceCPU: resource.MustParse("100m")}},
want: corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("100m")},
},
{
name: "non-nil first argument takes max",
a: corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("200m")},
b: []corev1.ResourceList{{corev1.ResourceCPU: resource.MustParse("100m")}},
want: corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("200m")},
},
{
name: "second argument larger takes max",
a: corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("100m")},
b: []corev1.ResourceList{{corev1.ResourceCPU: resource.MustParse("200m")}},
want: corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("200m")},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := max(tt.a, tt.b...)
if len(got) != len(tt.want) {
t.Errorf("case %q, expected %d resources but got %d", tt.name, len(tt.want), len(got))
return
}
for name, wantQty := range tt.want {
gotQty, ok := got[name]
if !ok {
t.Errorf("case %q, expected resource %s but it was missing", tt.name, name)
continue
}
if gotQty.Cmp(wantQty) != 0 {
t.Errorf("case %q, expected resource %s to be %s but got %s", tt.name, name, wantQty.String(), gotQty.String())
}
}
})
}
}