generic ephemeral volume: graduation to GA
The feature gate gets locked to "true", with the goal to remove it in two releases. All code now can assume that the feature is enabled. Tests for "feature disabled" are no longer needed and get removed. Some code wasn't using the new helper functions yet. That gets changed while touching those lines.
This commit is contained in:
@@ -1133,100 +1133,6 @@ func TestApplySeccompVersionSkew(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestEphemeralVolumeEnablement checks the behavior of the API server
|
||||
// when the GenericEphemeralVolume feature is turned on and then off:
|
||||
// the Ephemeral struct must be preserved even during updates.
|
||||
func TestEphemeralVolumeEnablement(t *testing.T) {
|
||||
// Enable the Feature Gate during the first pod creation
|
||||
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.GenericEphemeralVolume, true)()
|
||||
|
||||
pod := createPodWithGenericEphemeralVolume()
|
||||
expectedPod := pod.DeepCopy()
|
||||
|
||||
Strategy.PrepareForCreate(context.Background(), pod)
|
||||
require.Equal(t, expectedPod.Spec, pod.Spec, "pod spec")
|
||||
|
||||
errs := Strategy.Validate(context.Background(), pod)
|
||||
require.Empty(t, errs, "errors from validation")
|
||||
|
||||
// Now let's disable the Feature Gate, update some other field from the Pod and expect the volume to remain present
|
||||
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.GenericEphemeralVolume, false)()
|
||||
updatePod := testUpdatePod(t, pod, "aaa")
|
||||
|
||||
// And let's enable the FG again, add another from and check if the volume is still present
|
||||
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.GenericEphemeralVolume, true)()
|
||||
testUpdatePod(t, updatePod, "bbb")
|
||||
}
|
||||
|
||||
// TestEphemeralVolumeDisabled checks the behavior of the API server
|
||||
// when the GenericEphemeralVolume is off: the Ephemeral struct gets dropped,
|
||||
// validation fails.
|
||||
func TestEphemeralVolumeDisabled(t *testing.T) {
|
||||
// Disable the Feature Gate during the first pod creation
|
||||
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.GenericEphemeralVolume, false)()
|
||||
|
||||
pod := createPodWithGenericEphemeralVolume()
|
||||
expectedPod := pod.DeepCopy()
|
||||
expectedPod.Spec.Volumes[0].VolumeSource.Ephemeral = nil
|
||||
|
||||
Strategy.PrepareForCreate(context.Background(), pod)
|
||||
require.Equal(t, expectedPod.Spec, pod.Spec, "pod spec")
|
||||
|
||||
errs := Strategy.Validate(context.Background(), pod)
|
||||
require.NotEmpty(t, errs, "no errors from validation")
|
||||
}
|
||||
|
||||
func testUpdatePod(t *testing.T, oldPod *api.Pod, labelValue string) *api.Pod {
|
||||
updatedPod := oldPod.DeepCopy()
|
||||
updatedPod.Labels = map[string]string{"XYZ": labelValue}
|
||||
expectedPod := updatedPod.DeepCopy()
|
||||
Strategy.PrepareForUpdate(context.Background(), updatedPod, oldPod)
|
||||
require.Equal(t, expectedPod.Spec, updatedPod.Spec, "updated pod spec")
|
||||
errs := Strategy.Validate(context.Background(), updatedPod)
|
||||
require.Empty(t, errs, "errors from validation")
|
||||
return updatedPod
|
||||
}
|
||||
|
||||
func createPodWithGenericEphemeralVolume() *api.Pod {
|
||||
return &api.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: "ns",
|
||||
Name: "pod",
|
||||
},
|
||||
Spec: api.PodSpec{
|
||||
RestartPolicy: api.RestartPolicyAlways,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
Containers: []api.Container{{
|
||||
Name: "foo",
|
||||
Image: "example",
|
||||
TerminationMessagePolicy: api.TerminationMessageReadFile,
|
||||
ImagePullPolicy: api.PullAlways,
|
||||
}},
|
||||
Volumes: []api.Volume{
|
||||
{
|
||||
Name: "ephemeral",
|
||||
VolumeSource: api.VolumeSource{
|
||||
Ephemeral: &api.EphemeralVolumeSource{
|
||||
VolumeClaimTemplate: &api.PersistentVolumeClaimTemplate{
|
||||
Spec: api.PersistentVolumeClaimSpec{
|
||||
AccessModes: []api.PersistentVolumeAccessMode{
|
||||
api.ReadWriteOnce,
|
||||
},
|
||||
Resources: api.ResourceRequirements{
|
||||
Requests: api.ResourceList{
|
||||
api.ResourceStorage: resource.MustParse("1Gi"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func newPodtWithHugePageValue(reousreceName api.ResourceName, value resource.Quantity) *api.Pod {
|
||||
return &api.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
|
@@ -23,12 +23,10 @@ import (
|
||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||
"k8s.io/apiserver/pkg/registry/rest"
|
||||
"k8s.io/apiserver/pkg/storage/names"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||
psputil "k8s.io/kubernetes/pkg/api/podsecuritypolicy"
|
||||
"k8s.io/kubernetes/pkg/apis/policy"
|
||||
"k8s.io/kubernetes/pkg/apis/policy/validation"
|
||||
"k8s.io/kubernetes/pkg/features"
|
||||
)
|
||||
|
||||
// strategy implements behavior for PodSecurityPolicy objects
|
||||
@@ -74,10 +72,7 @@ func (strategy) Canonicalize(obj runtime.Object) {
|
||||
}
|
||||
|
||||
func (strategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorList {
|
||||
opts := validation.PodSecurityPolicyValidationOptions{
|
||||
// Only allowed if the feature is enabled.
|
||||
AllowEphemeralVolumeType: utilfeature.DefaultFeatureGate.Enabled(features.GenericEphemeralVolume),
|
||||
}
|
||||
opts := validation.PodSecurityPolicyValidationOptions{}
|
||||
return validation.ValidatePodSecurityPolicy(obj.(*policy.PodSecurityPolicy), opts)
|
||||
}
|
||||
|
||||
@@ -85,12 +80,7 @@ func (strategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorLis
|
||||
func (strategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string { return nil }
|
||||
|
||||
func (strategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList {
|
||||
opts := validation.PodSecurityPolicyValidationOptions{
|
||||
// Allowed if the feature is enabled or the old policy already had it.
|
||||
// A policy that had the type set when that was valid must remain valid.
|
||||
AllowEphemeralVolumeType: utilfeature.DefaultFeatureGate.Enabled(features.GenericEphemeralVolume) ||
|
||||
volumeInUse(old.(*policy.PodSecurityPolicy), policy.Ephemeral),
|
||||
}
|
||||
opts := validation.PodSecurityPolicyValidationOptions{}
|
||||
return validation.ValidatePodSecurityPolicyUpdate(old.(*policy.PodSecurityPolicy), obj.(*policy.PodSecurityPolicy), opts)
|
||||
}
|
||||
|
||||
@@ -98,15 +88,3 @@ func (strategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) fie
|
||||
func (strategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
func volumeInUse(oldPSP *policy.PodSecurityPolicy, volume policy.FSType) bool {
|
||||
if oldPSP == nil {
|
||||
return false
|
||||
}
|
||||
for _, v := range oldPSP.Spec.Volumes {
|
||||
if v == volume {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
@@ -23,10 +23,7 @@ import (
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
featuregatetesting "k8s.io/component-base/featuregate/testing"
|
||||
"k8s.io/kubernetes/pkg/apis/policy"
|
||||
"k8s.io/kubernetes/pkg/features"
|
||||
)
|
||||
|
||||
func TestAllowEphemeralVolumeType(t *testing.T) {
|
||||
@@ -83,35 +80,25 @@ func TestAllowEphemeralVolumeType(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
for _, enabled := range []bool{true, false} {
|
||||
for _, oldPSPInfo := range pspInfo {
|
||||
for _, newPSPInfo := range pspInfo {
|
||||
oldPSP := oldPSPInfo.psp()
|
||||
newPSP := newPSPInfo.psp()
|
||||
if newPSP == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
t.Run(fmt.Sprintf("feature enabled=%v, old PodSecurityPolicySpec %v, new PodSecurityPolicySpec %v", enabled, oldPSPInfo.description, newPSPInfo.description), func(t *testing.T) {
|
||||
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.GenericEphemeralVolume, enabled)()
|
||||
|
||||
var errs field.ErrorList
|
||||
var expectErrors bool
|
||||
if oldPSP == nil {
|
||||
errs = Strategy.Validate(context.Background(), newPSP)
|
||||
expectErrors = newPSPInfo.hasGenericVolume && !enabled
|
||||
} else {
|
||||
errs = Strategy.ValidateUpdate(context.Background(), newPSP, oldPSP)
|
||||
expectErrors = !oldPSPInfo.hasGenericVolume && newPSPInfo.hasGenericVolume && !enabled
|
||||
}
|
||||
if expectErrors && len(errs) == 0 {
|
||||
t.Error("expected errors, got none")
|
||||
}
|
||||
if !expectErrors && len(errs) > 0 {
|
||||
t.Errorf("expected no errors, got: %v", errs)
|
||||
}
|
||||
})
|
||||
for _, oldPSPInfo := range pspInfo {
|
||||
for _, newPSPInfo := range pspInfo {
|
||||
oldPSP := oldPSPInfo.psp()
|
||||
newPSP := newPSPInfo.psp()
|
||||
if newPSP == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
t.Run(fmt.Sprintf("old PodSecurityPolicySpec %v, new PodSecurityPolicySpec %v", oldPSPInfo.description, newPSPInfo.description), func(t *testing.T) {
|
||||
var errs field.ErrorList
|
||||
if oldPSP == nil {
|
||||
errs = Strategy.Validate(context.Background(), newPSP)
|
||||
} else {
|
||||
errs = Strategy.ValidateUpdate(context.Background(), newPSP, oldPSP)
|
||||
}
|
||||
if len(errs) > 0 {
|
||||
t.Errorf("expected no errors, got: %v", errs)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user