Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

graduate CSIServiceAccountToken to beta #99298

Merged
merged 1 commit into from Mar 12, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
28 changes: 14 additions & 14 deletions api/openapi-spec/swagger.json

Large diffs are not rendered by default.

18 changes: 16 additions & 2 deletions pkg/apis/storage/types.go
Expand Up @@ -274,6 +274,9 @@ type CSIDriverSpec struct {
// If the CSIDriverRegistry feature gate is enabled and the value is
// specified to false, the attach operation will be skipped.
// Otherwise the attach operation will be called.
//
// This field is immutable.
//
// +optional
AttachRequired *bool

Expand All @@ -282,6 +285,9 @@ type CSIDriverSpec struct {
// Refer to the specific FSGroupPolicy values for additional details.
// This field is alpha-level, and is only honored by servers
// that enable the CSIVolumeFSGroupPolicy feature gate.
//
// This field is immutable.
//
// +optional
FSGroupPolicy *FSGroupPolicy

Expand Down Expand Up @@ -309,6 +315,9 @@ type CSIDriverSpec struct {
// As Kubernetes 1.15 doesn't support this field, drivers can only support one mode when
// deployed on such a cluster and the deployment determines which mode that is, for example
// via a command line parameter of the driver.
//
// This field is immutable.
//
// +optional
PodInfoOnMount *bool

Expand All @@ -324,6 +333,9 @@ type CSIDriverSpec struct {
// https://kubernetes-csi.github.io/docs/ephemeral-local-volumes.html
// A driver can support one or more of these mode and
// more modes may be added in the future.
//
// This field is immutable.
//
// +optional
VolumeLifecycleModes []VolumeLifecycleMode

Expand All @@ -341,6 +353,8 @@ type CSIDriverSpec struct {
// unset or false and it can be flipped later when storage
// capacity information has been published.
//
// This field is immutable.
//
// This is a beta field and only available when the CSIStorageCapacity
// feature is enabled. The default is false.
//
Expand All @@ -363,7 +377,7 @@ type CSIDriverSpec struct {
// most one token is empty string. To receive a new token after expiry,
// RequiresRepublish can be used to trigger NodePublishVolume periodically.
//
// This is an alpha feature and only available when the
zshihang marked this conversation as resolved.
Show resolved Hide resolved
// This is a beta feature and only available when the
// CSIServiceAccountToken feature is enabled.
//
// +optional
Expand All @@ -378,7 +392,7 @@ type CSIDriverSpec struct {
// to NodePublishVolume should only update the contents of the volume. New
// mount points will not be seen by a running container.
//
// This is an alpha feature and only available when the
// This is a beta feature and only available when the
// CSIServiceAccountToken feature is enabled.
//
// +optional
Expand Down
13 changes: 8 additions & 5 deletions pkg/apis/storage/validation/validation.go
Expand Up @@ -425,11 +425,14 @@ func ValidateCSIDriver(csiDriver *storage.CSIDriver) field.ErrorList {
func ValidateCSIDriverUpdate(new, old *storage.CSIDriver) field.ErrorList {
allErrs := apivalidation.ValidateObjectMetaUpdate(&new.ObjectMeta, &old.ObjectMeta, field.NewPath("metadata"))

// Spec is read-only
// If this ever relaxes in the future, make sure to increment the Generation number in PrepareForUpdate
if !apiequality.Semantic.DeepEqual(old.Spec, new.Spec) {
allErrs = append(allErrs, field.Invalid(field.NewPath("spec"), new.Spec, "field is immutable"))
}
// immutable fields should not be mutated.
liggitt marked this conversation as resolved.
Show resolved Hide resolved
allErrs = append(allErrs, apimachineryvalidation.ValidateImmutableField(new.Spec.AttachRequired, old.Spec.AttachRequired, field.NewPath("spec", "attachedRequired"))...)
allErrs = append(allErrs, apimachineryvalidation.ValidateImmutableField(new.Spec.FSGroupPolicy, old.Spec.FSGroupPolicy, field.NewPath("spec", "fsGroupPolicy"))...)
allErrs = append(allErrs, apimachineryvalidation.ValidateImmutableField(new.Spec.PodInfoOnMount, old.Spec.PodInfoOnMount, field.NewPath("spec", "podInfoOnMount"))...)
allErrs = append(allErrs, apimachineryvalidation.ValidateImmutableField(new.Spec.VolumeLifecycleModes, old.Spec.VolumeLifecycleModes, field.NewPath("spec", "volumeLifecycleModes"))...)
allErrs = append(allErrs, apimachineryvalidation.ValidateImmutableField(new.Spec.StorageCapacity, old.Spec.StorageCapacity, field.NewPath("spec", "storageCapacity"))...)

allErrs = append(allErrs, validateTokenRequests(new.Spec.TokenRequests, field.NewPath("spec", "tokenRequests"))...)
return allErrs
}

Expand Down
67 changes: 39 additions & 28 deletions pkg/apis/storage/validation/validation_test.go
Expand Up @@ -1927,11 +1927,11 @@ func TestCSIDriverValidationUpdate(t *testing.T) {
podInfoOnMount := true
storageCapacity := true
notPodInfoOnMount := false
gcp := "gcp"
requiresRepublish := true
notRequiresRepublish := false
notStorageCapacity := false
resourceVersion := "1"
invalidFSGroupPolicy := storage.ReadWriteOnceWithFSTypeFSGroupPolicy
invalidFSGroupPolicy = "invalid-mode"
old := storage.CSIDriver{
ObjectMeta: metav1.ObjectMeta{Name: driverName, ResourceVersion: resourceVersion},
Spec: storage.CSIDriverSpec{
Expand All @@ -1946,30 +1946,35 @@ func TestCSIDriverValidationUpdate(t *testing.T) {
},
}

// Currently we compare the object against itself
// and ensure updates succeed
successCases := []storage.CSIDriver{
old,
// An invalid FSGroupPolicy should still pass
successCases := []struct {
name string
modify func(new *storage.CSIDriver)
}{
{
ObjectMeta: metav1.ObjectMeta{Name: driverName, ResourceVersion: resourceVersion},
Spec: storage.CSIDriverSpec{
AttachRequired: &attachNotRequired,
PodInfoOnMount: &notPodInfoOnMount,
VolumeLifecycleModes: []storage.VolumeLifecycleMode{
storage.VolumeLifecycleEphemeral,
storage.VolumeLifecyclePersistent,
},
FSGroupPolicy: &invalidFSGroupPolicy,
StorageCapacity: &storageCapacity,
name: "no change",
modify: func(new *storage.CSIDriver) {},
},
{
name: "change TokenRequests",
modify: func(new *storage.CSIDriver) {
new.Spec.TokenRequests = []storage.TokenRequest{{Audience: gcp}}
},
},
{
name: "change RequiresRepublish",
modify: func(new *storage.CSIDriver) {
new.Spec.RequiresRepublish = &requiresRepublish
},
},
}
for _, csiDriver := range successCases {
newDriver := csiDriver.DeepCopy()
if errs := ValidateCSIDriverUpdate(&csiDriver, newDriver); len(errs) != 0 {
t.Errorf("expected success for %+v: %v", csiDriver, errs)
}
for _, test := range successCases {
t.Run(test.name, func(t *testing.T) {
new := old.DeepCopy()
test.modify(new)
if errs := ValidateCSIDriverUpdate(new, &old); len(errs) != 0 {
t.Errorf("Expected success for %+v: %v", new, errs)
}
})
}

// Each test case changes exactly one field. None of that is valid.
Expand All @@ -1996,15 +2001,15 @@ func TestCSIDriverValidationUpdate(t *testing.T) {
},
},
{
name: "PodInfoOnMount not set",
name: "AttachRequired changed",
modify: func(new *storage.CSIDriver) {
new.Spec.PodInfoOnMount = nil
new.Spec.AttachRequired = &attachRequired
},
},
{
name: "AttachRequired changed",
name: "PodInfoOnMount not set",
modify: func(new *storage.CSIDriver) {
new.Spec.AttachRequired = &attachRequired
new.Spec.PodInfoOnMount = nil
},
},
{
Expand Down Expand Up @@ -2064,14 +2069,20 @@ func TestCSIDriverValidationUpdate(t *testing.T) {
new.Spec.StorageCapacity = &notStorageCapacity
},
},
{
name: "TokenRequests invalidated",
modify: func(new *storage.CSIDriver) {
new.Spec.TokenRequests = []storage.TokenRequest{{Audience: gcp}, {Audience: gcp}}
},
},
}

for _, test := range errorCases {
t.Run(test.name, func(t *testing.T) {
new := old.DeepCopy()
test.modify(new)
if errs := ValidateCSIDriverUpdate(new, &old); len(errs) == 0 {
t.Errorf("Expected failure for test: %v", new)
t.Errorf("Expected failure for test: %+v", new)
}
})
}
Expand Down Expand Up @@ -2253,7 +2264,7 @@ func TestCSIServiceAccountToken(t *testing.T) {
wantErr: true,
},
{
desc: "invalid - TokenRequests has tokens with ExpirationSeconds less than 10min",
desc: "invalid - TokenRequests has tokens with ExpirationSeconds longer than 1<<32 min",
csiDriver: &storage.CSIDriver{
ObjectMeta: metav1.ObjectMeta{Name: driverName},
Spec: storage.CSIDriverSpec{
Expand Down
3 changes: 2 additions & 1 deletion pkg/features/kube_features.go
Expand Up @@ -656,6 +656,7 @@ const (

// owner: @zshihang
// alpha: v1.20
// beta: v1.21
zshihang marked this conversation as resolved.
Show resolved Hide resolved
//
// Enable kubelet to pass pod's service account token to NodePublishVolume
// call of CSI driver which is mounting volumes for that pod.
Expand Down Expand Up @@ -801,7 +802,7 @@ var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureS
BalanceAttachedNodeVolumes: {Default: false, PreRelease: featuregate.Alpha},
CSIInlineVolume: {Default: true, PreRelease: featuregate.Beta},
CSIStorageCapacity: {Default: true, PreRelease: featuregate.Beta},
CSIServiceAccountToken: {Default: false, PreRelease: featuregate.Alpha},
CSIServiceAccountToken: {Default: true, PreRelease: featuregate.Beta},
GenericEphemeralVolume: {Default: true, PreRelease: featuregate.Beta},
CSIVolumeFSGroupPolicy: {Default: true, PreRelease: featuregate.Beta},
RuntimeClass: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.23
Expand Down
34 changes: 17 additions & 17 deletions pkg/registry/storage/csidriver/strategy.go
Expand Up @@ -19,6 +19,7 @@ package csidriver
import (
"context"

apiequality "k8s.io/apimachinery/pkg/api/equality"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/validation/field"
"k8s.io/apiserver/pkg/storage/names"
Expand Down Expand Up @@ -64,10 +65,7 @@ func (csiDriverStrategy) PrepareForCreate(ctx context.Context, obj runtime.Objec
func (csiDriverStrategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorList {
csiDriver := obj.(*storage.CSIDriver)

errs := validation.ValidateCSIDriver(csiDriver)
errs = append(errs, validation.ValidateCSIDriver(csiDriver)...)

return errs
return validation.ValidateCSIDriver(csiDriver)
liggitt marked this conversation as resolved.
Show resolved Hide resolved
}

// Canonicalize normalizes the object after validation.
Expand All @@ -82,31 +80,33 @@ func (csiDriverStrategy) AllowCreateOnUpdate() bool {
// existing object does not already have that field set. This allows the field to remain when
// downgrading to a version that has the feature disabled.
func (csiDriverStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) {
if old.(*storage.CSIDriver).Spec.StorageCapacity == nil &&
newCSIDriver := obj.(*storage.CSIDriver)
oldCSIDriver := old.(*storage.CSIDriver)

if oldCSIDriver.Spec.StorageCapacity == nil &&
!utilfeature.DefaultFeatureGate.Enabled(features.CSIStorageCapacity) {
newCSIDriver := obj.(*storage.CSIDriver)
newCSIDriver.Spec.StorageCapacity = nil
}
if old.(*storage.CSIDriver).Spec.VolumeLifecycleModes == nil &&
if oldCSIDriver.Spec.VolumeLifecycleModes == nil &&
!utilfeature.DefaultFeatureGate.Enabled(features.CSIInlineVolume) {
newCSIDriver := obj.(*storage.CSIDriver)
newCSIDriver.Spec.VolumeLifecycleModes = nil
}
if old.(*storage.CSIDriver).Spec.FSGroupPolicy == nil &&
if oldCSIDriver.Spec.FSGroupPolicy == nil &&
!utilfeature.DefaultFeatureGate.Enabled(features.CSIVolumeFSGroupPolicy) {
newCSIDriver := obj.(*storage.CSIDriver)
newCSIDriver.Spec.FSGroupPolicy = nil
}
if old.(*storage.CSIDriver).Spec.TokenRequests == nil &&
if oldCSIDriver.Spec.TokenRequests == nil &&
!utilfeature.DefaultFeatureGate.Enabled(features.CSIServiceAccountToken) {
csiDriver := obj.(*storage.CSIDriver)
csiDriver.Spec.TokenRequests = nil
newCSIDriver.Spec.TokenRequests = nil
}

if old.(*storage.CSIDriver).Spec.RequiresRepublish == nil &&
if oldCSIDriver.Spec.RequiresRepublish == nil &&
!utilfeature.DefaultFeatureGate.Enabled(features.CSIServiceAccountToken) {
csiDriver := obj.(*storage.CSIDriver)
csiDriver.Spec.RequiresRepublish = nil
newCSIDriver.Spec.RequiresRepublish = nil
}

// Any changes to the mutable fields increment the generation number.
if !apiequality.Semantic.DeepEqual(oldCSIDriver.Spec.TokenRequests, newCSIDriver.Spec.TokenRequests) || !apiequality.Semantic.DeepEqual(oldCSIDriver.Spec.RequiresRepublish, newCSIDriver.Spec.RequiresRepublish) {
newCSIDriver.Generation = oldCSIDriver.Generation + 1
liggitt marked this conversation as resolved.
Show resolved Hide resolved
}
}

Expand Down
4 changes: 4 additions & 0 deletions pkg/registry/storage/csidriver/strategy_test.go
Expand Up @@ -275,6 +275,7 @@ func TestCSIDriverPrepareForUpdate(t *testing.T) {
wantModes []storage.VolumeLifecycleMode
wantTokenRequests []storage.TokenRequest
wantRequiresRepublish *bool
wantGeneration int64
}{
{
name: "capacity feature enabled, before: none, update: enabled",
Expand Down Expand Up @@ -321,6 +322,7 @@ func TestCSIDriverPrepareForUpdate(t *testing.T) {
update: driverWithServiceAccountTokenGCP,
wantTokenRequests: []storage.TokenRequest{{Audience: gcp}},
wantRequiresRepublish: &enabled,
wantGeneration: 1,
},
{
name: "service account token feature disabled, before: none, update: audience=gcp",
Expand All @@ -335,6 +337,7 @@ func TestCSIDriverPrepareForUpdate(t *testing.T) {
update: driverWithServiceAccountTokenGCP,
wantTokenRequests: []storage.TokenRequest{{Audience: gcp}},
wantRequiresRepublish: &enabled,
wantGeneration: 1,
},
}

Expand All @@ -346,6 +349,7 @@ func TestCSIDriverPrepareForUpdate(t *testing.T) {

csiDriver := test.update.DeepCopy()
Strategy.PrepareForUpdate(ctx, csiDriver, test.old)
require.Equal(t, test.wantGeneration, csiDriver.GetGeneration())
require.Equal(t, test.wantCapacity, csiDriver.Spec.StorageCapacity)
require.Equal(t, test.wantModes, csiDriver.Spec.VolumeLifecycleModes)
require.Equal(t, test.wantTokenRequests, csiDriver.Spec.TokenRequests)
Expand Down
18 changes: 16 additions & 2 deletions staging/src/k8s.io/api/storage/v1/generated.proto

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.