From b550134dfea7333fafdbe982108f3d033cd8df6b Mon Sep 17 00:00:00 2001 From: Humble Chirammal Date: Fri, 20 Apr 2018 01:44:13 +0530 Subject: [PATCH] This bring up a heketi server pod and the server will be running in mock mode, the PVC creation should work, however the volume attachment to a pod and read/write is not part of this test. Due to the same reason the tests are marked as [fast]. Signed-off-by: Humble Chirammal --- test/e2e/storage/volume_provisioning.go | 121 ++++++++++++++++++++---- 1 file changed, 100 insertions(+), 21 deletions(-) diff --git a/test/e2e/storage/volume_provisioning.go b/test/e2e/storage/volume_provisioning.go index 17111d696e2..fab9b12fd00 100644 --- a/test/e2e/storage/volume_provisioning.go +++ b/test/e2e/storage/volume_provisioning.go @@ -56,6 +56,7 @@ type storageClassTest struct { expectedSize string pvCheck func(volume *v1.PersistentVolume) error nodeName string + attach bool } const ( @@ -98,10 +99,14 @@ func testDynamicProvisioning(t storageClassTest, client clientset.Interface, cla pv, err := client.CoreV1().PersistentVolumes().Get(claim.Spec.VolumeName, metav1.GetOptions{}) Expect(err).NotTo(HaveOccurred()) - // Check sizes - expectedCapacity := resource.MustParse(t.expectedSize) - pvCapacity := pv.Spec.Capacity[v1.ResourceName(v1.ResourceStorage)] - Expect(pvCapacity.Value()).To(Equal(expectedCapacity.Value()), "pvCapacity is not equal to expectedCapacity") + if class.Provisioner == "kubernetes.io/glusterfs" && framework.ProviderIs("gke", "gce") { + framework.Logf("Skipping glusterfs dynamic test for cloud provider %v", "GCE/GKE") + } else { + // Check sizes + expectedCapacity := resource.MustParse(t.expectedSize) + pvCapacity := pv.Spec.Capacity[v1.ResourceName(v1.ResourceStorage)] + Expect(pvCapacity.Value()).To(Equal(expectedCapacity.Value()), "pvCapacity is not equal to expectedCapacity") + } requestedCapacity := resource.MustParse(t.claimSize) claimCapacity := claim.Spec.Resources.Requests[v1.ResourceName(v1.ResourceStorage)] @@ -126,24 +131,25 @@ func testDynamicProvisioning(t storageClassTest, client clientset.Interface, cla Expect(err).NotTo(HaveOccurred()) } - // 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) + if t.attach { + // 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) + } + runInPodWithVolume(client, claim.Namespace, claim.Name, t.nodeName, command) + + By("checking the created volume is readable and retains data") + runInPodWithVolume(client, claim.Namespace, claim.Name, t.nodeName, "grep 'hello world' /mnt/test/data") } - runInPodWithVolume(client, claim.Namespace, claim.Name, t.nodeName, command) - - By("checking the created volume is readable and retains data") - runInPodWithVolume(client, claim.Namespace, claim.Name, t.nodeName, "grep 'hello world' /mnt/test/data") - By(fmt.Sprintf("deleting claim %q/%q", claim.Namespace, claim.Name)) framework.ExpectNoError(client.CoreV1().PersistentVolumeClaims(claim.Namespace).Delete(claim.Name, nil)) @@ -783,6 +789,30 @@ var _ = utils.SIGDescribe("Dynamic Provisioning", func() { Expect(claim.Status.Phase).To(Equal(v1.ClaimPending)) }) }) + + framework.KubeDescribe("GlusterDynamicProvisioner", func() { + It("should create and delete persistent volumes [fast]", func() { + By("creating a Gluster DP server Pod") + pod := startGlusterDpServerPod(c, ns) + serverUrl := "https://" + pod.Status.PodIP + ":8081" + By("creating a StorageClass") + test := storageClassTest{ + name: "Gluster Dynamic provisioner test", + provisioner: "kubernetes.io/glusterfs", + claimSize: "2Gi", + expectedSize: "2Gi", + parameters: map[string]string{"resturl": serverUrl}, + attach: false, + } + suffix := fmt.Sprintf("glusterdptest") + class := newStorageClass(test, ns, suffix) + + By("creating a claim object with a suffix for gluster dynamic provisioner") + claim := newClaim(test, ns, suffix) + + testDynamicProvisioning(test, c, claim, class) + }) + }) }) func getDefaultStorageClassName(c clientset.Interface) string { @@ -969,6 +999,55 @@ func newBetaStorageClass(t storageClassTest, suffix string) *storagebeta.Storage } } +func startGlusterDpServerPod(c clientset.Interface, ns string) *v1.Pod { + podClient := c.CoreV1().Pods(ns) + + provisionerPod := &v1.Pod{ + TypeMeta: metav1.TypeMeta{ + Kind: "Pod", + APIVersion: "v1", + }, + ObjectMeta: metav1.ObjectMeta{ + GenerateName: "glusterdynamic-provisioner-", + }, + + Spec: v1.PodSpec{ + Containers: []v1.Container{ + { + Name: "glusterdynamic-provisioner", + Image: "docker.io/humblec/glusterdynamic-provisioner:v1.0", + Args: []string{ + "-config=" + "/etc/heketi/heketi.json", + }, + Ports: []v1.ContainerPort{ + {Name: "heketi", ContainerPort: 8081}, + }, + Env: []v1.EnvVar{ + { + Name: "POD_IP", + ValueFrom: &v1.EnvVarSource{ + FieldRef: &v1.ObjectFieldSelector{ + FieldPath: "status.podIP", + }, + }, + }, + }, + ImagePullPolicy: v1.PullIfNotPresent, + }, + }, + }, + } + provisionerPod, err := podClient.Create(provisionerPod) + framework.ExpectNoError(err, "Failed to create %s pod: %v", provisionerPod.Name, err) + + framework.ExpectNoError(framework.WaitForPodRunningInNamespace(c, provisionerPod)) + + By("locating the provisioner pod") + pod, err := podClient.Get(provisionerPod.Name, metav1.GetOptions{}) + framework.ExpectNoError(err, "Cannot locate the provisioner pod %v: %v", provisionerPod.Name, err) + return pod +} + func startExternalProvisioner(c clientset.Interface, ns string) *v1.Pod { podClient := c.CoreV1().Pods(ns)