Skip to content

Commit 6bff3ef

Browse files
committed
VPA: Allow admission-controller to validate in-place spec
Only allow VPA objects with InPlaceOrRecreate update mode to be created if InPlaceOrRecreate feature gate is enabled. If a VPA object already exists with this mode on, and the feature gate is disabled, this prevents further objects to be created with InPlaceOrRecreate, but this does not prevent the existing InPlaceOrRecreate VPA objects with from being modified. Signed-off-by: Max Cao <[email protected]>
1 parent 4486391 commit 6bff3ef

File tree

5 files changed

+58
-7
lines changed

5 files changed

+58
-7
lines changed

vertical-pod-autoscaler/deploy/admission-controller-deployment.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ spec:
2121
containers:
2222
- name: admission-controller
2323
image: registry.k8s.io/autoscaling/vpa-admission-controller:1.3.0
24-
imagePullPolicy: IfNotPresent
24+
imagePullPolicy: Always
2525
env:
2626
- name: NAMESPACE
2727
valueFrom:

vertical-pod-autoscaler/deploy/recommender-deployment.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ spec:
2121
containers:
2222
- name: recommender
2323
image: registry.k8s.io/autoscaling/vpa-recommender:1.3.0
24-
imagePullPolicy: IfNotPresent
24+
imagePullPolicy: Always
2525
resources:
2626
limits:
2727
cpu: 200m

vertical-pod-autoscaler/deploy/updater-deployment.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ spec:
2121
containers:
2222
- name: updater
2323
image: registry.k8s.io/autoscaling/vpa-updater:1.3.0
24-
imagePullPolicy: IfNotPresent
24+
imagePullPolicy: Always
2525
env:
2626
- name: NAMESPACE
2727
valueFrom:

vertical-pod-autoscaler/pkg/admission-controller/resource/vpa/handler.go

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,15 +30,17 @@ import (
3030

3131
"k8s.io/autoscaler/vertical-pod-autoscaler/pkg/admission-controller/resource"
3232
vpa_types "k8s.io/autoscaler/vertical-pod-autoscaler/pkg/apis/autoscaling.k8s.io/v1"
33+
"k8s.io/autoscaler/vertical-pod-autoscaler/pkg/features"
3334
"k8s.io/autoscaler/vertical-pod-autoscaler/pkg/utils/metrics/admission"
3435
)
3536

3637
var (
3738
possibleUpdateModes = map[vpa_types.UpdateMode]interface{}{
38-
vpa_types.UpdateModeOff: struct{}{},
39-
vpa_types.UpdateModeInitial: struct{}{},
40-
vpa_types.UpdateModeRecreate: struct{}{},
41-
vpa_types.UpdateModeAuto: struct{}{},
39+
vpa_types.UpdateModeOff: struct{}{},
40+
vpa_types.UpdateModeInitial: struct{}{},
41+
vpa_types.UpdateModeRecreate: struct{}{},
42+
vpa_types.UpdateModeAuto: struct{}{},
43+
vpa_types.UpdateModeInPlaceOrRecreate: struct{}{},
4244
}
4345

4446
possibleScalingModes = map[vpa_types.ContainerScalingMode]interface{}{
@@ -121,6 +123,9 @@ func ValidateVPA(vpa *vpa_types.VerticalPodAutoscaler, isCreate bool) error {
121123
if _, found := possibleUpdateModes[*mode]; !found {
122124
return fmt.Errorf("unexpected UpdateMode value %s", *mode)
123125
}
126+
if (*mode == vpa_types.UpdateModeInPlaceOrRecreate) && !features.Enabled(features.InPlaceOrRecreate) && isCreate {
127+
return fmt.Errorf("in order to use UpdateMode %s, you must enable feature gate %s in the admission-controller args", vpa_types.UpdateModeInPlaceOrRecreate, features.InPlaceOrRecreate)
128+
}
124129

125130
if minReplicas := vpa.Spec.UpdatePolicy.MinReplicas; minReplicas != nil && *minReplicas <= 0 {
126131
return fmt.Errorf("MinReplicas has to be positive, got %v", *minReplicas)

vertical-pod-autoscaler/pkg/admission-controller/resource/vpa/handler_test.go

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,17 @@ package vpa
1818

1919
import (
2020
"fmt"
21+
"slices"
2122
"testing"
2223

2324
"github.com/stretchr/testify/assert"
2425
apiv1 "k8s.io/api/core/v1"
2526
"k8s.io/apimachinery/pkg/api/resource"
2627

28+
featuregatetesting "k8s.io/component-base/featuregate/testing"
29+
2730
vpa_types "k8s.io/autoscaler/vertical-pod-autoscaler/pkg/apis/autoscaling.k8s.io/v1"
31+
"k8s.io/autoscaler/vertical-pod-autoscaler/pkg/features"
2832
)
2933

3034
const (
@@ -42,6 +46,11 @@ func TestValidateVPA(t *testing.T) {
4246
validScalingMode := vpa_types.ContainerScalingModeAuto
4347
scalingModeOff := vpa_types.ContainerScalingModeOff
4448
controlledValuesRequestsAndLimits := vpa_types.ContainerControlledValuesRequestsAndLimits
49+
inPlaceOrRecreateUpdateMode := vpa_types.UpdateModeInPlaceOrRecreate
50+
inPlaceOrRecreateDisabledTestNames := []string{
51+
"creating VPA with InPlaceOrRecreate update mode not enabled by feature gate",
52+
"updating VPA with InPlaceOrRecreate update mode allowed with disabled feature gate",
53+
}
4554
tests := []struct {
4655
name string
4756
vpa vpa_types.VerticalPodAutoscaler
@@ -78,6 +87,40 @@ func TestValidateVPA(t *testing.T) {
7887
},
7988
expectError: fmt.Errorf("unexpected UpdateMode value bad"),
8089
},
90+
{
91+
name: inPlaceOrRecreateDisabledTestNames[0],
92+
vpa: vpa_types.VerticalPodAutoscaler{
93+
Spec: vpa_types.VerticalPodAutoscalerSpec{
94+
UpdatePolicy: &vpa_types.PodUpdatePolicy{
95+
UpdateMode: &inPlaceOrRecreateUpdateMode,
96+
},
97+
},
98+
},
99+
isCreate: true,
100+
expectError: fmt.Errorf("in order to use UpdateMode %s, you must enable feature gate %s in the admission-controller args", vpa_types.UpdateModeInPlaceOrRecreate, features.InPlaceOrRecreate),
101+
},
102+
{
103+
name: inPlaceOrRecreateDisabledTestNames[1],
104+
vpa: vpa_types.VerticalPodAutoscaler{
105+
Spec: vpa_types.VerticalPodAutoscalerSpec{
106+
UpdatePolicy: &vpa_types.PodUpdatePolicy{
107+
UpdateMode: &inPlaceOrRecreateUpdateMode,
108+
},
109+
},
110+
},
111+
isCreate: false,
112+
expectError: nil,
113+
},
114+
{
115+
name: "InPlaceOrRecreate update mode enabled by feature gate",
116+
vpa: vpa_types.VerticalPodAutoscaler{
117+
Spec: vpa_types.VerticalPodAutoscalerSpec{
118+
UpdatePolicy: &vpa_types.PodUpdatePolicy{
119+
UpdateMode: &inPlaceOrRecreateUpdateMode,
120+
},
121+
},
122+
},
123+
},
81124
{
82125
name: "zero minReplicas",
83126
vpa: vpa_types.VerticalPodAutoscaler{
@@ -282,6 +325,9 @@ func TestValidateVPA(t *testing.T) {
282325
}
283326
for _, tc := range tests {
284327
t.Run(fmt.Sprintf("test case: %s", tc.name), func(t *testing.T) {
328+
if !slices.Contains(inPlaceOrRecreateDisabledTestNames, tc.name) {
329+
featuregatetesting.SetFeatureGateDuringTest(t, features.MutableFeatureGate, features.InPlaceOrRecreate, true)
330+
}
285331
err := ValidateVPA(&tc.vpa, tc.isCreate)
286332
if tc.expectError == nil {
287333
assert.NoError(t, err)

0 commit comments

Comments
 (0)