diff --git a/test/e2e/storage/csi_volumes.go b/test/e2e/storage/csi_volumes.go index 4886ae16afc..10d3d126793 100644 --- a/test/e2e/storage/csi_volumes.go +++ b/test/e2e/storage/csi_volumes.go @@ -261,9 +261,11 @@ var _ = utils.SIGDescribe("CSI Volumes", func() { Parameters: sc.Parameters, ClaimSize: "1Gi", ExpectedSize: "1Gi", - NodeName: nodeName, } - class, claim, pod := startPausePod(cs, scTest, ns.Name) + nodeSelection := testsuites.NodeSelection{ + Name: nodeName, + } + class, claim, pod := startPausePod(cs, scTest, nodeSelection, ns.Name) if class != nil { defer cs.StorageV1().StorageClasses().Delete(class.Name, nil) } @@ -381,16 +383,16 @@ var _ = utils.SIGDescribe("CSI Volumes", func() { Parameters: sc.Parameters, ClaimSize: "1Gi", ExpectedSize: "1Gi", - // The mock driver only works when everything runs on a single node. - NodeName: nodeName, // Provisioner and storage class name must match what's used in // csi-storageclass.yaml, plus the test-specific suffix. Provisioner: sc.Provisioner, StorageClassName: "csi-mock-sc-" + f.UniqueName, - // Mock driver does not provide any persistency. - SkipWriteReadCheck: true, } - class, claim, pod := startPausePod(cs, scTest, ns.Name) + nodeSelection := testsuites.NodeSelection{ + // The mock driver only works when everything runs on a single node. + Name: nodeName, + } + class, claim, pod := startPausePod(cs, scTest, nodeSelection, ns.Name) if class != nil { defer cs.StorageV1().StorageClasses().Delete(class.Name, nil) } @@ -429,7 +431,7 @@ func testTopologyPositive(cs clientset.Interface, suffix, namespace string, dela claim.Spec.StorageClassName = &class.Name if delayBinding { - _, node := testsuites.TestBindingWaitForFirstConsumer(test, cs, claim, class) + _, node := testsuites.TestBindingWaitForFirstConsumer(test, cs, claim, class, nil /* node selector */, false /* expect unschedulable */) Expect(node).ToNot(BeNil(), "Unexpected nil node found") } else { testsuites.TestDynamicProvisioning(test, cs, claim, class) @@ -450,16 +452,22 @@ func testTopologyNegative(cs clientset.Interface, suffix, namespace string, dela test := createGCEPDStorageClassTest() test.DelayBinding = delayBinding - test.NodeSelector = map[string]string{v1.LabelZoneFailureDomain: podZone} - test.ExpectUnschedulable = true + nodeSelector := map[string]string{v1.LabelZoneFailureDomain: podZone} class := newStorageClass(test, namespace, suffix) addSingleCSIZoneAllowedTopologyToStorageClass(cs, class, pvZone) claim := newClaim(test, namespace, suffix) claim.Spec.StorageClassName = &class.Name if delayBinding { - testsuites.TestBindingWaitForFirstConsumer(test, cs, claim, class) + testsuites.TestBindingWaitForFirstConsumer(test, cs, claim, class, nodeSelector, true /* expect unschedulable */) } else { + test.PvCheck = func(claim *v1.PersistentVolumeClaim, volume *v1.PersistentVolume) { + // Ensure that a pod cannot be scheduled in an unsuitable zone. + pod := testsuites.StartInPodWithVolume(cs, namespace, claim.Name, "pvc-tester-unschedulable", "sleep 100000", + testsuites.NodeSelection{Selector: nodeSelector}) + defer testsuites.StopPod(cs, pod) + framework.ExpectNoError(framework.WaitForPodNameUnschedulableInNamespace(cs, pod.Name, pod.Namespace), "pod should be unschedulable") + } testsuites.TestDynamicProvisioning(test, cs, claim, class) } } @@ -500,7 +508,7 @@ func getVolumeHandle(cs clientset.Interface, claim *v1.PersistentVolumeClaim) st return pv.Spec.CSI.VolumeHandle } -func startPausePod(cs clientset.Interface, t testsuites.StorageClassTest, ns string) (*storagev1.StorageClass, *v1.PersistentVolumeClaim, *v1.Pod) { +func startPausePod(cs clientset.Interface, t testsuites.StorageClassTest, node testsuites.NodeSelection, ns string) (*storagev1.StorageClass, *v1.PersistentVolumeClaim, *v1.Pod) { class := newStorageClass(t, ns, "") class, err := cs.StorageV1().StorageClasses().Create(class) framework.ExpectNoError(err, "Failed to create class : %v", err) @@ -514,6 +522,9 @@ func startPausePod(cs clientset.Interface, t testsuites.StorageClassTest, ns str GenerateName: "pvc-volume-tester-", }, Spec: v1.PodSpec{ + NodeName: node.Name, + NodeSelector: node.Selector, + Affinity: node.Affinity, Containers: []v1.Container{ { Name: "volume-tester", @@ -541,9 +552,6 @@ func startPausePod(cs clientset.Interface, t testsuites.StorageClassTest, ns str }, } - if len(t.NodeName) != 0 { - pod.Spec.NodeName = t.NodeName - } pod, err = cs.CoreV1().Pods(ns).Create(pod) framework.ExpectNoError(err, "Failed to create pod: %v", err) return class, claim, pod diff --git a/test/e2e/storage/regional_pd.go b/test/e2e/storage/regional_pd.go index 176d380f88e..6673fedbe5e 100644 --- a/test/e2e/storage/regional_pd.go +++ b/test/e2e/storage/regional_pd.go @@ -108,12 +108,14 @@ func testVolumeProvisioning(c clientset.Interface, ns string) { }, ClaimSize: "1.5Gi", ExpectedSize: "2Gi", - PvCheck: func(volume *v1.PersistentVolume) error { - err := checkGCEPD(volume, "pd-standard") - if err != nil { - return err - } - return verifyZonesInPV(volume, sets.NewString(cloudZones...), true /* match */) + PvCheck: func(claim *v1.PersistentVolumeClaim, volume *v1.PersistentVolume) { + var err error + err = checkGCEPD(volume, "pd-standard") + Expect(err).NotTo(HaveOccurred(), "checkGCEPD") + err = verifyZonesInPV(volume, sets.NewString(cloudZones...), true /* match */) + Expect(err).NotTo(HaveOccurred(), "verifyZonesInPV") + + testsuites.PVWriteReadCheck(c, claim, volume, testsuites.NodeSelection{}) }, }, { @@ -126,16 +128,16 @@ func testVolumeProvisioning(c clientset.Interface, ns string) { }, ClaimSize: "1.5Gi", ExpectedSize: "2Gi", - PvCheck: func(volume *v1.PersistentVolume) error { - err := checkGCEPD(volume, "pd-standard") - if err != nil { - return err - } + PvCheck: func(claim *v1.PersistentVolumeClaim, volume *v1.PersistentVolume) { + var err error + err = checkGCEPD(volume, "pd-standard") + Expect(err).NotTo(HaveOccurred(), "checkGCEPD") zones, err := framework.GetClusterZones(c) - if err != nil { - return err - } - return verifyZonesInPV(volume, zones, false /* match */) + Expect(err).NotTo(HaveOccurred(), "GetClusterZones") + err = verifyZonesInPV(volume, zones, false /* match */) + Expect(err).NotTo(HaveOccurred(), "verifyZonesInPV") + + testsuites.PVWriteReadCheck(c, claim, volume, testsuites.NodeSelection{}) }, }, } @@ -317,7 +319,7 @@ func testRegionalDelayedBinding(c clientset.Interface, ns string, pvcCount int) claim.Spec.StorageClassName = &class.Name claims = append(claims, claim) } - pvs, node := testsuites.TestBindingWaitForFirstConsumerMultiPVC(test, c, claims, class) + pvs, node := testsuites.TestBindingWaitForFirstConsumerMultiPVC(test, c, claims, class, nil /* node selector */, false /* expect unschedulable */) if node == nil { framework.Failf("unexpected nil node found") } @@ -374,7 +376,7 @@ func testRegionalAllowedTopologiesWithDelayedBinding(c clientset.Interface, ns s claim.Spec.StorageClassName = &class.Name claims = append(claims, claim) } - pvs, node := testsuites.TestBindingWaitForFirstConsumerMultiPVC(test, c, claims, class) + pvs, node := testsuites.TestBindingWaitForFirstConsumerMultiPVC(test, c, claims, class, nil /* node selector */, false /* expect unschedulable */) if node == nil { framework.Failf("unexpected nil node found") } diff --git a/test/e2e/storage/testsuites/provisioning.go b/test/e2e/storage/testsuites/provisioning.go index 6f41c87cb2f..6ff13dcfa5b 100644 --- a/test/e2e/storage/testsuites/provisioning.go +++ b/test/e2e/storage/testsuites/provisioning.go @@ -37,22 +37,19 @@ import ( imageutils "k8s.io/kubernetes/test/utils/image" ) -// StorageClassTest represents parameters to be used by provisioning tests +// StorageClassTest represents parameters to be used by provisioning tests. +// Not all parameters are used by all tests. type StorageClassTest struct { - Name string - CloudProviders []string - Provisioner string - StorageClassName string - Parameters map[string]string - DelayBinding bool - ClaimSize string - ExpectedSize string - PvCheck func(volume *v1.PersistentVolume) error - NodeName string - SkipWriteReadCheck bool - VolumeMode *v1.PersistentVolumeMode - NodeSelector map[string]string // NodeSelector for the pod - ExpectUnschedulable bool // Whether the test pod is expected to be unschedulable + Name string + CloudProviders []string + Provisioner string + StorageClassName string + Parameters map[string]string + DelayBinding bool + ClaimSize string + ExpectedSize string + PvCheck func(claim *v1.PersistentVolumeClaim, volume *v1.PersistentVolume) + VolumeMode *v1.PersistentVolumeMode } type provisioningTestSuite struct { @@ -89,14 +86,14 @@ func createProvisioningTestInput(driver TestDriver, pattern testpatterns.TestPat testCase: StorageClassTest{ ClaimSize: resource.claimSize, ExpectedSize: resource.claimSize, - NodeName: driver.GetDriverInfo().Config.ClientNodeName, }, - cs: driver.GetDriverInfo().Config.Framework.ClientSet, - dc: driver.GetDriverInfo().Config.Framework.DynamicClient, - pvc: resource.pvc, - sc: resource.sc, - vsc: resource.vsc, - dInfo: driver.GetDriverInfo(), + cs: driver.GetDriverInfo().Config.Framework.ClientSet, + dc: driver.GetDriverInfo().Config.Framework.DynamicClient, + pvc: resource.pvc, + sc: resource.sc, + vsc: resource.vsc, + dInfo: driver.GetDriverInfo(), + nodeName: driver.GetDriverInfo().Config.ClientNodeName, } return resource, input @@ -179,10 +176,17 @@ type provisioningTestInput struct { sc *storage.StorageClass vsc *unstructured.Unstructured dInfo *DriverInfo + nodeName string } func testProvisioning(input *provisioningTestInput) { + // common checker for most of the test cases below + pvcheck := func(claim *v1.PersistentVolumeClaim, volume *v1.PersistentVolume) { + PVWriteReadCheck(input.cs, claim, volume, NodeSelection{Name: input.nodeName}) + } + It("should provision storage with defaults", func() { + input.testCase.PvCheck = pvcheck TestDynamicProvisioning(input.testCase, input.cs, input.pvc, input.sc) }) @@ -192,6 +196,7 @@ func testProvisioning(input *provisioningTestInput) { } input.sc.MountOptions = input.dInfo.SupportedMountOption.Union(input.dInfo.RequiredMountOption).List() + input.testCase.PvCheck = pvcheck TestDynamicProvisioning(input.testCase, input.cs, input.pvc, input.sc) }) @@ -201,7 +206,6 @@ func testProvisioning(input *provisioningTestInput) { } block := v1.PersistentVolumeBlock input.testCase.VolumeMode = &block - input.testCase.SkipWriteReadCheck = true input.pvc.Spec.VolumeMode = &block TestDynamicProvisioning(input.testCase, input.cs, input.pvc, input.sc) }) @@ -211,11 +215,15 @@ func testProvisioning(input *provisioningTestInput) { framework.Skipf("Driver %q does not support populate data from snapshot - skipping", input.dInfo.Name) } - input.testCase.SkipWriteReadCheck = true - dataSource, cleanupFunc := prepareDataSourceForProvisioning(input.testCase, input.cs, input.dc, input.pvc, input.sc, input.vsc) + dataSource, cleanupFunc := prepareDataSourceForProvisioning(NodeSelection{Name: input.nodeName}, input.cs, input.dc, input.pvc, input.sc, input.vsc) defer cleanupFunc() input.pvc.Spec.DataSource = dataSource + input.testCase.PvCheck = func(claim *v1.PersistentVolumeClaim, volume *v1.PersistentVolume) { + By("checking whether the created volume has the pre-populated data") + command := fmt.Sprintf("grep '%s' /mnt/test/initialData", claim.Namespace) + RunInPodWithVolume(input.cs, claim.Namespace, claim.Name, "pvc-snapshot-tester", command, NodeSelection{Name: input.nodeName}) + } TestDynamicProvisioning(input.testCase, input.cs, input.pvc, input.sc) }) } @@ -288,35 +296,7 @@ func TestDynamicProvisioning(t StorageClassTest, client clientset.Interface, cla // Run the checker if t.PvCheck != nil { - err = t.PvCheck(pv) - Expect(err).NotTo(HaveOccurred()) - } - - if claim.Spec.DataSource != nil { - By("checking the created volume whether has the pre-populated data") - command := fmt.Sprintf("grep '%s' /mnt/test/initialData", claim.Namespace) - runInPodWithVolume(client, claim.Namespace, claim.Name, "pvc-snapshot-reader", t.NodeName, command, t.NodeSelector, t.ExpectUnschedulable) - } - - if !t.SkipWriteReadCheck { - // We start two pods: - // - The first writes 'hello word' to the /mnt/test (= the volume). - // - The second one runs grep 'hello world' on /mnt/test. - // If both succeed, Kubernetes actually allocated something that is - // persistent across pods. - By("checking the created volume is writable and has the PV's mount options") - command := "echo 'hello world' > /mnt/test/data" - // We give the first pod the secondary responsibility of checking the volume has - // been mounted with the PV's mount options, if the PV was provisioned with any - for _, option := range pv.Spec.MountOptions { - // Get entry, get mount options at 6th word, replace brackets with commas - command += fmt.Sprintf(" && ( mount | grep 'on /mnt/test' | awk '{print $6}' | sed 's/^(/,/; s/)$/,/' | grep -q ,%s, )", option) - } - command += " || (mount | grep 'on /mnt/test'; false)" - runInPodWithVolume(client, claim.Namespace, claim.Name, "pvc-volume-tester-writer", t.NodeName, command, t.NodeSelector, t.ExpectUnschedulable) - - By("checking the created volume is readable and retains data") - runInPodWithVolume(client, claim.Namespace, claim.Name, "pvc-volume-tester-reader", t.NodeName, "grep 'hello world' /mnt/test/data", t.NodeSelector, t.ExpectUnschedulable) + t.PvCheck(claim, pv) } By(fmt.Sprintf("deleting claim %q/%q", claim.Namespace, claim.Name)) @@ -337,15 +317,41 @@ func TestDynamicProvisioning(t StorageClassTest, client clientset.Interface, cla return pv } -func TestBindingWaitForFirstConsumer(t StorageClassTest, client clientset.Interface, claim *v1.PersistentVolumeClaim, class *storage.StorageClass) (*v1.PersistentVolume, *v1.Node) { - pvs, node := TestBindingWaitForFirstConsumerMultiPVC(t, client, []*v1.PersistentVolumeClaim{claim}, class) +// PVWriteReadCheck checks that a PV retains data. +// +// It starts two pods: +// - The first writes 'hello word' to the /mnt/test (= the volume). +// - The second one runs grep 'hello world' on /mnt/test. +// If both succeed, Kubernetes actually allocated something that is +// persistent across pods. +// +// This is a common test that can be called from a StorageClassTest.PvCheck. +func PVWriteReadCheck(client clientset.Interface, claim *v1.PersistentVolumeClaim, volume *v1.PersistentVolume, node NodeSelection) { + By(fmt.Sprintf("checking the created volume is writable and has the PV's mount options on node %+v", node)) + command := "echo 'hello world' > /mnt/test/data" + // We give the first pod the secondary responsibility of checking the volume has + // been mounted with the PV's mount options, if the PV was provisioned with any + for _, option := range volume.Spec.MountOptions { + // Get entry, get mount options at 6th word, replace brackets with commas + command += fmt.Sprintf(" && ( mount | grep 'on /mnt/test' | awk '{print $6}' | sed 's/^(/,/; s/)$/,/' | grep -q ,%s, )", option) + } + command += " || (mount | grep 'on /mnt/test'; false)" + RunInPodWithVolume(client, claim.Namespace, claim.Name, "pvc-volume-tester-writer", command, node) + + By(fmt.Sprintf("checking the created volume is readable and retains data on the same node %+v", node)) + command = "grep 'hello world' /mnt/test/data" + RunInPodWithVolume(client, claim.Namespace, claim.Name, "pvc-volume-tester-reader", command, node) +} + +func TestBindingWaitForFirstConsumer(t StorageClassTest, client clientset.Interface, claim *v1.PersistentVolumeClaim, class *storage.StorageClass, nodeSelector map[string]string, expectUnschedulable bool) (*v1.PersistentVolume, *v1.Node) { + pvs, node := TestBindingWaitForFirstConsumerMultiPVC(t, client, []*v1.PersistentVolumeClaim{claim}, class, nodeSelector, expectUnschedulable) if pvs == nil { return nil, node } return pvs[0], node } -func TestBindingWaitForFirstConsumerMultiPVC(t StorageClassTest, client clientset.Interface, claims []*v1.PersistentVolumeClaim, class *storage.StorageClass) ([]*v1.PersistentVolume, *v1.Node) { +func TestBindingWaitForFirstConsumerMultiPVC(t StorageClassTest, client clientset.Interface, claims []*v1.PersistentVolumeClaim, class *storage.StorageClass, nodeSelector map[string]string, expectUnschedulable bool) ([]*v1.PersistentVolume, *v1.Node) { var err error Expect(len(claims)).ToNot(Equal(0)) namespace := claims[0].Namespace @@ -388,8 +394,8 @@ func TestBindingWaitForFirstConsumerMultiPVC(t StorageClassTest, client clientse By("creating a pod referring to the claims") // Create a pod referring to the claim and wait for it to get to running var pod *v1.Pod - if t.ExpectUnschedulable { - pod, err = framework.CreateUnschedulablePod(client, namespace, t.NodeSelector, createdClaims, true /* isPrivileged */, "" /* command */) + if expectUnschedulable { + pod, err = framework.CreateUnschedulablePod(client, namespace, nodeSelector, createdClaims, true /* isPrivileged */, "" /* command */) } else { pod, err = framework.CreatePod(client, namespace, nil /* nodeSelector */, createdClaims, true /* isPrivileged */, "" /* command */) } @@ -398,7 +404,7 @@ func TestBindingWaitForFirstConsumerMultiPVC(t StorageClassTest, client clientse framework.DeletePodOrFail(client, pod.Namespace, pod.Name) framework.WaitForPodToDisappear(client, pod.Namespace, pod.Name, labels.Everything(), framework.Poll, framework.PodDeleteTimeout) }() - if t.ExpectUnschedulable { + if expectUnschedulable { // Verify that no claims are provisioned. verifyPVCsPending(client, createdClaims) return nil, nil @@ -426,8 +432,25 @@ func TestBindingWaitForFirstConsumerMultiPVC(t StorageClassTest, client clientse return pvs, node } -// runInPodWithVolume runs a command in a pod with given claim mounted to /mnt directory. -func runInPodWithVolume(c clientset.Interface, ns, claimName, podName, nodeName, command string, nodeSelector map[string]string, unschedulable bool) { +// NodeSelection specifies where to run a pod, using a combination of fixed node name, +// node selector and/or affinity. +type NodeSelection struct { + Name string + Selector map[string]string + Affinity *v1.Affinity +} + +// RunInPodWithVolume runs a command in a pod with given claim mounted to /mnt directory. +// It starts, checks, collects output and stops it. +func RunInPodWithVolume(c clientset.Interface, ns, claimName, podName, command string, node NodeSelection) { + pod := StartInPodWithVolume(c, ns, claimName, podName, command, node) + defer StopPod(c, pod) + framework.ExpectNoError(framework.WaitForPodSuccessInNamespaceSlow(c, pod.Name, pod.Namespace)) +} + +// StartInPodWithVolume starts a command in a pod with given claim mounted to /mnt directory +// The caller is responsible for checking the pod and deleting it. +func StartInPodWithVolume(c clientset.Interface, ns, claimName, podName, command string, node NodeSelection) *v1.Pod { pod := &v1.Pod{ TypeMeta: metav1.TypeMeta{ Kind: "Pod", @@ -437,7 +460,9 @@ func runInPodWithVolume(c clientset.Interface, ns, claimName, podName, nodeName, GenerateName: podName + "-", }, Spec: v1.PodSpec{ - NodeName: nodeName, + NodeName: node.Name, + NodeSelector: node.Selector, + Affinity: node.Affinity, Containers: []v1.Container{ { Name: "volume-tester", @@ -464,27 +489,26 @@ func runInPodWithVolume(c clientset.Interface, ns, claimName, podName, nodeName, }, }, }, - NodeSelector: nodeSelector, }, } pod, err := c.CoreV1().Pods(ns).Create(pod) framework.ExpectNoError(err, "Failed to create pod: %v", err) - defer func() { - body, err := c.CoreV1().Pods(ns).GetLogs(pod.Name, &v1.PodLogOptions{}).Do().Raw() - if err != nil { - framework.Logf("Error getting logs for pod %s: %v", pod.Name, err) - } else { - framework.Logf("Pod %s has the following logs: %s", pod.Name, body) - } - framework.DeletePodOrFail(c, ns, pod.Name) - }() + return pod +} - if unschedulable { - framework.ExpectNoError(framework.WaitForPodNameUnschedulableInNamespace(c, pod.Name, pod.Namespace)) - } else { - framework.ExpectNoError(framework.WaitForPodSuccessInNamespaceSlow(c, pod.Name, pod.Namespace)) +// StopPod first tries to log the output of the pod's container, then deletes the pod. +func StopPod(c clientset.Interface, pod *v1.Pod) { + if pod == nil { + return } + body, err := c.CoreV1().Pods(pod.Namespace).GetLogs(pod.Name, &v1.PodLogOptions{}).Do().Raw() + if err != nil { + framework.Logf("Error getting logs for pod %s: %v", pod.Name, err) + } else { + framework.Logf("Pod %s has the following logs: %s", pod.Name, body) + } + framework.DeletePodOrFail(c, pod.Namespace, pod.Name) } func verifyPVCsPending(client clientset.Interface, pvcs []*v1.PersistentVolumeClaim) { @@ -497,7 +521,7 @@ func verifyPVCsPending(client clientset.Interface, pvcs []*v1.PersistentVolumeCl } func prepareDataSourceForProvisioning( - t StorageClassTest, + node NodeSelection, client clientset.Interface, dynamicClient dynamic.Interface, initClaim *v1.PersistentVolumeClaim, @@ -525,7 +549,7 @@ func prepareDataSourceForProvisioning( // write namespace to the /mnt/test (= the volume). By("[Initialize dataSource]write data to volume") command := fmt.Sprintf("echo '%s' > /mnt/test/initialData", updatedClaim.GetNamespace()) - runInPodWithVolume(client, updatedClaim.Namespace, updatedClaim.Name, "pvc-snapshot-writer", t.NodeName, command, t.NodeSelector, t.ExpectUnschedulable) + RunInPodWithVolume(client, updatedClaim.Namespace, updatedClaim.Name, "pvc-snapshot-writer", command, node) By("[Initialize dataSource]creating a SnapshotClass") snapshotClass, err = dynamicClient.Resource(snapshotClassGVR).Create(snapshotClass, metav1.CreateOptions{}) diff --git a/test/e2e/storage/volume_provisioning.go b/test/e2e/storage/volume_provisioning.go index 983c5070402..e5f840f344d 100644 --- a/test/e2e/storage/volume_provisioning.go +++ b/test/e2e/storage/volume_provisioning.go @@ -226,7 +226,7 @@ func testZonalDelayedBinding(c clientset.Interface, ns string, specifyAllowedTop claim.Spec.StorageClassName = &class.Name claims = append(claims, claim) } - pvs, node := testsuites.TestBindingWaitForFirstConsumerMultiPVC(test, c, claims, class) + pvs, node := testsuites.TestBindingWaitForFirstConsumerMultiPVC(test, c, claims, class, nil /* node selector */, false /* expect unschedulable */) if node == nil { framework.Failf("unexpected nil node found") } @@ -273,8 +273,10 @@ var _ = utils.SIGDescribe("Dynamic Provisioning", func() { }, ClaimSize: "1.5Gi", ExpectedSize: "2Gi", - PvCheck: func(volume *v1.PersistentVolume) error { - return checkGCEPD(volume, "pd-ssd") + PvCheck: func(claim *v1.PersistentVolumeClaim, volume *v1.PersistentVolume) { + err := checkGCEPD(volume, "pd-ssd") + Expect(err).NotTo(HaveOccurred(), "checkGCEPD pd-ssd") + testsuites.PVWriteReadCheck(c, claim, volume, testsuites.NodeSelection{}) }, }, { @@ -286,8 +288,10 @@ var _ = utils.SIGDescribe("Dynamic Provisioning", func() { }, ClaimSize: "1.5Gi", ExpectedSize: "2Gi", - PvCheck: func(volume *v1.PersistentVolume) error { - return checkGCEPD(volume, "pd-standard") + PvCheck: func(claim *v1.PersistentVolumeClaim, volume *v1.PersistentVolume) { + err := checkGCEPD(volume, "pd-standard") + Expect(err).NotTo(HaveOccurred(), "checkGCEPD pd-standard") + testsuites.PVWriteReadCheck(c, claim, volume, testsuites.NodeSelection{}) }, }, // AWS @@ -301,8 +305,10 @@ var _ = utils.SIGDescribe("Dynamic Provisioning", func() { }, ClaimSize: "1.5Gi", ExpectedSize: "2Gi", - PvCheck: func(volume *v1.PersistentVolume) error { - return checkAWSEBS(volume, "gp2", false) + PvCheck: func(claim *v1.PersistentVolumeClaim, volume *v1.PersistentVolume) { + err := checkAWSEBS(volume, "gp2", false) + Expect(err).NotTo(HaveOccurred(), "checkAWSEBS gp2") + testsuites.PVWriteReadCheck(c, claim, volume, testsuites.NodeSelection{}) }, }, { @@ -315,8 +321,10 @@ var _ = utils.SIGDescribe("Dynamic Provisioning", func() { }, ClaimSize: "3.5Gi", ExpectedSize: "4Gi", // 4 GiB is minimum for io1 - PvCheck: func(volume *v1.PersistentVolume) error { - return checkAWSEBS(volume, "io1", false) + PvCheck: func(claim *v1.PersistentVolumeClaim, volume *v1.PersistentVolume) { + err := checkAWSEBS(volume, "io1", false) + Expect(err).NotTo(HaveOccurred(), "checkAWSEBS io1") + testsuites.PVWriteReadCheck(c, claim, volume, testsuites.NodeSelection{}) }, }, { @@ -328,8 +336,10 @@ var _ = utils.SIGDescribe("Dynamic Provisioning", func() { }, ClaimSize: "500Gi", // minimum for sc1 ExpectedSize: "500Gi", - PvCheck: func(volume *v1.PersistentVolume) error { - return checkAWSEBS(volume, "sc1", false) + PvCheck: func(claim *v1.PersistentVolumeClaim, volume *v1.PersistentVolume) { + err := checkAWSEBS(volume, "sc1", false) + Expect(err).NotTo(HaveOccurred(), "checkAWSEBS sc1") + testsuites.PVWriteReadCheck(c, claim, volume, testsuites.NodeSelection{}) }, }, { @@ -341,8 +351,10 @@ var _ = utils.SIGDescribe("Dynamic Provisioning", func() { }, ClaimSize: "500Gi", // minimum for st1 ExpectedSize: "500Gi", - PvCheck: func(volume *v1.PersistentVolume) error { - return checkAWSEBS(volume, "st1", false) + PvCheck: func(claim *v1.PersistentVolumeClaim, volume *v1.PersistentVolume) { + err := checkAWSEBS(volume, "st1", false) + Expect(err).NotTo(HaveOccurred(), "checkAWSEBS st1") + testsuites.PVWriteReadCheck(c, claim, volume, testsuites.NodeSelection{}) }, }, { @@ -354,8 +366,10 @@ var _ = utils.SIGDescribe("Dynamic Provisioning", func() { }, ClaimSize: "1Gi", ExpectedSize: "1Gi", - PvCheck: func(volume *v1.PersistentVolume) error { - return checkAWSEBS(volume, "gp2", true) + PvCheck: func(claim *v1.PersistentVolumeClaim, volume *v1.PersistentVolume) { + err := checkAWSEBS(volume, "gp2", true) + Expect(err).NotTo(HaveOccurred(), "checkAWSEBS gp2 encrypted") + testsuites.PVWriteReadCheck(c, claim, volume, testsuites.NodeSelection{}) }, }, // OpenStack generic tests (works on all OpenStack deployments) @@ -366,7 +380,9 @@ var _ = utils.SIGDescribe("Dynamic Provisioning", func() { Parameters: map[string]string{}, ClaimSize: "1.5Gi", ExpectedSize: "2Gi", - PvCheck: nil, // there is currently nothing to check on OpenStack + PvCheck: func(claim *v1.PersistentVolumeClaim, volume *v1.PersistentVolume) { + testsuites.PVWriteReadCheck(c, claim, volume, testsuites.NodeSelection{}) + }, }, { Name: "Cinder volume with empty volume type and zone on OpenStack", @@ -378,7 +394,9 @@ var _ = utils.SIGDescribe("Dynamic Provisioning", func() { }, ClaimSize: "1.5Gi", ExpectedSize: "2Gi", - PvCheck: nil, // there is currently nothing to check on OpenStack + PvCheck: func(claim *v1.PersistentVolumeClaim, volume *v1.PersistentVolume) { + testsuites.PVWriteReadCheck(c, claim, volume, testsuites.NodeSelection{}) + }, }, // vSphere generic test { @@ -388,7 +406,9 @@ var _ = utils.SIGDescribe("Dynamic Provisioning", func() { Parameters: map[string]string{}, ClaimSize: "1.5Gi", ExpectedSize: "1.5Gi", - PvCheck: nil, + PvCheck: func(claim *v1.PersistentVolumeClaim, volume *v1.PersistentVolume) { + testsuites.PVWriteReadCheck(c, claim, volume, testsuites.NodeSelection{}) + }, }, // Azure { @@ -398,7 +418,9 @@ var _ = utils.SIGDescribe("Dynamic Provisioning", func() { Parameters: map[string]string{}, ClaimSize: "1Gi", ExpectedSize: "1Gi", - PvCheck: nil, + PvCheck: func(claim *v1.PersistentVolumeClaim, volume *v1.PersistentVolume) { + testsuites.PVWriteReadCheck(c, claim, volume, testsuites.NodeSelection{}) + }, }, } @@ -451,8 +473,10 @@ var _ = utils.SIGDescribe("Dynamic Provisioning", func() { }, ClaimSize: "1Gi", ExpectedSize: "1Gi", - PvCheck: func(volume *v1.PersistentVolume) error { - return checkGCEPD(volume, "pd-standard") + PvCheck: func(claim *v1.PersistentVolumeClaim, volume *v1.PersistentVolume) { + err := checkGCEPD(volume, "pd-standard") + Expect(err).NotTo(HaveOccurred(), "checkGCEPD") + testsuites.PVWriteReadCheck(c, claim, volume, testsuites.NodeSelection{}) }, } class := newStorageClass(test, ns, "reclaimpolicy") @@ -793,12 +817,11 @@ var _ = utils.SIGDescribe("Dynamic Provisioning", func() { serverUrl := "https://" + pod.Status.PodIP + ":8081" By("creating a StorageClass") test := testsuites.StorageClassTest{ - Name: "Gluster Dynamic provisioner test", - Provisioner: "kubernetes.io/glusterfs", - ClaimSize: "2Gi", - ExpectedSize: "2Gi", - Parameters: map[string]string{"resturl": serverUrl}, - SkipWriteReadCheck: true, + Name: "Gluster Dynamic provisioner test", + Provisioner: "kubernetes.io/glusterfs", + ClaimSize: "2Gi", + ExpectedSize: "2Gi", + Parameters: map[string]string{"resturl": serverUrl}, } suffix := fmt.Sprintf("glusterdptest") class := newStorageClass(test, ns, suffix)