Skip to content

Commit c7c4039

Browse files
authored
Merge pull request kubernetes#123151 from carlory/honor-pv-reclaim-policy-e2e
add e2e test for HonorPVReclaimPolicy
2 parents a07d3c4 + 522c06b commit c7c4039

File tree

6 files changed

+378
-4
lines changed

6 files changed

+378
-4
lines changed

test/e2e/feature/feature.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,20 @@ var (
139139
// TODO: document the feature (owning SIG, when to use this feature for a test)
140140
HPA = framework.WithFeature(framework.ValidFeatures.Add("HPA"))
141141

142+
// owning-sig: sig-storage
143+
// kep: https://kep.k8s.io/2680
144+
// test-infra jobs:
145+
// - pull-kubernetes-e2e-storage-kind-alpha-features (need manual trigger)
146+
// - ci-kubernetes-e2e-storage-kind-alpha-features
147+
//
148+
// When this label is added to a test, it means that the cluster must be created
149+
// with the feature-gate "HonorPVReclaimPolicy=true".
150+
//
151+
// Once the feature are stable, this label should be removed and these tests will
152+
// be run by default on any cluster. The test-infra job also should be updated to
153+
// not focus on this feature anymore.
154+
HonorPVReclaimPolicy = framework.WithFeature(framework.ValidFeatures.Add("HonorPVReclaimPolicy"))
155+
142156
// TODO: document the feature (owning SIG, when to use this feature for a test)
143157
HugePages = framework.WithFeature(framework.ValidFeatures.Add("HugePages"))
144158

test/e2e/framework/pv/pv.go

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,9 @@ type PersistentVolumeConfig struct {
9393
// [Optional] Labels contains information used to organize and categorize
9494
// objects
9595
Labels labels.Set
96+
// [Optional] Annotations contains information used to organize and categorize
97+
// objects
98+
Annotations map[string]string
9699
// PVSource contains the details of the underlying volume and must be set
97100
PVSource v1.PersistentVolumeSource
98101
// [Optional] Prebind lets you specify a PVC to bind this PV to before
@@ -595,13 +598,18 @@ func MakePersistentVolume(pvConfig PersistentVolumeConfig) *v1.PersistentVolume
595598
}
596599
}
597600

601+
annotations := map[string]string{
602+
volumeGidAnnotationKey: "777",
603+
}
604+
for k, v := range pvConfig.Annotations {
605+
annotations[k] = v
606+
}
607+
598608
return &v1.PersistentVolume{
599609
ObjectMeta: metav1.ObjectMeta{
600610
GenerateName: pvConfig.NamePrefix,
601611
Labels: pvConfig.Labels,
602-
Annotations: map[string]string{
603-
volumeGidAnnotationKey: "777",
604-
},
612+
Annotations: annotations,
605613
},
606614
Spec: v1.PersistentVolumeSpec{
607615
PersistentVolumeReclaimPolicy: pvConfig.ReclaimPolicy,

test/e2e/storage/csimock/base.go

Lines changed: 140 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ import (
4848
"k8s.io/kubernetes/test/e2e/storage/utils"
4949
"k8s.io/kubernetes/test/utils/format"
5050
imageutils "k8s.io/kubernetes/test/utils/image"
51+
"k8s.io/utils/ptr"
5152
)
5253

5354
const (
@@ -101,14 +102,17 @@ type testParameters struct {
101102
fsGroupPolicy *storagev1.FSGroupPolicy
102103
enableSELinuxMount *bool
103104
enableRecoverExpansionFailure bool
105+
enableHonorPVReclaimPolicy bool
104106
enableCSINodeExpandSecret bool
107+
reclaimPolicy *v1.PersistentVolumeReclaimPolicy
105108
}
106109

107110
type mockDriverSetup struct {
108111
cs clientset.Interface
109112
config *storageframework.PerTestConfig
110113
pods []*v1.Pod
111114
pvcs []*v1.PersistentVolumeClaim
115+
pvs []*v1.PersistentVolume
112116
sc map[string]*storagev1.StorageClass
113117
vsc map[string]*unstructured.Unstructured
114118
driver drivers.MockCSITestDriver
@@ -171,6 +175,7 @@ func (m *mockDriverSetup) init(ctx context.Context, tp testParameters) {
171175
FSGroupPolicy: tp.fsGroupPolicy,
172176
EnableSELinuxMount: tp.enableSELinuxMount,
173177
EnableRecoverExpansionFailure: tp.enableRecoverExpansionFailure,
178+
EnableHonorPVReclaimPolicy: tp.enableHonorPVReclaimPolicy,
174179
}
175180

176181
// At the moment, only tests which need hooks are
@@ -235,6 +240,11 @@ func (m *mockDriverSetup) cleanup(ctx context.Context) {
235240
}
236241
}
237242

243+
for _, pv := range m.pvs {
244+
ginkgo.By(fmt.Sprintf("Deleting pv %s", pv.Name))
245+
errs = append(errs, e2epv.DeletePersistentVolume(ctx, cs, pv.Name))
246+
}
247+
238248
for _, sc := range m.sc {
239249
ginkgo.By(fmt.Sprintf("Deleting storageclass %s", sc.Name))
240250
cs.StorageV1().StorageClasses().Delete(context.TODO(), sc.Name, metav1.DeleteOptions{})
@@ -286,6 +296,7 @@ func (m *mockDriverSetup) createPod(ctx context.Context, withVolume volumeType)
286296
ExpectedSize: "1Gi",
287297
DelayBinding: m.tp.lateBinding,
288298
AllowVolumeExpansion: m.tp.enableResizing,
299+
ReclaimPolicy: m.tp.reclaimPolicy,
289300
}
290301

291302
// The mock driver only works when everything runs on a single node.
@@ -319,6 +330,92 @@ func (m *mockDriverSetup) createPod(ctx context.Context, withVolume volumeType)
319330
return // result variables set above
320331
}
321332

333+
func (m *mockDriverSetup) createPVC(ctx context.Context) (class *storagev1.StorageClass, claim *v1.PersistentVolumeClaim) {
334+
ginkgo.By("Creating pvc")
335+
f := m.f
336+
337+
sc := m.driver.GetDynamicProvisionStorageClass(ctx, m.config, "")
338+
if m.tp.enableCSINodeExpandSecret {
339+
if sc.Parameters == nil {
340+
parameters := map[string]string{
341+
csiNodeExpandSecretKey: "test-secret",
342+
csiNodeExpandSecretNamespaceKey: f.Namespace.Name,
343+
}
344+
sc.Parameters = parameters
345+
} else {
346+
sc.Parameters[csiNodeExpandSecretKey] = "test-secret"
347+
sc.Parameters[csiNodeExpandSecretNamespaceKey] = f.Namespace.Name
348+
}
349+
}
350+
scTest := testsuites.StorageClassTest{
351+
Name: m.driver.GetDriverInfo().Name,
352+
Timeouts: f.Timeouts,
353+
Provisioner: sc.Provisioner,
354+
Parameters: sc.Parameters,
355+
ClaimSize: "1Gi",
356+
ExpectedSize: "1Gi",
357+
DelayBinding: m.tp.lateBinding,
358+
AllowVolumeExpansion: m.tp.enableResizing,
359+
ReclaimPolicy: m.tp.reclaimPolicy,
360+
}
361+
362+
// The mock driver only works when everything runs on a single node.
363+
nodeSelection := m.config.ClientNodeSelection
364+
class, claim = createClaim(ctx, f.ClientSet, scTest, nodeSelection, m.tp.scName, f.Namespace.Name, nil)
365+
if class != nil {
366+
m.sc[class.Name] = class
367+
}
368+
if claim != nil {
369+
m.pvcs = append(m.pvcs, claim)
370+
}
371+
372+
return class, claim
373+
}
374+
375+
func (m *mockDriverSetup) createPVPVC(ctx context.Context) (class *storagev1.StorageClass, volume *v1.PersistentVolume, claim *v1.PersistentVolumeClaim) {
376+
ginkgo.By("Creating the PV and PVC manually")
377+
f := m.f
378+
379+
sc := m.driver.GetDynamicProvisionStorageClass(ctx, m.config, "")
380+
if m.tp.enableCSINodeExpandSecret {
381+
if sc.Parameters == nil {
382+
parameters := map[string]string{
383+
csiNodeExpandSecretKey: "test-secret",
384+
csiNodeExpandSecretNamespaceKey: f.Namespace.Name,
385+
}
386+
sc.Parameters = parameters
387+
} else {
388+
sc.Parameters[csiNodeExpandSecretKey] = "test-secret"
389+
sc.Parameters[csiNodeExpandSecretNamespaceKey] = f.Namespace.Name
390+
}
391+
}
392+
scTest := testsuites.StorageClassTest{
393+
Name: m.driver.GetDriverInfo().Name,
394+
Timeouts: f.Timeouts,
395+
Provisioner: sc.Provisioner,
396+
Parameters: sc.Parameters,
397+
ClaimSize: "1Gi",
398+
ExpectedSize: "1Gi",
399+
DelayBinding: m.tp.lateBinding,
400+
AllowVolumeExpansion: m.tp.enableResizing,
401+
ReclaimPolicy: m.tp.reclaimPolicy,
402+
}
403+
404+
// The mock driver only works when everything runs on a single node.
405+
nodeSelection := m.config.ClientNodeSelection
406+
class, volume, claim = createVolumeAndClaim(ctx, f.ClientSet, scTest, nodeSelection, m.tp.scName, f.Namespace.Name, nil)
407+
if class != nil {
408+
m.sc[class.Name] = class
409+
}
410+
if volume != nil {
411+
m.pvs = append(m.pvs, volume)
412+
}
413+
if claim != nil {
414+
m.pvcs = append(m.pvcs, claim)
415+
}
416+
return class, volume, claim
417+
}
418+
322419
func (m *mockDriverSetup) createPodWithPVC(pvc *v1.PersistentVolumeClaim) (*v1.Pod, error) {
323420
f := m.f
324421

@@ -344,6 +441,7 @@ func (m *mockDriverSetup) createPodWithFSGroup(ctx context.Context, fsGroup *int
344441
ExpectedSize: "1Gi",
345442
DelayBinding: m.tp.lateBinding,
346443
AllowVolumeExpansion: m.tp.enableResizing,
444+
ReclaimPolicy: m.tp.reclaimPolicy,
347445
}
348446
class, claim, pod := startBusyBoxPod(ctx, f.ClientSet, scTest, nodeSelection, m.tp.scName, f.Namespace.Name, fsGroup)
349447

@@ -375,6 +473,7 @@ func (m *mockDriverSetup) createPodWithSELinux(ctx context.Context, accessModes
375473
DelayBinding: m.tp.lateBinding,
376474
AllowVolumeExpansion: m.tp.enableResizing,
377475
MountOptions: mountOptions,
476+
ReclaimPolicy: m.tp.reclaimPolicy,
378477
}
379478
class, claim := createClaim(ctx, f.ClientSet, scTest, nodeSelection, m.tp.scName, f.Namespace.Name, accessModes)
380479
pod, err := startPausePodWithSELinuxOptions(f.ClientSet, claim, nodeSelection, f.Namespace.Name, seLinuxOpts)
@@ -441,7 +540,7 @@ func newStorageClass(t testsuites.StorageClassTest, ns string, prefix string) *s
441540
}
442541
}
443542

444-
sc := getStorageClass(pluginName, t.Parameters, &bindingMode, t.MountOptions, ns, prefix)
543+
sc := getStorageClass(pluginName, t.Parameters, &bindingMode, t.MountOptions, t.ReclaimPolicy, ns, prefix)
445544
if t.AllowVolumeExpansion {
446545
sc.AllowVolumeExpansion = &t.AllowVolumeExpansion
447546
}
@@ -453,6 +552,7 @@ func getStorageClass(
453552
parameters map[string]string,
454553
bindingMode *storagev1.VolumeBindingMode,
455554
mountOptions []string,
555+
reclaimPolicy *v1.PersistentVolumeReclaimPolicy,
456556
ns string,
457557
prefix string,
458558
) *storagev1.StorageClass {
@@ -472,6 +572,7 @@ func getStorageClass(
472572
Parameters: parameters,
473573
VolumeBindingMode: bindingMode,
474574
MountOptions: mountOptions,
575+
ReclaimPolicy: reclaimPolicy,
475576
}
476577
}
477578

@@ -523,6 +624,44 @@ func createClaim(ctx context.Context, cs clientset.Interface, t testsuites.Stora
523624
return class, claim
524625
}
525626

627+
func createVolumeAndClaim(ctx context.Context, cs clientset.Interface, t testsuites.StorageClassTest, node e2epod.NodeSelection, scName, ns string, accessModes []v1.PersistentVolumeAccessMode) (*storagev1.StorageClass, *v1.PersistentVolume, *v1.PersistentVolumeClaim) {
628+
class := createSC(cs, t, scName, ns)
629+
630+
volumeMode := v1.PersistentVolumeFilesystem
631+
if t.VolumeMode != "" {
632+
volumeMode = t.VolumeMode
633+
}
634+
635+
pvConfig := e2epv.PersistentVolumeConfig{
636+
Capacity: t.ClaimSize,
637+
StorageClassName: class.Name,
638+
VolumeMode: &volumeMode,
639+
AccessModes: accessModes,
640+
ReclaimPolicy: ptr.Deref(class.ReclaimPolicy, v1.PersistentVolumeReclaimDelete),
641+
PVSource: v1.PersistentVolumeSource{
642+
CSI: &v1.CSIPersistentVolumeSource{
643+
Driver: class.Provisioner,
644+
VolumeHandle: "test-volume-handle",
645+
},
646+
},
647+
}
648+
649+
pvcConfig := e2epv.PersistentVolumeClaimConfig{
650+
ClaimSize: t.ClaimSize,
651+
StorageClassName: &(class.Name),
652+
VolumeMode: &volumeMode,
653+
AccessModes: accessModes,
654+
}
655+
656+
volume, claim, err := e2epv.CreatePVPVC(ctx, cs, t.Timeouts, pvConfig, pvcConfig, ns, true)
657+
framework.ExpectNoError(err, "Failed to create PV and PVC")
658+
659+
err = e2epv.WaitOnPVandPVC(ctx, cs, t.Timeouts, ns, volume, claim)
660+
framework.ExpectNoError(err, "Failed waiting for PV and PVC to be bound each other")
661+
662+
return class, volume, claim
663+
}
664+
526665
func startPausePod(ctx context.Context, cs clientset.Interface, t testsuites.StorageClassTest, node e2epod.NodeSelection, scName, ns string) (*storagev1.StorageClass, *v1.PersistentVolumeClaim, *v1.Pod) {
527666
class, claim := createClaim(ctx, cs, t, node, scName, ns, nil)
528667

0 commit comments

Comments
 (0)