drop unrelated changes for /resize request

Since resize request takes the full pod object as the request type, drop
any unrelated changes. Only container resources and resize policy should
be validated.
This commit is contained in:
Anish Shah 2024-10-22 12:20:30 -07:00
parent 507ce443b0
commit 8f967c19b3
2 changed files with 352 additions and 0 deletions

View File

@ -284,10 +284,34 @@ type podResizeStrategy struct {
// ResizeStrategy wraps and exports the used podStrategy for the storage package.
var ResizeStrategy = podResizeStrategy{Strategy}
// dropNonPodResizeUpdates discards all changes except for pod.Spec.Containers[*].Resources,ResizePolicy and certain metadata
func dropNonPodResizeUpdates(newPod, oldPod *api.Pod) *api.Pod {
pod := oldPod.DeepCopy()
pod.Name = newPod.Name
pod.Namespace = newPod.Namespace
pod.ResourceVersion = newPod.ResourceVersion
pod.UID = newPod.UID
oldCtrToIndex := make(map[string]int)
for idx, ctr := range pod.Spec.Containers {
oldCtrToIndex[ctr.Name] = idx
}
for _, ctr := range newPod.Spec.Containers {
idx, ok := oldCtrToIndex[ctr.Name]
if !ok {
continue
}
pod.Spec.Containers[idx].Resources = ctr.Resources
pod.Spec.Containers[idx].ResizePolicy = ctr.ResizePolicy
}
return pod
}
func (podResizeStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) {
newPod := obj.(*api.Pod)
oldPod := old.(*api.Pod)
*newPod = *dropNonPodResizeUpdates(newPod, oldPod)
podutil.MarkPodProposedForResize(oldPod, newPod)
podutil.DropDisabledPodFields(newPod, oldPod)
}

View File

@ -2451,3 +2451,331 @@ var _ warning.Recorder = &warningRecorder{}
func (w *warningRecorder) AddWarning(_, text string) {
w.warnings = append(w.warnings, text)
}
func TestDropNonPodResizeUpdates(t *testing.T) {
tests := []struct {
name string
oldPod *api.Pod
newPod *api.Pod
expected *api.Pod
}{
{
name: "no resize",
oldPod: &api.Pod{
Spec: api.PodSpec{
Containers: []api.Container{
{
Name: "container1",
Resources: api.ResourceRequirements{
Requests: api.ResourceList{
api.ResourceCPU: resource.MustParse("1"),
api.ResourceMemory: resource.MustParse("1Gi"),
},
},
},
},
},
},
newPod: &api.Pod{
Spec: api.PodSpec{
Containers: []api.Container{
{
Name: "container1",
Resources: api.ResourceRequirements{
Requests: api.ResourceList{
api.ResourceCPU: resource.MustParse("1"),
api.ResourceMemory: resource.MustParse("1Gi"),
},
},
},
},
},
},
expected: &api.Pod{
Spec: api.PodSpec{
Containers: []api.Container{
{
Name: "container1",
Resources: api.ResourceRequirements{
Requests: api.ResourceList{
api.ResourceCPU: resource.MustParse("1"),
api.ResourceMemory: resource.MustParse("1Gi"),
},
},
},
},
},
},
},
{
name: "update resizepolicy",
oldPod: &api.Pod{
Spec: api.PodSpec{
Containers: []api.Container{
{
Name: "container1",
Resources: api.ResourceRequirements{
Requests: api.ResourceList{
api.ResourceCPU: resource.MustParse("1"),
api.ResourceMemory: resource.MustParse("1Gi"),
},
},
},
},
},
},
newPod: &api.Pod{
Spec: api.PodSpec{
Containers: []api.Container{
{
Name: "container1",
Resources: api.ResourceRequirements{
Requests: api.ResourceList{
api.ResourceCPU: resource.MustParse("2"),
api.ResourceMemory: resource.MustParse("2Gi"),
},
Limits: api.ResourceList{
api.ResourceCPU: resource.MustParse("4"),
api.ResourceMemory: resource.MustParse("4Gi"),
},
},
ResizePolicy: []api.ContainerResizePolicy{
{ResourceName: "cpu", RestartPolicy: "NotRequired"},
{ResourceName: "memory", RestartPolicy: "RestartContainer"},
},
},
},
},
},
expected: &api.Pod{
Spec: api.PodSpec{
Containers: []api.Container{
{
Name: "container1",
Resources: api.ResourceRequirements{
Requests: api.ResourceList{
api.ResourceCPU: resource.MustParse("2"),
api.ResourceMemory: resource.MustParse("2Gi"),
},
Limits: api.ResourceList{
api.ResourceCPU: resource.MustParse("4"),
api.ResourceMemory: resource.MustParse("4Gi"),
},
},
ResizePolicy: []api.ContainerResizePolicy{
{ResourceName: "cpu", RestartPolicy: "NotRequired"},
{ResourceName: "memory", RestartPolicy: "RestartContainer"},
},
},
},
},
},
},
{
name: "add new container",
oldPod: &api.Pod{
Spec: api.PodSpec{
Containers: []api.Container{
{
Name: "container1",
Resources: api.ResourceRequirements{
Requests: api.ResourceList{
api.ResourceCPU: resource.MustParse("1"),
api.ResourceMemory: resource.MustParse("1Gi"),
},
},
},
},
},
},
newPod: &api.Pod{
Spec: api.PodSpec{
Containers: []api.Container{
{
Name: "container1",
Resources: api.ResourceRequirements{
Requests: api.ResourceList{
api.ResourceCPU: resource.MustParse("1"),
api.ResourceMemory: resource.MustParse("1Gi"),
},
},
},
{
Name: "container2",
Resources: api.ResourceRequirements{
Requests: api.ResourceList{
api.ResourceCPU: resource.MustParse("1"),
api.ResourceMemory: resource.MustParse("1Gi"),
},
},
},
},
},
},
expected: &api.Pod{
Spec: api.PodSpec{
Containers: []api.Container{
{
Name: "container1",
Resources: api.ResourceRequirements{
Requests: api.ResourceList{
api.ResourceCPU: resource.MustParse("1"),
api.ResourceMemory: resource.MustParse("1Gi"),
},
},
},
},
},
},
},
{
name: "add new container and update resources of existing container",
oldPod: &api.Pod{
Spec: api.PodSpec{
Containers: []api.Container{
{
Name: "container1",
Resources: api.ResourceRequirements{
Requests: api.ResourceList{
api.ResourceCPU: resource.MustParse("1"),
api.ResourceMemory: resource.MustParse("1Gi"),
},
},
},
},
},
},
newPod: &api.Pod{
Spec: api.PodSpec{
Containers: []api.Container{
{
Name: "container1",
Resources: api.ResourceRequirements{
Requests: api.ResourceList{
api.ResourceCPU: resource.MustParse("1"),
api.ResourceMemory: resource.MustParse("2Gi"),
},
},
},
{
Name: "container2",
Resources: api.ResourceRequirements{
Requests: api.ResourceList{
api.ResourceCPU: resource.MustParse("1"),
api.ResourceMemory: resource.MustParse("1Gi"),
},
},
},
},
},
},
expected: &api.Pod{
Spec: api.PodSpec{
Containers: []api.Container{
{
Name: "container1",
Resources: api.ResourceRequirements{
Requests: api.ResourceList{
api.ResourceCPU: resource.MustParse("1"),
api.ResourceMemory: resource.MustParse("2Gi"),
},
},
},
},
},
},
},
{
name: "change container order and update resources",
oldPod: &api.Pod{
Spec: api.PodSpec{
Containers: []api.Container{
{
Name: "container1",
Resources: api.ResourceRequirements{
Requests: api.ResourceList{
api.ResourceCPU: resource.MustParse("1"),
api.ResourceMemory: resource.MustParse("1Gi"),
},
},
},
{
Name: "container2",
Resources: api.ResourceRequirements{
Requests: api.ResourceList{
api.ResourceCPU: resource.MustParse("1"),
api.ResourceMemory: resource.MustParse("1Gi"),
},
},
},
},
},
},
newPod: &api.Pod{
Spec: api.PodSpec{
Containers: []api.Container{
{
Name: "container2",
Resources: api.ResourceRequirements{
Requests: api.ResourceList{
api.ResourceCPU: resource.MustParse("2"),
api.ResourceMemory: resource.MustParse("2Gi"),
},
},
},
{
Name: "container1",
Resources: api.ResourceRequirements{
Requests: api.ResourceList{
api.ResourceCPU: resource.MustParse("2"),
api.ResourceMemory: resource.MustParse("4Gi"),
},
},
},
},
},
},
expected: &api.Pod{
Spec: api.PodSpec{
Containers: []api.Container{
{
Name: "container1",
Resources: api.ResourceRequirements{
Requests: api.ResourceList{
api.ResourceCPU: resource.MustParse("2"),
api.ResourceMemory: resource.MustParse("4Gi"),
},
},
},
{
Name: "container2",
Resources: api.ResourceRequirements{
Requests: api.ResourceList{
api.ResourceCPU: resource.MustParse("2"),
api.ResourceMemory: resource.MustParse("2Gi"),
},
},
},
},
},
},
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
tc.newPod.Name = "test-pod"
tc.newPod.Namespace = "test-ns"
tc.newPod.ResourceVersion = "123"
tc.newPod.UID = "abc"
tc.expected.Name = "test-pod"
tc.expected.Namespace = "test-ns"
tc.expected.ResourceVersion = "123"
tc.expected.UID = "abc"
got := dropNonPodResizeUpdates(tc.newPod, tc.oldPod)
if !cmp.Equal(tc.expected, got) {
t.Errorf("dropNonPodResizeUpdates() diff = %v", cmp.Diff(tc.expected, got))
}
})
}
}