mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-24 12:15:52 +00:00
Merge pull request #88636 from NetApp/generic-datasource
Add generic DataSource feature gate
This commit is contained in:
commit
59c6d339cd
2
api/openapi-spec/swagger.json
generated
2
api/openapi-spec/swagger.json
generated
@ -7832,7 +7832,7 @@
|
||||
},
|
||||
"dataSource": {
|
||||
"$ref": "#/definitions/io.k8s.api.core.v1.TypedLocalObjectReference",
|
||||
"description": "This field can be used to specify either: * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot - Beta) * An existing PVC (PersistentVolumeClaim) In order to use VolumeSnapshot object types, the appropriate feature gate must be enabled (VolumeSnapshotDataSource) If the provisioner can support the specified data source, it will create a new volume based on the contents of the specified PVC or Snapshot. If the provisioner does not support the specified data source, the volume will not be created and the failure will be reported as an event. In the future, we plan to support more data source types and the behavior of the provisioner may change."
|
||||
"description": "This field can be used to specify either: * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot - Beta) * An existing PVC (PersistentVolumeClaim) * An existing custom resource/object that implements data population (Alpha) In order to use VolumeSnapshot object types, the appropriate feature gate must be enabled (VolumeSnapshotDataSource or AnyVolumeDataSource) If the provisioner or an external controller can support the specified data source, it will create a new volume based on the contents of the specified data source. If the specified data source is not supported, the volume will not be created and the failure will be reported as an event. In the future, we plan to support more data source types and the behavior of the provisioner may change."
|
||||
},
|
||||
"resources": {
|
||||
"$ref": "#/definitions/io.k8s.api.core.v1.ResourceRequirements",
|
||||
|
@ -47,6 +47,10 @@ func dataSourceInUse(oldPVCSpec *core.PersistentVolumeClaimSpec) bool {
|
||||
|
||||
func dataSourceIsEnabled(pvcSpec *core.PersistentVolumeClaimSpec) bool {
|
||||
if pvcSpec.DataSource != nil {
|
||||
if utilfeature.DefaultFeatureGate.Enabled(features.AnyVolumeDataSource) {
|
||||
return true
|
||||
}
|
||||
|
||||
apiGroup := ""
|
||||
if pvcSpec.DataSource.APIGroup != nil {
|
||||
apiGroup = *pvcSpec.DataSource.APIGroup
|
||||
|
@ -71,6 +71,9 @@ func TestDropDisabledSnapshotDataSource(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
// Ensure that any data sources aren't enabled for this test
|
||||
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.AnyVolumeDataSource, false)()
|
||||
|
||||
for _, enabled := range []bool{true, false} {
|
||||
for _, oldpvcInfo := range pvcInfo {
|
||||
for _, newpvcInfo := range pvcInfo {
|
||||
@ -169,6 +172,9 @@ func TestPVCDataSourceSpecFilter(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
// Ensure that any data sources aren't enabled for this test
|
||||
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.AnyVolumeDataSource, false)()
|
||||
|
||||
for testName, test := range tests {
|
||||
t.Run(testName, func(t *testing.T) {
|
||||
DropDisabledFields(&test.spec, nil)
|
||||
@ -181,3 +187,108 @@ func TestPVCDataSourceSpecFilter(t *testing.T) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// TestAnyDataSourceFilter checks to ensure the AnyVolumeDataSource feature gate works
|
||||
func TestAnyDataSourceFilter(t *testing.T) {
|
||||
makeDataSource := func(apiGroup, kind, name string) *core.TypedLocalObjectReference {
|
||||
return &core.TypedLocalObjectReference{
|
||||
APIGroup: &apiGroup,
|
||||
Kind: kind,
|
||||
Name: name,
|
||||
}
|
||||
}
|
||||
|
||||
volumeDataSource := makeDataSource("", "PersistentVolumeClaim", "my-vol")
|
||||
snapshotDataSource := makeDataSource("snapshot.storage.k8s.io", "VolumeSnapshot", "my-snap")
|
||||
genericDataSource := makeDataSource("generic.storage.k8s.io", "Generic", "my-foo")
|
||||
|
||||
var tests = map[string]struct {
|
||||
spec core.PersistentVolumeClaimSpec
|
||||
snapshotEnabled bool
|
||||
anyEnabled bool
|
||||
want *core.TypedLocalObjectReference
|
||||
}{
|
||||
"both disabled with empty ds": {
|
||||
spec: core.PersistentVolumeClaimSpec{},
|
||||
want: nil,
|
||||
},
|
||||
"both disabled with volume ds": {
|
||||
spec: core.PersistentVolumeClaimSpec{DataSource: volumeDataSource},
|
||||
want: volumeDataSource,
|
||||
},
|
||||
"both disabled with snapshot ds": {
|
||||
spec: core.PersistentVolumeClaimSpec{DataSource: snapshotDataSource},
|
||||
want: nil,
|
||||
},
|
||||
"both disabled with generic ds": {
|
||||
spec: core.PersistentVolumeClaimSpec{DataSource: genericDataSource},
|
||||
want: nil,
|
||||
},
|
||||
"any enabled with empty ds": {
|
||||
spec: core.PersistentVolumeClaimSpec{},
|
||||
anyEnabled: true,
|
||||
want: nil,
|
||||
},
|
||||
"any enabled with volume ds": {
|
||||
spec: core.PersistentVolumeClaimSpec{DataSource: volumeDataSource},
|
||||
anyEnabled: true,
|
||||
want: volumeDataSource,
|
||||
},
|
||||
"any enabled with snapshot ds": {
|
||||
spec: core.PersistentVolumeClaimSpec{DataSource: snapshotDataSource},
|
||||
anyEnabled: true,
|
||||
want: snapshotDataSource,
|
||||
},
|
||||
"any enabled with generic ds": {
|
||||
spec: core.PersistentVolumeClaimSpec{DataSource: genericDataSource},
|
||||
anyEnabled: true,
|
||||
want: genericDataSource,
|
||||
},
|
||||
"snapshot enabled with snapshot ds": {
|
||||
spec: core.PersistentVolumeClaimSpec{DataSource: snapshotDataSource},
|
||||
snapshotEnabled: true,
|
||||
want: snapshotDataSource,
|
||||
},
|
||||
"snapshot enabled with generic ds": {
|
||||
spec: core.PersistentVolumeClaimSpec{DataSource: genericDataSource},
|
||||
snapshotEnabled: true,
|
||||
want: nil,
|
||||
},
|
||||
"both enabled with empty ds": {
|
||||
spec: core.PersistentVolumeClaimSpec{},
|
||||
snapshotEnabled: true,
|
||||
anyEnabled: true,
|
||||
want: nil,
|
||||
},
|
||||
"both enabled with volume ds": {
|
||||
spec: core.PersistentVolumeClaimSpec{DataSource: volumeDataSource},
|
||||
snapshotEnabled: true,
|
||||
anyEnabled: true,
|
||||
want: volumeDataSource,
|
||||
},
|
||||
"both enabled with snapshot ds": {
|
||||
spec: core.PersistentVolumeClaimSpec{DataSource: snapshotDataSource},
|
||||
snapshotEnabled: true,
|
||||
anyEnabled: true,
|
||||
want: snapshotDataSource,
|
||||
},
|
||||
"both enabled with generic ds": {
|
||||
spec: core.PersistentVolumeClaimSpec{DataSource: genericDataSource},
|
||||
snapshotEnabled: true,
|
||||
anyEnabled: true,
|
||||
want: genericDataSource,
|
||||
},
|
||||
}
|
||||
|
||||
for testName, test := range tests {
|
||||
t.Run(testName, func(t *testing.T) {
|
||||
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.VolumeSnapshotDataSource, test.snapshotEnabled)()
|
||||
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.AnyVolumeDataSource, test.anyEnabled)()
|
||||
DropDisabledFields(&test.spec, nil)
|
||||
if test.spec.DataSource != test.want {
|
||||
t.Errorf("expected condition was not met, test: %s, snapshotEnabled: %v, anyEnabled: %v, spec: %v, expected: %v",
|
||||
testName, test.snapshotEnabled, test.anyEnabled, test.spec, test.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -420,11 +420,12 @@ type PersistentVolumeClaimSpec struct {
|
||||
// This field can be used to specify either:
|
||||
// * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot - Beta)
|
||||
// * An existing PVC (PersistentVolumeClaim)
|
||||
// * An existing custom resource/object that implements data population (Alpha)
|
||||
// In order to use VolumeSnapshot object types, the appropriate feature gate
|
||||
// must be enabled (VolumeSnapshotDataSource)
|
||||
// If the provisioner can support the specified data source, it will create
|
||||
// a new volume based on the contents of the specified PVC or Snapshot.
|
||||
// If the provisioner does not support the specified data source, the volume will
|
||||
// must be enabled (VolumeSnapshotDataSource or AnyVolumeDataSource)
|
||||
// If the provisioner or an external controller can support the specified data source,
|
||||
// it will create a new volume based on the contents of the specified data source.
|
||||
// If the specified data source is not supported, the volume will
|
||||
// not be created and the failure will be reported as an event.
|
||||
// In the future, we plan to support more data source types and the behavior
|
||||
// of the provisioner may change.
|
||||
|
@ -33,7 +33,6 @@ go_library(
|
||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1/validation:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/labels:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/util/diff:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/util/intstr:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library",
|
||||
|
@ -38,7 +38,6 @@ import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
unversionedvalidation "k8s.io/apimachinery/pkg/apis/meta/v1/validation"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/util/diff"
|
||||
"k8s.io/apimachinery/pkg/util/intstr"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
@ -1563,11 +1562,6 @@ var supportedReclaimPolicy = sets.NewString(string(core.PersistentVolumeReclaimD
|
||||
|
||||
var supportedVolumeModes = sets.NewString(string(core.PersistentVolumeBlock), string(core.PersistentVolumeFilesystem))
|
||||
|
||||
var supportedDataSourceAPIGroupKinds = map[schema.GroupKind]bool{
|
||||
{Group: "snapshot.storage.k8s.io", Kind: "VolumeSnapshot"}: true,
|
||||
{Group: "", Kind: "PersistentVolumeClaim"}: true,
|
||||
}
|
||||
|
||||
func ValidatePersistentVolumeSpec(pvSpec *core.PersistentVolumeSpec, pvName string, validateInlinePersistentVolumeSpec bool, fldPath *field.Path) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
|
||||
@ -1929,17 +1923,15 @@ func ValidatePersistentVolumeClaimSpec(spec *core.PersistentVolumeClaimSpec, fld
|
||||
if len(spec.DataSource.Name) == 0 {
|
||||
allErrs = append(allErrs, field.Required(fldPath.Child("dataSource", "name"), ""))
|
||||
}
|
||||
|
||||
groupKind := schema.GroupKind{Group: "", Kind: spec.DataSource.Kind}
|
||||
if len(spec.DataSource.Kind) == 0 {
|
||||
allErrs = append(allErrs, field.Required(fldPath.Child("dataSource", "kind"), ""))
|
||||
}
|
||||
apiGroup := ""
|
||||
if spec.DataSource.APIGroup != nil {
|
||||
groupKind.Group = string(*spec.DataSource.APIGroup)
|
||||
apiGroup = *spec.DataSource.APIGroup
|
||||
}
|
||||
groupKindList := make([]string, 0, len(supportedDataSourceAPIGroupKinds))
|
||||
for grp := range supportedDataSourceAPIGroupKinds {
|
||||
groupKindList = append(groupKindList, grp.String())
|
||||
}
|
||||
if !supportedDataSourceAPIGroupKinds[groupKind] {
|
||||
allErrs = append(allErrs, field.NotSupported(fldPath.Child("dataSource"), groupKind.String(), groupKindList))
|
||||
if len(apiGroup) == 0 && spec.DataSource.Kind != "PersistentVolumeClaim" {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath.Child("dataSource"), spec.DataSource.Kind, ""))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -904,8 +904,7 @@ func TestAlphaVolumeSnapshotDataSource(t *testing.T) {
|
||||
}
|
||||
failedTestCases := []core.PersistentVolumeClaimSpec{
|
||||
*testVolumeSnapshotDataSourceInSpec("", "VolumeSnapshot", "snapshot.storage.k8s.io"),
|
||||
*testVolumeSnapshotDataSourceInSpec("test_snapshot", "PersistentVolumeClaim", "snapshot.storage.k8s.io"),
|
||||
*testVolumeSnapshotDataSourceInSpec("test_snapshot", "VolumeSnapshot", "storage.k8s.io"),
|
||||
*testVolumeSnapshotDataSourceInSpec("test_snapshot", "", "snapshot.storage.k8s.io"),
|
||||
}
|
||||
|
||||
for _, tc := range successTestCases {
|
||||
@ -14864,13 +14863,17 @@ func TestAlphaVolumePVCDataSource(t *testing.T) {
|
||||
expectedFail: true,
|
||||
},
|
||||
{
|
||||
testName: "test specifying pvc with snapshot api group should fail",
|
||||
claimSpec: *testDataSourceInSpec("test_snapshot", "PersistentVolumeClaim", "snapshot.storage.k8s.io"),
|
||||
testName: "test missing kind in snapshot datasource should fail",
|
||||
claimSpec: *testDataSourceInSpec("test_snapshot", "", "snapshot.storage.k8s.io"),
|
||||
expectedFail: true,
|
||||
},
|
||||
{
|
||||
testName: "test invalid group name in snapshot datasource should fail",
|
||||
claimSpec: *testDataSourceInSpec("test_snapshot", "VolumeSnapshot", "storage.k8s.io"),
|
||||
testName: "test create from valid generic custom resource source",
|
||||
claimSpec: *testDataSourceInSpec("test_generic", "Generic", "generic.storage.k8s.io"),
|
||||
},
|
||||
{
|
||||
testName: "test invalid datasource should fail",
|
||||
claimSpec: *testDataSourceInSpec("test_pod", "Pod", ""),
|
||||
expectedFail: true,
|
||||
},
|
||||
}
|
||||
|
@ -564,6 +564,12 @@ const (
|
||||
// e.g. emptyDir:
|
||||
// medium: HugePages-1Gi
|
||||
HugePageStorageMediumSize featuregate.Feature = "HugePageStorageMediumSize"
|
||||
|
||||
// owner: @bswartz
|
||||
// alpha: v1.18
|
||||
//
|
||||
// Enables usage of any object for volume data source in PVCs
|
||||
AnyVolumeDataSource featuregate.Feature = "AnyVolumeDataSource"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@ -652,6 +658,7 @@ var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureS
|
||||
ImmutableEphemeralVolumes: {Default: false, PreRelease: featuregate.Alpha},
|
||||
DefaultIngressClass: {Default: true, PreRelease: featuregate.Beta},
|
||||
HugePageStorageMediumSize: {Default: false, PreRelease: featuregate.Alpha},
|
||||
AnyVolumeDataSource: {Default: false, PreRelease: featuregate.Alpha},
|
||||
|
||||
// inherited features from generic apiserver, relisted here to get a conflict if it is changed
|
||||
// unintentionally on either side:
|
||||
|
@ -2640,11 +2640,12 @@ message PersistentVolumeClaimSpec {
|
||||
// This field can be used to specify either:
|
||||
// * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot - Beta)
|
||||
// * An existing PVC (PersistentVolumeClaim)
|
||||
// * An existing custom resource/object that implements data population (Alpha)
|
||||
// In order to use VolumeSnapshot object types, the appropriate feature gate
|
||||
// must be enabled (VolumeSnapshotDataSource)
|
||||
// If the provisioner can support the specified data source, it will create
|
||||
// a new volume based on the contents of the specified PVC or Snapshot.
|
||||
// If the provisioner does not support the specified data source, the volume will
|
||||
// must be enabled (VolumeSnapshotDataSource or AnyVolumeDataSource)
|
||||
// If the provisioner or an external controller can support the specified data source,
|
||||
// it will create a new volume based on the contents of the specified data source.
|
||||
// If the specified data source is not supported, the volume will
|
||||
// not be created and the failure will be reported as an event.
|
||||
// In the future, we plan to support more data source types and the behavior
|
||||
// of the provisioner may change.
|
||||
|
@ -464,11 +464,12 @@ type PersistentVolumeClaimSpec struct {
|
||||
// This field can be used to specify either:
|
||||
// * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot - Beta)
|
||||
// * An existing PVC (PersistentVolumeClaim)
|
||||
// * An existing custom resource/object that implements data population (Alpha)
|
||||
// In order to use VolumeSnapshot object types, the appropriate feature gate
|
||||
// must be enabled (VolumeSnapshotDataSource)
|
||||
// If the provisioner can support the specified data source, it will create
|
||||
// a new volume based on the contents of the specified PVC or Snapshot.
|
||||
// If the provisioner does not support the specified data source, the volume will
|
||||
// must be enabled (VolumeSnapshotDataSource or AnyVolumeDataSource)
|
||||
// If the provisioner or an external controller can support the specified data source,
|
||||
// it will create a new volume based on the contents of the specified data source.
|
||||
// If the specified data source is not supported, the volume will
|
||||
// not be created and the failure will be reported as an event.
|
||||
// In the future, we plan to support more data source types and the behavior
|
||||
// of the provisioner may change.
|
||||
|
@ -1301,7 +1301,7 @@ var map_PersistentVolumeClaimSpec = map[string]string{
|
||||
"volumeName": "VolumeName is the binding reference to the PersistentVolume backing this claim.",
|
||||
"storageClassName": "Name of the StorageClass required by the claim. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1",
|
||||
"volumeMode": "volumeMode defines what type of volume is required by the claim. Value of Filesystem is implied when not included in claim spec.",
|
||||
"dataSource": "This field can be used to specify either: * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot - Beta) * An existing PVC (PersistentVolumeClaim) In order to use VolumeSnapshot object types, the appropriate feature gate must be enabled (VolumeSnapshotDataSource) If the provisioner can support the specified data source, it will create a new volume based on the contents of the specified PVC or Snapshot. If the provisioner does not support the specified data source, the volume will not be created and the failure will be reported as an event. In the future, we plan to support more data source types and the behavior of the provisioner may change.",
|
||||
"dataSource": "This field can be used to specify either: * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot - Beta) * An existing PVC (PersistentVolumeClaim) * An existing custom resource/object that implements data population (Alpha) In order to use VolumeSnapshot object types, the appropriate feature gate must be enabled (VolumeSnapshotDataSource or AnyVolumeDataSource) If the provisioner or an external controller can support the specified data source, it will create a new volume based on the contents of the specified data source. If the specified data source is not supported, the volume will not be created and the failure will be reported as an event. In the future, we plan to support more data source types and the behavior of the provisioner may change.",
|
||||
}
|
||||
|
||||
func (PersistentVolumeClaimSpec) SwaggerDoc() map[string]string {
|
||||
|
Loading…
Reference in New Issue
Block a user