diff --git a/pkg/api/pod/util.go b/pkg/api/pod/util.go index 2f7cba4c181..11d5dee8b60 100644 --- a/pkg/api/pod/util.go +++ b/pkg/api/pod/util.go @@ -416,6 +416,9 @@ func GetValidationOptionsFromPodSpecAndMeta(podSpec, oldPodSpec *api.PodSpec, po } } } + + // if old spec has used image volume source, we must allow it + opts.AllowImageVolumeSource = opts.AllowImageVolumeSource || hasUsedImageVolumeSourceWithPodSpec(oldPodSpec) } if oldPodMeta != nil && !opts.AllowInvalidPodDeletionCost { // This is an update, so validate only if the existing object was valid. @@ -581,6 +584,19 @@ func hasUsedDownwardAPIFieldPathWithContainer(container *api.Container, fieldPat return false } +func hasUsedImageVolumeSourceWithPodSpec(podSpec *api.PodSpec) bool { + if podSpec == nil { + return false + } + + for _, vol := range podSpec.Volumes { + if vol.Image != nil { + return true + } + } + return false +} + // GetValidationOptionsFromPodTemplate will return pod validation options for specified template. func GetValidationOptionsFromPodTemplate(podTemplate, oldPodTemplate *api.PodTemplateSpec) apivalidation.PodValidationOptions { var newPodSpec, oldPodSpec *api.PodSpec diff --git a/pkg/api/pod/util_test.go b/pkg/api/pod/util_test.go index c94005283a4..610b9c838ad 100644 --- a/pkg/api/pod/util_test.go +++ b/pkg/api/pod/util_test.go @@ -2553,6 +2553,48 @@ func TestValidateAllowNonLocalProjectedTokenPathOption(t *testing.T) { } } +func TestValidateAllowImageVolumeSourceOption(t *testing.T) { + testCases := []struct { + name string + oldPodSpec *api.PodSpec + featureEnabled bool + wantOption bool + }{ + { + name: "CreateFeatureEnabled", + featureEnabled: true, + wantOption: true, + }, + { + name: "CreateFeatureDisabled", + featureEnabled: false, + wantOption: false, + }, + { + name: "UpdateFeatureDisabled", + oldPodSpec: &api.PodSpec{Volumes: []api.Volume{{VolumeSource: api.VolumeSource{Image: &api.ImageVolumeSource{Reference: "image"}}}}}, + featureEnabled: false, + wantOption: true, + }, + { + name: "UpdateFeatureEnabled", + oldPodSpec: &api.PodSpec{Volumes: []api.Volume{{VolumeSource: api.VolumeSource{Image: &api.ImageVolumeSource{Reference: "image"}}}}}, + featureEnabled: true, + wantOption: true, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ImageVolume, tc.featureEnabled) + gotOptions := GetValidationOptionsFromPodSpecAndMeta(nil, tc.oldPodSpec, nil, nil) + if tc.wantOption != gotOptions.AllowImageVolumeSource { + t.Errorf("unexpected diff, want: %v, got: %v", tc.wantOption, gotOptions.AllowImageVolumeSource) + } + }) + } +} + func TestDropInPlacePodVerticalScaling(t *testing.T) { podWithInPlaceVerticalScaling := func() *api.Pod { return &api.Pod{