Add API and validation for CrossNamespaceVolumeDataSource

This commit is contained in:
Takafumi Takahashi
2022-11-01 03:54:34 +00:00
parent 623376bc82
commit 87c1ca88d4
12 changed files with 596 additions and 137 deletions

View File

@@ -154,23 +154,47 @@ 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,
}
}
var (
coreGroup = ""
snapGroup = "snapshot.storage.k8s.io"
genericGroup = "generic.storage.k8s.io"
pvcKind = "PersistentVolumeClaim"
snapKind = "VolumeSnapshot"
genericKind = "Generic"
podKind = "Pod"
)
volumeDataSource := makeDataSource("", "PersistentVolumeClaim", "my-vol")
func makeDataSource(apiGroup, kind, name string) *core.TypedLocalObjectReference {
return &core.TypedLocalObjectReference{
APIGroup: &apiGroup,
Kind: kind,
Name: name,
}
}
func makeDataSourceRef(apiGroup, kind, name string, namespace *string) *core.TypedObjectReference {
return &core.TypedObjectReference{
APIGroup: &apiGroup,
Kind: kind,
Name: name,
Namespace: namespace,
}
}
// TestDataSourceFilter checks to ensure the AnyVolumeDataSource feature gate and CrossNamespaceVolumeDataSource works
func TestDataSourceFilter(t *testing.T) {
ns := "ns1"
volumeDataSource := makeDataSource(coreGroup, pvcKind, "my-vol")
volumeDataSourceRef := makeDataSourceRef(coreGroup, pvcKind, "my-vol", nil)
xnsVolumeDataSourceRef := makeDataSourceRef(coreGroup, pvcKind, "my-vol", &ns)
var tests = map[string]struct {
spec core.PersistentVolumeClaimSpec
oldSpec core.PersistentVolumeClaimSpec
anyEnabled bool
xnsEnabled bool
want *core.TypedLocalObjectReference
wantRef *core.TypedLocalObjectReference
wantRef *core.TypedObjectReference
}{
"any disabled with empty ds": {
spec: core.PersistentVolumeClaimSpec{},
@@ -180,10 +204,10 @@ func TestAnyDataSourceFilter(t *testing.T) {
want: volumeDataSource,
},
"any disabled with volume ds ref": {
spec: core.PersistentVolumeClaimSpec{DataSourceRef: volumeDataSource},
spec: core.PersistentVolumeClaimSpec{DataSourceRef: volumeDataSourceRef},
},
"any disabled with both data sources": {
spec: core.PersistentVolumeClaimSpec{DataSource: volumeDataSource, DataSourceRef: volumeDataSource},
spec: core.PersistentVolumeClaimSpec{DataSource: volumeDataSource, DataSourceRef: volumeDataSourceRef},
want: volumeDataSource,
},
"any enabled with empty ds": {
@@ -196,25 +220,63 @@ func TestAnyDataSourceFilter(t *testing.T) {
want: volumeDataSource,
},
"any enabled with volume ds ref": {
spec: core.PersistentVolumeClaimSpec{DataSourceRef: volumeDataSource},
spec: core.PersistentVolumeClaimSpec{DataSourceRef: volumeDataSourceRef},
anyEnabled: true,
wantRef: volumeDataSource,
wantRef: volumeDataSourceRef,
},
"any enabled with both data sources": {
spec: core.PersistentVolumeClaimSpec{DataSource: volumeDataSource, DataSourceRef: volumeDataSource},
spec: core.PersistentVolumeClaimSpec{DataSource: volumeDataSource, DataSourceRef: volumeDataSourceRef},
anyEnabled: true,
want: volumeDataSource,
wantRef: volumeDataSource,
wantRef: volumeDataSourceRef,
},
"both any and xns enabled with xns volume ds": {
spec: core.PersistentVolumeClaimSpec{DataSourceRef: xnsVolumeDataSourceRef},
anyEnabled: true,
xnsEnabled: true,
wantRef: xnsVolumeDataSourceRef,
},
"both any and xns enabled with xns volume ds when xns volume exists in oldSpec": {
spec: core.PersistentVolumeClaimSpec{DataSourceRef: xnsVolumeDataSourceRef},
oldSpec: core.PersistentVolumeClaimSpec{DataSourceRef: xnsVolumeDataSourceRef},
anyEnabled: true,
xnsEnabled: true,
wantRef: xnsVolumeDataSourceRef,
},
"only xns enabled with xns volume ds": {
spec: core.PersistentVolumeClaimSpec{DataSourceRef: xnsVolumeDataSourceRef},
xnsEnabled: true,
},
"only any enabled with xns volume ds": {
spec: core.PersistentVolumeClaimSpec{DataSourceRef: xnsVolumeDataSourceRef},
anyEnabled: true,
},
"only any enabled with xns volume ds when xns volume exists in oldSpec": {
spec: core.PersistentVolumeClaimSpec{DataSourceRef: xnsVolumeDataSourceRef},
oldSpec: core.PersistentVolumeClaimSpec{DataSourceRef: xnsVolumeDataSourceRef},
anyEnabled: true,
wantRef: xnsVolumeDataSourceRef, // existing field isn't dropped.
},
"only any enabled with xns volume ds when volume exists in oldSpec": {
spec: core.PersistentVolumeClaimSpec{DataSourceRef: xnsVolumeDataSourceRef},
oldSpec: core.PersistentVolumeClaimSpec{DataSourceRef: volumeDataSourceRef},
anyEnabled: true,
wantRef: xnsVolumeDataSourceRef, // existing field isn't dropped.
},
}
for testName, test := range tests {
t.Run(testName, func(t *testing.T) {
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.AnyVolumeDataSource, test.anyEnabled)()
DropDisabledFields(&test.spec)
if test.spec.DataSource != test.want || test.spec.DataSourceRef != test.wantRef {
t.Errorf("expected condition was not met, test: %s, anyEnabled: %v, spec: %v, expected: %v %v",
testName, test.anyEnabled, test.spec, test.want, test.wantRef)
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CrossNamespaceVolumeDataSource, test.xnsEnabled)()
DropDisabledFields(&test.spec, &test.oldSpec)
if test.spec.DataSource != test.want {
t.Errorf("expected condition was not met, test: %s, anyEnabled: %v, xnsEnabled: %v, spec: %+v, expected DataSource: %+v",
testName, test.anyEnabled, test.xnsEnabled, test.spec, test.want)
}
if test.spec.DataSourceRef != test.wantRef {
t.Errorf("expected condition was not met, test: %s, anyEnabled: %v, xnsEnabled: %v, spec: %+v, expected DataSourceRef: %+v",
testName, test.anyEnabled, test.xnsEnabled, test.spec, test.wantRef)
}
})
}
@@ -223,69 +285,99 @@ func TestAnyDataSourceFilter(t *testing.T) {
// TestDataSourceRef checks to ensure the DataSourceRef field handles backwards
// compatibility with the DataSource field
func TestDataSourceRef(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")
coreDataSource := makeDataSource("", "Pod", "my-pod")
ns := "ns1"
volumeDataSource := makeDataSource(coreGroup, pvcKind, "my-vol")
volumeDataSourceRef := makeDataSourceRef(coreGroup, pvcKind, "my-vol", nil)
xnsVolumeDataSourceRef := makeDataSourceRef(coreGroup, pvcKind, "my-vol", &ns)
snapshotDataSource := makeDataSource(snapGroup, snapKind, "my-snap")
snapshotDataSourceRef := makeDataSourceRef(snapGroup, snapKind, "my-snap", nil)
xnsSnapshotDataSourceRef := makeDataSourceRef(snapGroup, snapKind, "my-snap", &ns)
genericDataSource := makeDataSource(genericGroup, genericKind, "my-foo")
genericDataSourceRef := makeDataSourceRef(genericGroup, genericKind, "my-foo", nil)
xnsGenericDataSourceRef := makeDataSourceRef(genericGroup, genericKind, "my-foo", &ns)
coreDataSource := makeDataSource(coreGroup, podKind, "my-pod")
coreDataSourceRef := makeDataSourceRef(coreGroup, podKind, "my-pod", nil)
xnsCoreDataSourceRef := makeDataSourceRef(coreGroup, podKind, "my-pod", &ns)
var tests = map[string]struct {
spec core.PersistentVolumeClaimSpec
want *core.TypedLocalObjectReference
spec core.PersistentVolumeClaimSpec
want *core.TypedLocalObjectReference
wantRef *core.TypedObjectReference
}{
"empty ds": {
spec: core.PersistentVolumeClaimSpec{},
},
"volume ds": {
spec: core.PersistentVolumeClaimSpec{DataSource: volumeDataSource},
want: volumeDataSource,
spec: core.PersistentVolumeClaimSpec{DataSource: volumeDataSource},
want: volumeDataSource,
wantRef: volumeDataSourceRef,
},
"snapshot ds": {
spec: core.PersistentVolumeClaimSpec{DataSource: snapshotDataSource},
want: snapshotDataSource,
spec: core.PersistentVolumeClaimSpec{DataSource: snapshotDataSource},
want: snapshotDataSource,
wantRef: snapshotDataSourceRef,
},
"generic ds": {
spec: core.PersistentVolumeClaimSpec{DataSource: genericDataSource},
want: genericDataSource,
spec: core.PersistentVolumeClaimSpec{DataSource: genericDataSource},
want: genericDataSource,
wantRef: genericDataSourceRef,
},
"core ds": {
spec: core.PersistentVolumeClaimSpec{DataSource: coreDataSource},
want: coreDataSource,
spec: core.PersistentVolumeClaimSpec{DataSource: coreDataSource},
want: coreDataSource,
wantRef: coreDataSourceRef,
},
"volume ds ref": {
spec: core.PersistentVolumeClaimSpec{DataSourceRef: volumeDataSource},
want: volumeDataSource,
spec: core.PersistentVolumeClaimSpec{DataSourceRef: volumeDataSourceRef},
want: volumeDataSource,
wantRef: volumeDataSourceRef,
},
"snapshot ds ref": {
spec: core.PersistentVolumeClaimSpec{DataSourceRef: snapshotDataSource},
want: snapshotDataSource,
spec: core.PersistentVolumeClaimSpec{DataSourceRef: snapshotDataSourceRef},
want: snapshotDataSource,
wantRef: snapshotDataSourceRef,
},
"generic ds ref": {
spec: core.PersistentVolumeClaimSpec{DataSourceRef: genericDataSource},
want: genericDataSource,
spec: core.PersistentVolumeClaimSpec{DataSourceRef: genericDataSourceRef},
want: genericDataSource,
wantRef: genericDataSourceRef,
},
"core ds ref": {
spec: core.PersistentVolumeClaimSpec{DataSourceRef: coreDataSource},
want: coreDataSource,
spec: core.PersistentVolumeClaimSpec{DataSourceRef: coreDataSourceRef},
want: coreDataSource,
wantRef: coreDataSourceRef,
},
"xns volume ds ref": {
spec: core.PersistentVolumeClaimSpec{DataSourceRef: xnsVolumeDataSourceRef},
wantRef: xnsVolumeDataSourceRef,
},
"xns snapshot ds ref": {
spec: core.PersistentVolumeClaimSpec{DataSourceRef: xnsSnapshotDataSourceRef},
wantRef: xnsSnapshotDataSourceRef,
},
"xns generic ds ref": {
spec: core.PersistentVolumeClaimSpec{DataSourceRef: xnsGenericDataSourceRef},
wantRef: xnsGenericDataSourceRef,
},
"xns core ds ref": {
spec: core.PersistentVolumeClaimSpec{DataSourceRef: xnsCoreDataSourceRef},
wantRef: xnsCoreDataSourceRef,
},
}
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.AnyVolumeDataSource, true)()
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CrossNamespaceVolumeDataSource, true)()
for testName, test := range tests {
t.Run(testName, func(t *testing.T) {
NormalizeDataSources(&test.spec)
if !reflect.DeepEqual(test.spec.DataSource, test.want) ||
!reflect.DeepEqual(test.spec.DataSourceRef, test.want) {
t.Errorf("expected condition was not met, test: %s, spec: %v, expected: %v",
testName, test.spec, test.want)
if !reflect.DeepEqual(test.spec.DataSource, test.want) {
t.Errorf("expected condition was not met, test: %s, spec.datasource: %+v, want: %+v",
testName, test.spec.DataSource, test.want)
}
if !reflect.DeepEqual(test.spec.DataSourceRef, test.wantRef) {
t.Errorf("expected condition was not met, test: %s, spec.datasourceRef: %+v, wantRef: %+v",
testName, test.spec.DataSourceRef, test.wantRef)
}
})
}