Skip to content

Commit cfd8f7b

Browse files
e2e: test for PVC with volumeBindingMode on helm installation
Test PVC binding with WaitForFirstConsumer in Helm installation. Signed-off-by: ShravaniVangur <shravanivangur@gmail.com>
1 parent b6ef888 commit cfd8f7b

4 files changed

Lines changed: 125 additions & 8 deletions

File tree

e2e/cephfs.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,23 @@ var _ = Describe(cephfsType, func() {
329329
framework.Failf("failed to delete CephFS storageclass: %v", err)
330330
}
331331
})
332+
333+
By("verify PVC with volumeBindingMode on helm installation", func() {
334+
err := createCephfsStorageClassVolumeBindingMode(f.ClientSet, f, true, nil, true)
335+
if err != nil {
336+
framework.Failf("failed to create CephFS storageclass: %v", err)
337+
}
338+
339+
err = validatePVCAndAppForVolumeBindingMode(pvcPath, appPath, f)
340+
if err != nil {
341+
framework.Failf("failed to validate CephFS pvc and application binding: %v", err)
342+
}
343+
344+
err = deleteResource(cephFSExamplePath + "storageclass.yaml")
345+
if err != nil {
346+
framework.Failf("failed to delete CephFS storageclass: %v", err)
347+
}
348+
})
332349
}
333350

334351
By("verify mountOptions support", func() {

e2e/cephfs_helper.go

Lines changed: 45 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import (
2626

2727
snapapi "github.com/kubernetes-csi/external-snapshotter/client/v8/apis/volumesnapshot/v1"
2828
v1 "k8s.io/api/core/v1"
29+
scv1 "k8s.io/api/storage/v1"
2930
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
3031
"k8s.io/apimachinery/pkg/util/wait"
3132
"k8s.io/client-go/kubernetes"
@@ -62,11 +63,47 @@ func createCephfsStorageClass(
6263
params map[string]string,
6364
) error {
6465
scPath := fmt.Sprintf("%s/%s", cephFSExamplePath, "storageclass.yaml")
65-
sc, err := getStorageClass(scPath)
66+
scValue, err := getStorageClass(scPath)
6667
if err != nil {
6768
return err
6869
}
6970

71+
sc, err := updateStorageClassParameters(&scValue, params, enablePool, f)
72+
if err != nil {
73+
return err
74+
}
75+
76+
return createStorageClass(c, sc)
77+
}
78+
79+
func createCephfsStorageClassVolumeBindingMode(c kubernetes.Interface, f *framework.Framework,
80+
enablePool bool,
81+
params map[string]string, waitForFirstConsumer bool) error {
82+
scPath := fmt.Sprintf("%s/%s", cephFSExamplePath, "storageclass.yaml")
83+
scValue, err := getStorageClass(scPath)
84+
if err != nil {
85+
return err
86+
}
87+
88+
sc, err := updateStorageClassParameters(&scValue, params, enablePool, f)
89+
if err != nil {
90+
return err
91+
}
92+
93+
value := scv1.VolumeBindingImmediate
94+
if waitForFirstConsumer {
95+
value = scv1.VolumeBindingWaitForFirstConsumer
96+
}
97+
sc.VolumeBindingMode = &value
98+
99+
return createStorageClass(c, sc)
100+
}
101+
102+
func updateStorageClassParameters(sc *scv1.StorageClass, params map[string]string, enablePool bool, f *framework.Framework) (*scv1.StorageClass, error) {
103+
if sc == nil {
104+
return sc, fmt.Errorf("StorageClass is nil")
105+
}
106+
70107
sc.Parameters["fsName"] = fileSystemName
71108
sc.Parameters["csi.storage.k8s.io/provisioner-secret-namespace"] = cephCSINamespace
72109
sc.Parameters["csi.storage.k8s.io/provisioner-secret-name"] = cephFSProvisionerSecretName
@@ -93,27 +130,27 @@ func createCephfsStorageClass(
93130

94131
// fetch and set fsID from the cluster if not set in params
95132
if _, found := params["clusterID"]; !found {
96-
var fsID string
97-
fsID, err = getClusterID(f)
133+
fsID, err := getClusterID(f)
98134
if err != nil {
99-
return fmt.Errorf("failed to get clusterID: %w", err)
135+
return nil, fmt.Errorf("failed to get clusterID: %w", err)
100136
}
101137
sc.Parameters["clusterID"] = fsID
102138
}
103139

104-
timeout := time.Duration(deployTimeout) * time.Minute
140+
return sc, nil
141+
}
105142

143+
func createStorageClass(c kubernetes.Interface, sc *scv1.StorageClass) error {
144+
timeout := time.Duration(deployTimeout) * time.Minute
106145
return wait.PollUntilContextTimeout(context.TODO(), poll, timeout, true, func(ctx context.Context) (bool, error) {
107-
_, err = c.StorageV1().StorageClasses().Create(ctx, &sc, metav1.CreateOptions{})
146+
_, err := c.StorageV1().StorageClasses().Create(ctx, sc, metav1.CreateOptions{})
108147
if err != nil {
109148
framework.Logf("error creating StorageClass %q: %v", sc.Name, err)
110149
if isRetryableAPIError(err) {
111150
return false, nil
112151
}
113-
114152
return false, fmt.Errorf("failed to create StorageClass %q: %w", sc.Name, err)
115153
}
116-
117154
return true, nil
118155
})
119156
}

e2e/pvc.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,15 @@ func createPVCAndPV(c kubernetes.Interface, pvc *v1.PersistentVolumeClaim, pv *v
130130
return err
131131
}
132132

133+
func createPVC(c kubernetes.Interface, pvc *v1.PersistentVolumeClaim) error {
134+
_, err := c.CoreV1().PersistentVolumeClaims(pvc.Namespace).Create(context.TODO(), pvc, metav1.CreateOptions{})
135+
if err != nil {
136+
return fmt.Errorf("failed to create pvc: %w", err)
137+
}
138+
139+
return err
140+
}
141+
133142
func deletePVCAndPV(c kubernetes.Interface, pvc *v1.PersistentVolumeClaim, pv *v1.PersistentVolume, t int) error {
134143
ctx := context.TODO()
135144
err := c.CoreV1().PersistentVolumeClaims(pvc.Namespace).Delete(ctx, pvc.Name, metav1.DeleteOptions{})

e2e/utils.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -508,6 +508,60 @@ func validatePVCAndAppBinding(pvcPath, appPath string, f *framework.Framework) e
508508
return err
509509
}
510510

511+
func validatePVCAndAppForVolumeBindingMode(pvcPath, appPath string, f *framework.Framework) error {
512+
pvc, err := loadPVC(pvcPath)
513+
if err != nil {
514+
return err
515+
}
516+
pvc.Namespace = f.UniqueName
517+
518+
app, err := loadApp(appPath)
519+
if err != nil {
520+
return err
521+
}
522+
app.Namespace = f.UniqueName
523+
524+
err = createPVC(f.ClientSet, pvc)
525+
if err != nil {
526+
return err
527+
}
528+
529+
//verifies that the pvc is in pending state
530+
err = waitForPVCPhase(f.ClientSet, pvc.Namespace, pvc.Name, v1.ClaimPending, 30*time.Second)
531+
if err != nil {
532+
return fmt.Errorf("PVC did not stay in Pending state as expected: %w", err)
533+
}
534+
535+
err = createApp(f.ClientSet, app, deployTimeout)
536+
if err != nil {
537+
return err
538+
}
539+
540+
//verifies that the pvc is in bound state
541+
err = waitForPVCPhase(f.ClientSet, pvc.Namespace, pvc.Name, v1.ClaimBound, 30*time.Second)
542+
if err != nil {
543+
return fmt.Errorf("PVC did not reach Bound state after creating the pod: %w", err)
544+
}
545+
546+
err = deletePVCAndApp("", f, pvc, app)
547+
548+
return err
549+
}
550+
551+
func waitForPVCPhase(c kubernetes.Interface, namespace, name string, phase v1.PersistentVolumeClaimPhase, timeout time.Duration) error {
552+
return wait.PollUntilContextTimeout(context.TODO(), poll, timeout, true, func(ctx context.Context) (bool, error) {
553+
pvc, err := c.CoreV1().PersistentVolumeClaims(namespace).Get(context.TODO(), name, metav1.GetOptions{})
554+
if err != nil {
555+
return false, fmt.Errorf("error fetching PVC %s: %w", name, err)
556+
}
557+
if pvc.Status.Phase == phase {
558+
return true, nil
559+
}
560+
framework.Logf("Waiting for PVC %s to reach phase %s, current phase: %s", name, phase, pvc.Status.Phase)
561+
return false, nil
562+
})
563+
}
564+
511565
func getMountType(selector, mountPath string, f *framework.Framework) (string, error) {
512566
opt := metav1.ListOptions{
513567
LabelSelector: selector,

0 commit comments

Comments
 (0)