mirror of
https://github.com/k3s-io/kubernetes.git
synced 2026-01-06 07:57:35 +00:00
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:
@@ -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,
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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{}
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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{}
|
||||
|
||||
@@ -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{}
|
||||
|
||||
Reference in New Issue
Block a user