@@ -17,10 +17,13 @@ limitations under the License.
1717package tests
1818
1919import (
20+ "context"
21+ "fmt"
2022 "time"
2123
2224 "github.com/onsi/ginkgo"
2325 "github.com/onsi/gomega"
26+ "github.com/openebs/lib-csi/pkg/csipv"
2427
2528 "github.com/openebs/lvm-localpv/pkg/lvm"
2629 "github.com/openebs/lvm-localpv/tests/container"
@@ -30,6 +33,7 @@ import (
3033 "github.com/openebs/lvm-localpv/tests/pts"
3134 "github.com/openebs/lvm-localpv/tests/pvc"
3235 "github.com/openebs/lvm-localpv/tests/sc"
36+ appsv1 "k8s.io/api/apps/v1"
3337 corev1 "k8s.io/api/core/v1"
3438 k8serrors "k8s.io/apimachinery/pkg/api/errors"
3539 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -526,3 +530,178 @@ func IsPVDeletedEventually(shouldExist bool, pvName string) bool {
526530 120 , 10 ).
527531 Should (shouldPVExist )
528532}
533+
534+ func getGeneratedVolName (pvc * corev1.PersistentVolumeClaim ) string {
535+ return fmt .Sprintf ("pvc-%v" , pvcObj .GetUID ())
536+ }
537+
538+ func createPVC () {
539+ var (
540+ err error
541+ pvcName = "lvmpv-pvc"
542+ )
543+ ginkgo .By ("building a pvc" )
544+ pvcObj , err = pvc .NewBuilder ().
545+ WithName (pvcName ).
546+ WithNamespace (OpenEBSNamespace ).
547+ WithStorageClass (scObj .Name ).
548+ WithAccessModes (accessModes ).
549+ WithCapacity (capacity ).Build ()
550+ gomega .Expect (err ).ShouldNot (
551+ gomega .HaveOccurred (),
552+ "while building pvc {%s} in namespace {%s}" ,
553+ pvcName ,
554+ OpenEBSNamespace ,
555+ )
556+
557+ ginkgo .By ("creating above pvc" )
558+ pvcObj , err = PVCClient .WithNamespace (OpenEBSNamespace ).Create (pvcObj )
559+ gomega .Expect (err ).To (
560+ gomega .BeNil (),
561+ "while creating pvc {%s} in namespace {%s}" ,
562+ pvcName ,
563+ OpenEBSNamespace ,
564+ )
565+ }
566+
567+ func deleteAndVerifyLeakedPVC (pvcName string ) {
568+ ginkgo .By ("Deleting pending PVC" )
569+ err := PVCClient .WithNamespace (OpenEBSNamespace ).Delete (pvcName , & metav1.DeleteOptions {})
570+ gomega .Expect (err ).To (
571+ gomega .BeNil (),
572+ "while deleting pvc {%s} in namespace {%s}" ,
573+ pvcName ,
574+ OpenEBSNamespace ,
575+ )
576+ ginkgo .By ("Verify leaked pvc finalizer" )
577+
578+ status := gomega .Eventually (func () bool {
579+ pvcRes , err := PVCClient .
580+ Get (pvcName , metav1.GetOptions {})
581+ gomega .Expect (err ).To (
582+ gomega .BeNil (),
583+ "fetch pvc %v" , pvcName )
584+ return len (pvcRes .GetFinalizers ()) == 1 &&
585+ pvcRes .GetFinalizers ()[0 ] == LocalProvisioner + "/" + csipv .LeakProtectionFinalizer
586+ }, 120 , 10 ).Should (gomega .BeTrue ())
587+ gomega .Expect (status ).To (gomega .Equal (true ), "expecting a leak protection finalizer" )
588+ }
589+
590+ func verifyPendingLVMVolume (volName string ) {
591+ ginkgo .By ("fetching lvm volume" )
592+ vol , err := LVMClient .WithNamespace (OpenEBSNamespace ).
593+ Get (volName , metav1.GetOptions {})
594+ gomega .Expect (err ).To (gomega .BeNil (), "while fetching the lvm volume {%s}" , volName )
595+
596+ ginkgo .By ("verifying lvm volume" )
597+ gomega .Expect (scObj .Parameters ["volgroup" ]).To (gomega .MatchRegexp (vol .Spec .VgPattern ),
598+ "while checking volume group of lvm volume" , volName )
599+ }
600+
601+ // WaitForLVMVolumeReady verify the if lvm-volume is ready
602+ func WaitForLVMVolumeReady () {
603+ volName := getGeneratedVolName (pvcObj )
604+ status := gomega .Eventually (func () bool {
605+ vol , err := LVMClient .WithNamespace (OpenEBSNamespace ).
606+ Get (volName , metav1.GetOptions {})
607+ gomega .Expect (err ).To (gomega .BeNil (), "while fetching the lvm volume {%s}" , volName )
608+ return vol .Status .State == "Ready"
609+ }, 120 , 10 ).
610+ Should (gomega .BeTrue ())
611+ gomega .Expect (status ).To (gomega .Equal (true ), "expecting a lvmvol resource to be ready" )
612+ }
613+
614+ func scaleControllerPlugin (num int32 ) int32 {
615+ ginkgo .By (fmt .Sprintf ( "scaling controller plugin statefulset %v to size %v" , controllerStatefulSet , num ))
616+
617+ scale , err := K8sClient .AppsV1 ().StatefulSets (metav1 .NamespaceSystem ).
618+ GetScale (context .Background (), controllerStatefulSet ,metav1.GetOptions {})
619+ gomega .Expect (err ).To (
620+ gomega .BeNil (),
621+ "fetch current replica of stateful set %v" , controllerStatefulSet )
622+ existingReplicas := scale .Spec .Replicas
623+
624+ if scale .Spec .Replicas == num {
625+ return existingReplicas
626+ }
627+ scale .Spec .Replicas = num
628+ scale , err = K8sClient .AppsV1 ().StatefulSets (metav1 .NamespaceSystem ).
629+ UpdateScale (context .Background (), controllerStatefulSet , scale , metav1.UpdateOptions {})
630+ gomega .Expect (err ).To (
631+ gomega .BeNil (),
632+ "update replicas of stateful set %v to %v" , controllerStatefulSet , num )
633+
634+ scaled := gomega .Eventually (func () bool {
635+ scale , err = K8sClient .AppsV1 ().StatefulSets (metav1 .NamespaceSystem ).
636+ GetScale (context .Background (), controllerStatefulSet ,metav1.GetOptions {})
637+ gomega .Expect (err ).ShouldNot (gomega .HaveOccurred ())
638+ return scale .Spec .Replicas == num
639+ }, 120 , 10 ).
640+ Should (gomega .BeTrue ())
641+ gomega .Expect (scaled ).To (gomega .BeTrue (),
642+ "failed to scale up stateful set %v to size %v" , controllerStatefulSet , num )
643+ return existingReplicas
644+ }
645+
646+ func deleteNodeDaemonSet () * appsv1.DaemonSet {
647+ csiNodes , err := K8sClient .StorageV1 ().CSINodes ().List (context .Background (), metav1.ListOptions {})
648+ gomega .Expect (err ).To (
649+ gomega .BeNil (), "fetching csi node" )
650+ if len (csiNodes .Items ) == 0 {
651+ err = fmt .Errorf ("expecting non-zero csi nodes in the cluster" )
652+ gomega .Expect (err ).To (gomega .BeNil ())
653+ }
654+ csiNode := csiNodes .Items [0 ]
655+
656+ ginkgo .By ("deleting node plugin daemonset " + nodeDaemonSet )
657+ ds , err := K8sClient .AppsV1 ().
658+ DaemonSets (metav1 .NamespaceSystem ).
659+ Get (context .Background (), nodeDaemonSet , metav1.GetOptions {})
660+ gomega .Expect (err ).To (
661+ gomega .BeNil (),
662+ "fetching node plugin daemonset %v" , nodeDaemonSet )
663+ policy := metav1 .DeletePropagationForeground
664+ err = K8sClient .AppsV1 ().
665+ DaemonSets (metav1 .NamespaceSystem ).
666+ Delete (context .Background (), nodeDaemonSet , metav1.DeleteOptions {
667+ PropagationPolicy : & policy ,
668+ })
669+ gomega .Expect (err ).To (
670+ gomega .BeNil (),
671+ "deleting node plugin daemonset %v" , nodeDaemonSet )
672+
673+ ginkgo .By ("waiting for deletion of node plugin pods" )
674+ status := gomega .Eventually (func () bool {
675+ _ , err = K8sClient .AppsV1 ().
676+ DaemonSets (metav1 .NamespaceSystem ).
677+ Get (context .Background (), nodeDaemonSet , metav1.GetOptions {})
678+ return k8serrors .IsNotFound (err )
679+ }, 120 , 10 ).Should (gomega .BeTrue ())
680+ gomega .Expect (status ).To (gomega .Equal (true ),
681+ "waiting for deletion of node plugin daemonset" )
682+
683+
684+ // update the underlying csi node resource to ensure pvc gets scheduled
685+ // by external provisioner.
686+ ginkgo .By ("patching csinode resource" )
687+ newCSINode , err := K8sClient .StorageV1 ().CSINodes ().Get (context .Background (), csiNode .GetName (), metav1.GetOptions {})
688+ gomega .Expect (err ).To (
689+ gomega .BeNil (), "fetching updated csi node" )
690+ newCSINode .Spec .Drivers = csiNode .Spec .Drivers
691+ _ , err = K8sClient .StorageV1 ().CSINodes ().Update (context .Background (), newCSINode , metav1.UpdateOptions {})
692+ gomega .Expect (err ).To (
693+ gomega .BeNil (), "updating csi node %v" , csiNode .GetName ())
694+
695+ return ds
696+ }
697+
698+ func createNodeDaemonSet (ds * appsv1.DaemonSet ) {
699+ ds .SetResourceVersion ("" ) // reset the resource version for creation.
700+ ginkgo .By ("creating node plugin daemonset " + nodeDaemonSet )
701+ _ , err := K8sClient .AppsV1 ().
702+ DaemonSets (metav1 .NamespaceSystem ).
703+ Create (context .Background (), ds , metav1.CreateOptions {})
704+ gomega .Expect (err ).To (
705+ gomega .BeNil (),
706+ "creating node plugin daemonset %v" , nodeDaemonSet )
707+ }
0 commit comments