Skip to content

Commit 46b3d9b

Browse files
authoredNov 8, 2024
Merge pull request kubernetes#128186 from sreeram-venkitesh/117767-in-place-pod-vertical-scaling-version-skew
Updated version skew strategy for InPlacePodVerticalScaling
2 parents 4d10ae8 + 851dbf2 commit 46b3d9b

File tree

2 files changed

+89
-0
lines changed

2 files changed

+89
-0
lines changed
 

‎pkg/apis/core/validation/validation.go

+21
Original file line numberDiff line numberDiff line change
@@ -5503,6 +5503,10 @@ func ValidatePodResize(newPod, oldPod *core.Pod, opts PodValidationOptions) fiel
55035503
allErrs = append(allErrs, field.Invalid(specPath, newPod.Status.QOSClass, "Pod QOS Class may not change as a result of resizing"))
55045504
}
55055505

5506+
if !isPodResizeRequestSupported(*oldPod) {
5507+
allErrs = append(allErrs, field.Forbidden(specPath, "Pod running on node without support for resize"))
5508+
}
5509+
55065510
// Ensure that only CPU and memory resources are mutable.
55075511
originalCPUMemPodSpec := *newPod.Spec.DeepCopy()
55085512
var newContainers []core.Container
@@ -5543,6 +5547,23 @@ func ValidatePodResize(newPod, oldPod *core.Pod, opts PodValidationOptions) fiel
55435547
return allErrs
55445548
}
55455549

5550+
// isPodResizeRequestSupported checks whether the pod is running on a node with InPlacePodVerticalScaling enabled.
5551+
func isPodResizeRequestSupported(pod core.Pod) bool {
5552+
// TODO: Remove this after GA+3 releases of InPlacePodVerticalScaling
5553+
// This code handles the version skew as described in the KEP.
5554+
// For handling version skew we're only allowing to update the Pod's Resources
5555+
// if the Pod already has Pod.Status.ContainerStatuses[i].Resources. This means
5556+
// that the apiserver would only allow updates to Pods running on Nodes with
5557+
// the InPlacePodVerticalScaling feature gate enabled.
5558+
for _, c := range pod.Status.ContainerStatuses {
5559+
if c.State.Running != nil {
5560+
return c.Resources != nil
5561+
}
5562+
}
5563+
// No running containers. We cannot tell whether the node supports resize at this point, so we assume it does.
5564+
return true
5565+
}
5566+
55465567
// ValidatePodBinding tests if required fields in the pod binding are legal.
55475568
func ValidatePodBinding(binding *core.Binding) field.ErrorList {
55485569
allErrs := field.ErrorList{}

‎pkg/apis/core/validation/validation_test.go

+68
Original file line numberDiff line numberDiff line change
@@ -25203,6 +25203,74 @@ func TestValidatePodResize(t *testing.T) {
2520325203
new: mkPod(core.ResourceList{}, getResources("200m", "0", "1Gi", ""), podtest.SetOS(core.Windows)),
2520425204
err: "Forbidden: windows pods cannot be resized",
2520525205
},
25206+
{
25207+
test: "Pod with nil Resource field in Status",
25208+
old: mkPod(core.ResourceList{}, getResources("100m", "0", "1Gi", ""), podtest.SetStatus(core.PodStatus{
25209+
ContainerStatuses: []core.ContainerStatus{{
25210+
ContainerID: "docker://numbers",
25211+
Image: "nginx:alpine",
25212+
Name: "main",
25213+
Ready: true,
25214+
Started: proto.Bool(true),
25215+
Resources: nil,
25216+
State: core.ContainerState{
25217+
Running: &core.ContainerStateRunning{
25218+
StartedAt: metav1.NewTime(time.Now()),
25219+
},
25220+
},
25221+
}},
25222+
})),
25223+
new: mkPod(core.ResourceList{}, getResources("200m", "0", "1Gi", "")),
25224+
err: "Forbidden: Pod running on node without support for resize",
25225+
},
25226+
{
25227+
test: "Pod with non-nil Resources field in Status",
25228+
old: mkPod(core.ResourceList{}, getResources("100m", "0", "1Gi", ""), podtest.SetStatus(core.PodStatus{
25229+
ContainerStatuses: []core.ContainerStatus{{
25230+
ContainerID: "docker://numbers",
25231+
Image: "nginx:alpine",
25232+
Name: "main",
25233+
Ready: true,
25234+
Started: proto.Bool(true),
25235+
Resources: &core.ResourceRequirements{},
25236+
State: core.ContainerState{
25237+
Running: &core.ContainerStateRunning{
25238+
StartedAt: metav1.NewTime(time.Now()),
25239+
},
25240+
},
25241+
}},
25242+
})),
25243+
new: mkPod(core.ResourceList{}, getResources("200m", "0", "1Gi", "")),
25244+
err: "",
25245+
},
25246+
{
25247+
test: "Pod without running containers",
25248+
old: mkPod(core.ResourceList{}, getResources("100m", "0", "1Gi", ""), podtest.SetStatus(core.PodStatus{
25249+
ContainerStatuses: []core.ContainerStatus{},
25250+
})),
25251+
new: mkPod(core.ResourceList{}, getResources("200m", "0", "1Gi", "")),
25252+
err: "",
25253+
},
25254+
{
25255+
test: "Pod with containers which are not running yet",
25256+
old: mkPod(core.ResourceList{}, getResources("100m", "0", "1Gi", ""), podtest.SetStatus(core.PodStatus{
25257+
ContainerStatuses: []core.ContainerStatus{{
25258+
ContainerID: "docker://numbers",
25259+
Image: "nginx:alpine",
25260+
Name: "main",
25261+
Ready: true,
25262+
Started: proto.Bool(true),
25263+
Resources: &core.ResourceRequirements{},
25264+
State: core.ContainerState{
25265+
Waiting: &core.ContainerStateWaiting{
25266+
Reason: "PodInitializing",
25267+
},
25268+
},
25269+
}},
25270+
})),
25271+
new: mkPod(core.ResourceList{}, getResources("200m", "0", "1Gi", "")),
25272+
err: "",
25273+
},
2520625274
}
2520725275

2520825276
for _, test := range tests {

0 commit comments

Comments
 (0)
Please sign in to comment.