CSIStorageCapacity: CSIDriver.Spec.StorageCapacity field

This is needed to inform the Kubernetes pod scheduler whether it has
to check CSIStorageCapacity objects for available capacity.
This commit is contained in:
Patrick Ohly 2020-01-21 11:57:55 +01:00
parent 22aeb81e84
commit 1089954fa6
12 changed files with 311 additions and 51 deletions

View File

@ -78,6 +78,10 @@ var Funcs = func(codecs runtimeserializer.CodecFactory) []interface{} {
obj.Spec.PodInfoOnMount = new(bool)
*(obj.Spec.PodInfoOnMount) = false
}
if obj.Spec.StorageCapacity == nil {
obj.Spec.StorageCapacity = new(bool)
*(obj.Spec.StorageCapacity) = false
}
if len(obj.Spec.VolumeLifecycleModes) == 0 {
obj.Spec.VolumeLifecycleModes = []storage.VolumeLifecycleMode{
storage.VolumeLifecyclePersistent,

View File

@ -309,6 +309,26 @@ type CSIDriverSpec struct {
// more modes may be added in the future.
// +optional
VolumeLifecycleModes []VolumeLifecycleMode
// If set to true, storageCapacity indicates that the CSI
// volume driver wants pod scheduling to consider the storage
// capacity that the driver deployment will report by creating
// CSIStorageCapacity objects with capacity information.
//
// The check can be enabled immediately when deploying a driver.
// In that case, provisioning new volumes with late binding
// will pause until the driver deployment has published
// some suitable CSIStorageCapacity object.
//
// Alternatively, the driver can be deployed with the field
// unset or false and it can be flipped later when storage
// capacity information has been published.
//
// This is an alpha field and only available when the CSIStorageCapacity
// feature is enabled. The default is false.
//
// +optional
StorageCapacity *bool
}
// VolumeLifecycleMode specifies how a CSI volume is used in Kubernetes.

View File

@ -49,6 +49,10 @@ func SetDefaults_CSIDriver(obj *storagev1.CSIDriver) {
obj.Spec.PodInfoOnMount = new(bool)
*(obj.Spec.PodInfoOnMount) = false
}
if obj.Spec.StorageCapacity == nil && utilfeature.DefaultFeatureGate.Enabled(features.CSIStorageCapacity) {
obj.Spec.StorageCapacity = new(bool)
*(obj.Spec.StorageCapacity) = false
}
if len(obj.Spec.VolumeLifecycleModes) == 0 && utilfeature.DefaultFeatureGate.Enabled(features.CSIInlineVolume) {
obj.Spec.VolumeLifecycleModes = append(obj.Spec.VolumeLifecycleModes, storagev1.VolumeLifecyclePersistent)
}

View File

@ -22,8 +22,11 @@ import (
storagev1 "k8s.io/api/storage/v1"
"k8s.io/apimachinery/pkg/runtime"
utilfeature "k8s.io/apiserver/pkg/util/feature"
featuregatetesting "k8s.io/component-base/featuregate/testing"
"k8s.io/kubernetes/pkg/api/legacyscheme"
_ "k8s.io/kubernetes/pkg/apis/storage/install"
"k8s.io/kubernetes/pkg/features"
)
func roundTrip(t *testing.T, obj runtime.Object) runtime.Object {
@ -47,6 +50,33 @@ func roundTrip(t *testing.T, obj runtime.Object) runtime.Object {
return obj3
}
func TestSetDefaultStorageCapacityEnabled(t *testing.T) {
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIStorageCapacity, true)()
driver := &storagev1.CSIDriver{}
// field should be defaulted
defaultStorageCapacity := false
output := roundTrip(t, runtime.Object(driver)).(*storagev1.CSIDriver)
outStorageCapacity := output.Spec.StorageCapacity
if outStorageCapacity == nil {
t.Errorf("Expected StorageCapacity to be defaulted to: %+v, got: nil", defaultStorageCapacity)
} else if *outStorageCapacity != defaultStorageCapacity {
t.Errorf("Expected StorageCapacity to be defaulted to: %+v, got: %+v", defaultStorageCapacity, outStorageCapacity)
}
}
func TestSetDefaultStorageCapacityDisabled(t *testing.T) {
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIStorageCapacity, false)()
driver := &storagev1.CSIDriver{}
// field should not be defaulted
output := roundTrip(t, runtime.Object(driver)).(*storagev1.CSIDriver)
outStorageCapacity := output.Spec.StorageCapacity
if outStorageCapacity != nil {
t.Errorf("Expected StorageCapacity to remain nil, got: %+v", outStorageCapacity)
}
}
func TestSetDefaultVolumeBindingMode(t *testing.T) {
class := &storagev1.StorageClass{}

View File

@ -49,6 +49,10 @@ func SetDefaults_CSIDriver(obj *storagev1beta1.CSIDriver) {
obj.Spec.PodInfoOnMount = new(bool)
*(obj.Spec.PodInfoOnMount) = false
}
if obj.Spec.StorageCapacity == nil && utilfeature.DefaultFeatureGate.Enabled(features.CSIStorageCapacity) {
obj.Spec.StorageCapacity = new(bool)
*(obj.Spec.StorageCapacity) = false
}
if len(obj.Spec.VolumeLifecycleModes) == 0 && utilfeature.DefaultFeatureGate.Enabled(features.CSIInlineVolume) {
obj.Spec.VolumeLifecycleModes = append(obj.Spec.VolumeLifecycleModes, storagev1beta1.VolumeLifecyclePersistent)
}

View File

@ -85,6 +85,33 @@ func TestSetDefaultAttachRequired(t *testing.T) {
}
}
func TestSetDefaultStorageCapacityEnabled(t *testing.T) {
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIStorageCapacity, true)()
driver := &storagev1beta1.CSIDriver{}
// field should be defaulted
defaultStorageCapacity := false
output := roundTrip(t, runtime.Object(driver)).(*storagev1beta1.CSIDriver)
outStorageCapacity := output.Spec.StorageCapacity
if outStorageCapacity == nil {
t.Errorf("Expected StorageCapacity to be defaulted to: %+v, got: nil", defaultStorageCapacity)
} else if *outStorageCapacity != defaultStorageCapacity {
t.Errorf("Expected StorageCapacity to be defaulted to: %+v, got: %+v", defaultStorageCapacity, outStorageCapacity)
}
}
func TestSetDefaultStorageCapacityDisabled(t *testing.T) {
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIStorageCapacity, false)()
driver := &storagev1beta1.CSIDriver{}
// field should not be defaulted
output := roundTrip(t, runtime.Object(driver)).(*storagev1beta1.CSIDriver)
outStorageCapacity := output.Spec.StorageCapacity
if outStorageCapacity != nil {
t.Errorf("Expected StorageCapacity to remain nil, got: %+v", outStorageCapacity)
}
}
func TestSetDefaultVolumeLifecycleModesEnabled(t *testing.T) {
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIInlineVolume, true)()
driver := &storagev1beta1.CSIDriver{}

View File

@ -419,6 +419,7 @@ func validateCSIDriverSpec(
allErrs := field.ErrorList{}
allErrs = append(allErrs, validateAttachRequired(spec.AttachRequired, fldPath.Child("attachedRequired"))...)
allErrs = append(allErrs, validatePodInfoOnMount(spec.PodInfoOnMount, fldPath.Child("podInfoOnMount"))...)
allErrs = append(allErrs, validateStorageCapacity(spec.StorageCapacity, fldPath.Child("storageCapacity"))...)
allErrs = append(allErrs, validateVolumeLifecycleModes(spec.VolumeLifecycleModes, fldPath.Child("volumeLifecycleModes"))...)
return allErrs
}
@ -443,6 +444,16 @@ func validatePodInfoOnMount(podInfoOnMount *bool, fldPath *field.Path) field.Err
return allErrs
}
// validateStorageCapacity tests if storageCapacity is set for CSIDriver.
func validateStorageCapacity(storageCapacity *bool, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
if storageCapacity == nil && utilfeature.DefaultFeatureGate.Enabled(features.CSIStorageCapacity) {
allErrs = append(allErrs, field.Required(fldPath, ""))
}
return allErrs
}
// validateVolumeLifecycleModes tests if mode has one of the allowed values.
func validateVolumeLifecycleModes(modes []storage.VolumeLifecycleMode, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{}

View File

@ -46,6 +46,7 @@ import (
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/duration"
"k8s.io/apimachinery/pkg/util/sets"
utilfeature "k8s.io/apiserver/pkg/util/feature"
"k8s.io/kubernetes/pkg/apis/admissionregistration"
"k8s.io/kubernetes/pkg/apis/apps"
"k8s.io/kubernetes/pkg/apis/autoscaling"
@ -64,6 +65,7 @@ import (
"k8s.io/kubernetes/pkg/apis/scheduling"
"k8s.io/kubernetes/pkg/apis/storage"
storageutil "k8s.io/kubernetes/pkg/apis/storage/util"
"k8s.io/kubernetes/pkg/features"
"k8s.io/kubernetes/pkg/printers"
"k8s.io/kubernetes/pkg/util/node"
)
@ -510,9 +512,16 @@ func AddHandlers(h printers.PrintHandler) {
{Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
{Name: "AttachRequired", Type: "boolean", Description: storagev1.CSIDriverSpec{}.SwaggerDoc()["attachRequired"]},
{Name: "PodInfoOnMount", Type: "boolean", Description: storagev1.CSIDriverSpec{}.SwaggerDoc()["podInfoOnMount"]},
}
if utilfeature.DefaultFeatureGate.Enabled(features.CSIStorageCapacity) {
csiDriverColumnDefinitions = append(csiDriverColumnDefinitions, metav1.TableColumnDefinition{
Name: "StorageCapacity", Type: "boolean", Description: storagev1.CSIDriverSpec{}.SwaggerDoc()["storageCapacity"],
})
}
csiDriverColumnDefinitions = append(csiDriverColumnDefinitions, []metav1.TableColumnDefinition{
{Name: "Modes", Type: "string", Description: storagev1.CSIDriverSpec{}.SwaggerDoc()["volumeLifecycleModes"]},
{Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
}
}...)
h.TableHandler(csiDriverColumnDefinitions, printCSIDriver)
h.TableHandler(csiDriverColumnDefinitions, printCSIDriverList)
@ -1366,7 +1375,15 @@ func printCSIDriver(obj *storage.CSIDriver, options printers.GenerateOptions) ([
modes = "<none>"
}
row.Cells = append(row.Cells, obj.Name, attachRequired, podInfoOnMount, modes, translateTimestampSince(obj.CreationTimestamp))
row.Cells = append(row.Cells, obj.Name, attachRequired, podInfoOnMount)
if utilfeature.DefaultFeatureGate.Enabled(features.CSIStorageCapacity) {
storageCapacity := false
if obj.Spec.StorageCapacity != nil {
storageCapacity = *obj.Spec.StorageCapacity
}
row.Cells = append(row.Cells, storageCapacity)
}
row.Cells = append(row.Cells, modes, translateTimestampSince(obj.CreationTimestamp))
return []metav1.TableRow{row}, nil
}

View File

@ -43,8 +43,12 @@ func (csiDriverStrategy) NamespaceScoped() bool {
return false
}
// PrepareForCreate clears the VolumeLifecycleModes field if the corresponding feature is disabled.
// PrepareForCreate clears the fields for which the corresponding feature is disabled.
func (csiDriverStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object) {
if !utilfeature.DefaultFeatureGate.Enabled(features.CSIStorageCapacity) {
csiDriver := obj.(*storage.CSIDriver)
csiDriver.Spec.StorageCapacity = nil
}
if !utilfeature.DefaultFeatureGate.Enabled(features.CSIInlineVolume) {
csiDriver := obj.(*storage.CSIDriver)
csiDriver.Spec.VolumeLifecycleModes = nil
@ -68,10 +72,15 @@ func (csiDriverStrategy) AllowCreateOnUpdate() bool {
return false
}
// PrepareForUpdate clears the VolumeLifecycleModes field if the corresponding feature is disabled and
// PrepareForUpdate clears the fields for which the corresponding feature is disabled and
// 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 &&
!utilfeature.DefaultFeatureGate.Enabled(features.CSIStorageCapacity) {
newCSIDriver := obj.(*storage.CSIDriver)
newCSIDriver.Spec.StorageCapacity = nil
}
if old.(*storage.CSIDriver).Spec.VolumeLifecycleModes == nil &&
!utilfeature.DefaultFeatureGate.Enabled(features.CSIInlineVolume) {
newCSIDriver := obj.(*storage.CSIDriver)

View File

@ -30,15 +30,15 @@ import (
)
func getValidCSIDriver(name string) *storage.CSIDriver {
attachRequired := true
podInfoOnMount := true
enabled := true
return &storage.CSIDriver{
ObjectMeta: metav1.ObjectMeta{
Name: name,
},
Spec: storage.CSIDriverSpec{
AttachRequired: &attachRequired,
PodInfoOnMount: &podInfoOnMount,
AttachRequired: &enabled,
PodInfoOnMount: &enabled,
StorageCapacity: &enabled,
},
}
}
@ -87,22 +87,12 @@ func TestCSIDriverPrepareForCreate(t *testing.T) {
attachRequired := true
podInfoOnMount := true
csiDriver := &storage.CSIDriver{
ObjectMeta: metav1.ObjectMeta{
Name: "foo",
},
Spec: storage.CSIDriverSpec{
AttachRequired: &attachRequired,
PodInfoOnMount: &podInfoOnMount,
VolumeLifecycleModes: []storage.VolumeLifecycleMode{
storage.VolumeLifecyclePersistent,
},
},
}
storageCapacity := true
tests := []struct {
name string
withInline bool
name string
withCapacity bool
withInline bool
}{
{
name: "inline enabled",
@ -112,17 +102,48 @@ func TestCSIDriverPrepareForCreate(t *testing.T) {
name: "inline disabled",
withInline: false,
},
{
name: "capacity enabled",
withCapacity: true,
},
{
name: "capacity disabled",
withCapacity: false,
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIStorageCapacity, test.withCapacity)()
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIInlineVolume, test.withInline)()
csiDriver := &storage.CSIDriver{
ObjectMeta: metav1.ObjectMeta{
Name: "foo",
},
Spec: storage.CSIDriverSpec{
AttachRequired: &attachRequired,
PodInfoOnMount: &podInfoOnMount,
StorageCapacity: &storageCapacity,
VolumeLifecycleModes: []storage.VolumeLifecycleMode{
storage.VolumeLifecyclePersistent,
},
},
}
Strategy.PrepareForCreate(ctx, csiDriver)
errs := Strategy.Validate(ctx, csiDriver)
if len(errs) != 0 {
t.Errorf("unexpected validating errors: %v", errs)
}
if test.withCapacity {
if csiDriver.Spec.StorageCapacity == nil || *csiDriver.Spec.StorageCapacity != storageCapacity {
t.Errorf("StorageCapacity modified: %v", csiDriver.Spec.StorageCapacity)
}
} else {
if csiDriver.Spec.StorageCapacity != nil {
t.Errorf("StorageCapacity not stripped: %v", csiDriver.Spec.StorageCapacity)
}
}
if test.withInline {
if len(csiDriver.Spec.VolumeLifecycleModes) != 1 {
t.Errorf("VolumeLifecycleModes modified: %v", csiDriver.Spec)
@ -178,15 +199,69 @@ func TestCSIDriverPrepareForUpdate(t *testing.T) {
},
},
}
enabled := true
disabled := false
driverWithoutCapacity := &storage.CSIDriver{
ObjectMeta: metav1.ObjectMeta{
Name: "foo",
},
}
driverWithCapacityEnabled := &storage.CSIDriver{
ObjectMeta: metav1.ObjectMeta{
Name: "foo",
},
Spec: storage.CSIDriverSpec{
StorageCapacity: &enabled,
},
}
driverWithCapacityDisabled := &storage.CSIDriver{
ObjectMeta: metav1.ObjectMeta{
Name: "foo",
},
Spec: storage.CSIDriverSpec{
StorageCapacity: &disabled,
},
}
var resultEmpty []storage.VolumeLifecycleMode
resultPersistent := []storage.VolumeLifecycleMode{storage.VolumeLifecyclePersistent}
resultEphemeral := []storage.VolumeLifecycleMode{storage.VolumeLifecycleEphemeral}
tests := []struct {
name string
old, update *storage.CSIDriver
withInline, withoutInline []storage.VolumeLifecycleMode
name string
old, update *storage.CSIDriver
withCapacity, withoutCapacity *bool
withInline, withoutInline []storage.VolumeLifecycleMode
}{
{
name: "before: no capacity, update: no capacity",
old: driverWithoutCapacity,
update: driverWithoutCapacity,
withCapacity: nil,
withoutCapacity: nil,
},
{
name: "before: no capacity, update: enabled",
old: driverWithoutCapacity,
update: driverWithCapacityEnabled,
withCapacity: &enabled,
withoutCapacity: nil,
},
{
name: "before: capacity enabled, update: disabled",
old: driverWithCapacityEnabled,
update: driverWithCapacityDisabled,
withCapacity: &disabled,
withoutCapacity: &disabled,
},
{
name: "before: capacity enabled, update: no capacity",
old: driverWithCapacityEnabled,
update: driverWithoutCapacity,
withCapacity: nil,
withoutCapacity: nil,
},
{
name: "before: no mode, update: no mode",
old: driverWithoutModes,
@ -217,35 +292,46 @@ func TestCSIDriverPrepareForUpdate(t *testing.T) {
},
}
runAll := func(t *testing.T, withInline bool) {
runAll := func(t *testing.T, withCapacity, withInline bool) {
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIStorageCapacity, withCapacity)()
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIInlineVolume, withInline)()
csiDriver := test.update.DeepCopy()
Strategy.PrepareForUpdate(ctx, csiDriver, test.old)
if withInline {
require.Equal(t, csiDriver.Spec.VolumeLifecycleModes, test.withInline)
if withCapacity {
require.Equal(t, test.withCapacity, csiDriver.Spec.StorageCapacity)
} else {
require.Equal(t, csiDriver.Spec.VolumeLifecycleModes, test.withoutInline)
require.Equal(t, test.withoutCapacity, csiDriver.Spec.StorageCapacity)
}
if withInline {
require.Equal(t, test.withInline, csiDriver.Spec.VolumeLifecycleModes)
} else {
require.Equal(t, test.withoutInline, csiDriver.Spec.VolumeLifecycleModes)
}
})
}
}
t.Run("with capacity", func(t *testing.T) {
runAll(t, true, false)
})
t.Run("without capacity", func(t *testing.T) {
runAll(t, false, false)
})
t.Run("with inline volumes", func(t *testing.T) {
runAll(t, true)
runAll(t, false, true)
})
t.Run("without inline volumes", func(t *testing.T) {
runAll(t, false)
runAll(t, false, false)
})
}
func TestCSIDriverValidation(t *testing.T) {
attachRequired := true
notAttachRequired := false
podInfoOnMount := true
notPodInfoOnMount := false
enabled := true
disabled := true
tests := []struct {
name string
@ -258,27 +344,29 @@ func TestCSIDriverValidation(t *testing.T) {
false,
},
{
"true PodInfoOnMount and AttachRequired",
"true for all flags",
&storage.CSIDriver{
ObjectMeta: metav1.ObjectMeta{
Name: "foo",
},
Spec: storage.CSIDriverSpec{
AttachRequired: &attachRequired,
PodInfoOnMount: &podInfoOnMount,
AttachRequired: &enabled,
PodInfoOnMount: &enabled,
StorageCapacity: &enabled,
},
},
false,
},
{
"false PodInfoOnMount and AttachRequired",
"false for all flags",
&storage.CSIDriver{
ObjectMeta: metav1.ObjectMeta{
Name: "foo",
},
Spec: storage.CSIDriverSpec{
AttachRequired: &notAttachRequired,
PodInfoOnMount: &notPodInfoOnMount,
AttachRequired: &disabled,
PodInfoOnMount: &disabled,
StorageCapacity: &disabled,
},
},
false,
@ -290,8 +378,9 @@ func TestCSIDriverValidation(t *testing.T) {
Name: "*foo#",
},
Spec: storage.CSIDriverSpec{
AttachRequired: &attachRequired,
PodInfoOnMount: &podInfoOnMount,
AttachRequired: &enabled,
PodInfoOnMount: &enabled,
StorageCapacity: &enabled,
},
},
true,
@ -303,8 +392,9 @@ func TestCSIDriverValidation(t *testing.T) {
Name: "foo",
},
Spec: storage.CSIDriverSpec{
AttachRequired: &attachRequired,
PodInfoOnMount: &podInfoOnMount,
AttachRequired: &enabled,
PodInfoOnMount: &enabled,
StorageCapacity: &enabled,
VolumeLifecycleModes: []storage.VolumeLifecycleMode{
storage.VolumeLifecycleMode("no-such-mode"),
},
@ -319,8 +409,9 @@ func TestCSIDriverValidation(t *testing.T) {
Name: "foo",
},
Spec: storage.CSIDriverSpec{
AttachRequired: &attachRequired,
PodInfoOnMount: &podInfoOnMount,
AttachRequired: &enabled,
PodInfoOnMount: &enabled,
StorageCapacity: &enabled,
VolumeLifecycleModes: []storage.VolumeLifecycleMode{
storage.VolumeLifecyclePersistent,
},
@ -335,8 +426,9 @@ func TestCSIDriverValidation(t *testing.T) {
Name: "foo",
},
Spec: storage.CSIDriverSpec{
AttachRequired: &attachRequired,
PodInfoOnMount: &podInfoOnMount,
AttachRequired: &enabled,
PodInfoOnMount: &enabled,
StorageCapacity: &enabled,
VolumeLifecycleModes: []storage.VolumeLifecycleMode{
storage.VolumeLifecycleEphemeral,
},
@ -351,8 +443,9 @@ func TestCSIDriverValidation(t *testing.T) {
Name: "foo",
},
Spec: storage.CSIDriverSpec{
AttachRequired: &attachRequired,
PodInfoOnMount: &podInfoOnMount,
AttachRequired: &enabled,
PodInfoOnMount: &enabled,
StorageCapacity: &enabled,
VolumeLifecycleModes: []storage.VolumeLifecycleMode{
storage.VolumeLifecyclePersistent,
storage.VolumeLifecycleEphemeral,

View File

@ -316,6 +316,26 @@ type CSIDriverSpec struct {
// +optional
// +listType=set
VolumeLifecycleModes []VolumeLifecycleMode `json:"volumeLifecycleModes,omitempty" protobuf:"bytes,3,opt,name=volumeLifecycleModes"`
// If set to true, storageCapacity indicates that the CSI
// volume driver wants pod scheduling to consider the storage
// capacity that the driver deployment will report by creating
// CSIStorageCapacity objects with capacity information.
//
// The check can be enabled immediately when deploying a driver.
// In that case, provisioning new volumes with late binding
// will pause until the driver deployment has published
// some suitable CSIStorageCapacity object.
//
// Alternatively, the driver can be deployed with the field
// unset or false and it can be flipped later when storage
// capacity information has been published.
//
// This is an alpha field and only available when the CSIStorageCapacity
// feature is enabled. The default is false.
//
// +optional
StorageCapacity *bool `json:"storageCapacity,omitempty" protobuf:"bytes,4,opt,name=storageCapacity"`
}
// VolumeLifecycleMode is an enumeration of possible usage modes for a volume

View File

@ -335,6 +335,27 @@ type CSIDriverSpec struct {
// more modes may be added in the future.
// +optional
VolumeLifecycleModes []VolumeLifecycleMode `json:"volumeLifecycleModes,omitempty" protobuf:"bytes,3,opt,name=volumeLifecycleModes"`
// If set to true, storageCapacity indicates that the CSI
// volume driver wants pod scheduling to consider the storage
// capacity that the driver deployment will report by creating
// CSIStorageCapacity objects with capacity information.
//
//
// The check can be enabled immediately when deploying a driver.
// In that case, provisioning new volumes with late binding
// will pause until the driver deployment has published
// some suitable CSIStorageCapacity object.
//
// Alternatively, the driver can be deployed with the field
// unset or false and it can be flipped later when storage
// capacity information has been published.
//
// This is an alpha field and only available when the CSIStorageCapacity
// feature is enabled. The default is false.
//
// +optional
StorageCapacity *bool `json:"storageCapacity,omitempty" protobuf:"bytes,4,opt,name=storageCapacity"`
}
// VolumeLifecycleMode is an enumeration of possible usage modes for a volume