diff --git a/pkg/registry/core/pod/strategy.go b/pkg/registry/core/pod/strategy.go index a596e5f11a9..0586f3994ba 100644 --- a/pkg/registry/core/pod/strategy.go +++ b/pkg/registry/core/pod/strategy.go @@ -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) } diff --git a/pkg/registry/core/pod/strategy_test.go b/pkg/registry/core/pod/strategy_test.go index 9b5e290d2ad..33a44610039 100644 --- a/pkg/registry/core/pod/strategy_test.go +++ b/pkg/registry/core/pod/strategy_test.go @@ -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)) + } + }) + } +}