Skip to content

Commit 82bfa66

Browse files
authored
Merge pull request kubernetes#76913 from j-griffith/cleaned_enable_pvc_datasource
Cleaned enable pvc datasource
2 parents 7929c15 + 62a4861 commit 82bfa66

File tree

6 files changed

+181
-8
lines changed

6 files changed

+181
-8
lines changed

pkg/api/persistentvolumeclaim/util.go

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,18 @@ import (
2222
"k8s.io/kubernetes/pkg/features"
2323
)
2424

25+
const (
26+
pvc string = "PersistentVolumeClaim"
27+
volumeSnapshot string = "VolumeSnapshot"
28+
)
29+
2530
// DropDisabledFields removes disabled fields from the pvc spec.
2631
// This should be called from PrepareForCreate/PrepareForUpdate for all resources containing a pvc spec.
2732
func DropDisabledFields(pvcSpec, oldPVCSpec *core.PersistentVolumeClaimSpec) {
2833
if !utilfeature.DefaultFeatureGate.Enabled(features.BlockVolume) && !volumeModeInUse(oldPVCSpec) {
2934
pvcSpec.VolumeMode = nil
3035
}
31-
if !utilfeature.DefaultFeatureGate.Enabled(features.VolumeSnapshotDataSource) && !volumeSnapshotDataSourceInUse(oldPVCSpec) {
36+
if !dataSourceIsEnabled(pvcSpec) && !dataSourceInUse(oldPVCSpec) {
3237
pvcSpec.DataSource = nil
3338
}
3439
}
@@ -43,7 +48,7 @@ func volumeModeInUse(oldPVCSpec *core.PersistentVolumeClaimSpec) bool {
4348
return false
4449
}
4550

46-
func volumeSnapshotDataSourceInUse(oldPVCSpec *core.PersistentVolumeClaimSpec) bool {
51+
func dataSourceInUse(oldPVCSpec *core.PersistentVolumeClaimSpec) bool {
4752
if oldPVCSpec == nil {
4853
return false
4954
}
@@ -52,3 +57,20 @@ func volumeSnapshotDataSourceInUse(oldPVCSpec *core.PersistentVolumeClaimSpec) b
5257
}
5358
return false
5459
}
60+
61+
func dataSourceIsEnabled(pvcSpec *core.PersistentVolumeClaimSpec) bool {
62+
if pvcSpec.DataSource != nil {
63+
if pvcSpec.DataSource.Kind == pvc &&
64+
*pvcSpec.DataSource.APIGroup == "" &&
65+
utilfeature.DefaultFeatureGate.Enabled(features.VolumePVCDataSource) {
66+
return true
67+
68+
}
69+
if pvcSpec.DataSource.Kind == volumeSnapshot &&
70+
*pvcSpec.DataSource.APIGroup == "snapshot.storage.k8s.io" &&
71+
utilfeature.DefaultFeatureGate.Enabled(features.VolumeSnapshotDataSource) {
72+
return true
73+
}
74+
}
75+
return false
76+
}

pkg/api/persistentvolumeclaim/util_test.go

Lines changed: 72 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ func TestDropAlphaPVCVolumeMode(t *testing.T) {
118118
}
119119
}
120120

121-
func TestDropDisabledDataSource(t *testing.T) {
121+
func TestDropDisabledSnapshotDataSource(t *testing.T) {
122122
pvcWithoutDataSource := func() *core.PersistentVolumeClaim {
123123
return &core.PersistentVolumeClaim{
124124
Spec: core.PersistentVolumeClaimSpec{
@@ -210,3 +210,74 @@ func TestDropDisabledDataSource(t *testing.T) {
210210
}
211211
}
212212
}
213+
214+
// TestPVCDataSourceSpecFilter checks to ensure the DropDisabledFields function behaves correctly for PVCDataSource featuregate
215+
func TestPVCDataSourceSpecFilter(t *testing.T) {
216+
apiGroup := ""
217+
validSpec := core.PersistentVolumeClaimSpec{
218+
DataSource: &core.TypedLocalObjectReference{
219+
APIGroup: &apiGroup,
220+
Kind: "PersistentVolumeClaim",
221+
Name: "test_clone",
222+
},
223+
}
224+
225+
invalidAPIGroup := "invalid.pvc.api.group"
226+
invalidSpec := core.PersistentVolumeClaimSpec{
227+
DataSource: &core.TypedLocalObjectReference{
228+
APIGroup: &invalidAPIGroup,
229+
Kind: "PersistentVolumeClaim",
230+
Name: "test_clone_invalid",
231+
},
232+
}
233+
234+
var tests = map[string]struct {
235+
spec core.PersistentVolumeClaimSpec
236+
gateEnabled bool
237+
want *core.TypedLocalObjectReference
238+
}{
239+
"enabled with empty ds": {
240+
spec: core.PersistentVolumeClaimSpec{},
241+
gateEnabled: true,
242+
want: nil,
243+
},
244+
"enabled with invalid spec": {
245+
spec: invalidSpec,
246+
gateEnabled: true,
247+
want: nil,
248+
},
249+
"enabled with valid spec": {
250+
spec: validSpec,
251+
gateEnabled: true,
252+
want: validSpec.DataSource,
253+
},
254+
"disabled with invalid spec": {
255+
spec: invalidSpec,
256+
gateEnabled: false,
257+
want: nil,
258+
},
259+
"disabled with valid spec": {
260+
spec: validSpec,
261+
gateEnabled: false,
262+
want: nil,
263+
},
264+
"diabled with empty ds": {
265+
spec: core.PersistentVolumeClaimSpec{},
266+
gateEnabled: false,
267+
want: nil,
268+
},
269+
}
270+
271+
for testName, test := range tests {
272+
t.Run(testName, func(t *testing.T) {
273+
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.VolumePVCDataSource, test.gateEnabled)()
274+
DropDisabledFields(&test.spec, nil)
275+
if test.spec.DataSource != test.want {
276+
t.Errorf("expected drop datasource condition was not met, test: %s, gateEnabled: %v, spec: %v, expected: %v", testName, test.gateEnabled, test.spec, test.want)
277+
}
278+
279+
})
280+
281+
}
282+
283+
}

pkg/apis/core/types.go

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -413,11 +413,14 @@ type PersistentVolumeClaimSpec struct {
413413
// This is a beta feature.
414414
// +optional
415415
VolumeMode *PersistentVolumeMode
416-
// This field requires the VolumeSnapshotDataSource alpha feature gate to be
417-
// enabled and currently VolumeSnapshot is the only supported data source.
418-
// If the provisioner can support VolumeSnapshot data source, it will create
419-
// a new volume and data will be restored to the volume at the same time.
420-
// If the provisioner does not support VolumeSnapshot data source, volume will
416+
// This field can be used to specify either:
417+
// * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot)
418+
// * An existing PVC (PersistentVolumeClaim)
419+
// In order to use either of these DataSource types, the appropriate feature gate
420+
// must be enabled (VolumeSnapshotDataSource, VolumePVCDataSource)
421+
// If the provisioner can support the specified data source, it will create
422+
// a new volume based on the contents of the specified PVC or Snapshot.
423+
// If the provisioner does not support the specified data source, the volume will
421424
// not be created and the failure will be reported as an event.
422425
// In the future, we plan to support more data source types and the behavior
423426
// of the provisioner may change.

pkg/apis/core/validation/validation.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1537,6 +1537,7 @@ var supportedVolumeModes = sets.NewString(string(core.PersistentVolumeBlock), st
15371537

15381538
var supportedDataSourceAPIGroupKinds = map[schema.GroupKind]bool{
15391539
{Group: "snapshot.storage.k8s.io", Kind: "VolumeSnapshot"}: true,
1540+
{Group: "", Kind: "PersistentVolumeClaim"}: true,
15401541
}
15411542

15421543
func ValidatePersistentVolume(pv *core.PersistentVolume) field.ErrorList {

pkg/apis/core/validation/validation_test.go

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13288,3 +13288,72 @@ func TestValidateWindowsSecurityContextOptions(t *testing.T) {
1328813288
})
1328913289
}
1329013290
}
13291+
13292+
func testDataSourceInSpec(name string, kind string, apiGroup string) *core.PersistentVolumeClaimSpec {
13293+
scName := "csi-plugin"
13294+
dataSourceInSpec := core.PersistentVolumeClaimSpec{
13295+
AccessModes: []core.PersistentVolumeAccessMode{
13296+
core.ReadOnlyMany,
13297+
},
13298+
Resources: core.ResourceRequirements{
13299+
Requests: core.ResourceList{
13300+
core.ResourceName(core.ResourceStorage): resource.MustParse("10G"),
13301+
},
13302+
},
13303+
StorageClassName: &scName,
13304+
DataSource: &core.TypedLocalObjectReference{
13305+
APIGroup: &apiGroup,
13306+
Kind: kind,
13307+
Name: name,
13308+
},
13309+
}
13310+
13311+
return &dataSourceInSpec
13312+
}
13313+
13314+
func TestAlphaVolumePVCDataSource(t *testing.T) {
13315+
13316+
testCases := []struct {
13317+
testName string
13318+
claimSpec core.PersistentVolumeClaimSpec
13319+
expectedFail bool
13320+
}{
13321+
{
13322+
testName: "test create from valid snapshot source",
13323+
claimSpec: *testDataSourceInSpec("test_snapshot", "VolumeSnapshot", "snapshot.storage.k8s.io"),
13324+
},
13325+
{
13326+
testName: "test create from valid pvc source",
13327+
claimSpec: *testDataSourceInSpec("test_pvc", "PersistentVolumeClaim", ""),
13328+
},
13329+
{
13330+
testName: "test missing name in snapshot datasource should fail",
13331+
claimSpec: *testDataSourceInSpec("", "VolumeSnapshot", "snapshot.storage.k8s.io"),
13332+
expectedFail: true,
13333+
},
13334+
{
13335+
testName: "test specifying pvc with snapshot api group should fail",
13336+
claimSpec: *testDataSourceInSpec("test_snapshot", "PersistentVolumeClaim", "snapshot.storage.k8s.io"),
13337+
expectedFail: true,
13338+
},
13339+
{
13340+
testName: "test invalid group name in snapshot datasource should fail",
13341+
claimSpec: *testDataSourceInSpec("test_snapshot", "VolumeSnapshot", "storage.k8s.io"),
13342+
expectedFail: true,
13343+
},
13344+
}
13345+
13346+
for _, tc := range testCases {
13347+
if tc.expectedFail {
13348+
if errs := ValidatePersistentVolumeClaimSpec(&tc.claimSpec, field.NewPath("spec")); len(errs) == 0 {
13349+
t.Errorf("expected failure: %v", errs)
13350+
}
13351+
13352+
} else {
13353+
if errs := ValidatePersistentVolumeClaimSpec(&tc.claimSpec, field.NewPath("spec")); len(errs) != 0 {
13354+
t.Errorf("expected success: %v", errs)
13355+
}
13356+
13357+
}
13358+
}
13359+
}

pkg/features/kube_features.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -465,6 +465,12 @@ const (
465465
//
466466
// Enables NonPreempting option for priorityClass and pod.
467467
NonPreemptingPriority featuregate.Feature = "NonPreemptingPriority"
468+
469+
// owner: @j-griffith
470+
// alpha: v1.15
471+
//
472+
// Enable support for specifying an existing PVC as a DataSource
473+
VolumePVCDataSource featuregate.Feature = "VolumePVCDataSource"
468474
)
469475

470476
func init() {
@@ -543,6 +549,7 @@ var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureS
543549
WindowsGMSA: {Default: false, PreRelease: featuregate.Alpha},
544550
LocalStorageCapacityIsolationFSQuotaMonitoring: {Default: false, PreRelease: featuregate.Alpha},
545551
NonPreemptingPriority: {Default: false, PreRelease: featuregate.Alpha},
552+
VolumePVCDataSource: {Default: false, PreRelease: featuregate.Alpha},
546553

547554
// inherited features from generic apiserver, relisted here to get a conflict if it is changed
548555
// unintentionally on either side:

0 commit comments

Comments
 (0)