func deletePersistentVolume(c *client.Client, pv *api.PersistentVolume) { // Delete the PersistentVolume framework.Logf("Deleting PersistentVolume") err := c.PersistentVolumes().Delete(pv.Name) if err != nil { framework.Failf("Delete PersistentVolume failed: %v", err) } // Wait for PersistentVolume to Delete framework.WaitForPersistentVolumeDeleted(c, pv.Name, 3*time.Second, 30*time.Second) }
func testDynamicProvisioning(client clientset.Interface, claim *v1.PersistentVolumeClaim) { err := framework.WaitForPersistentVolumeClaimPhase(v1.ClaimBound, client, claim.Namespace, claim.Name, framework.Poll, framework.ClaimProvisionTimeout) Expect(err).NotTo(HaveOccurred()) By("checking the claim") // Get new copy of the claim claim, err = client.Core().PersistentVolumeClaims(claim.Namespace).Get(claim.Name, metav1.GetOptions{}) Expect(err).NotTo(HaveOccurred()) // Get the bound PV pv, err := client.Core().PersistentVolumes().Get(claim.Spec.VolumeName, metav1.GetOptions{}) Expect(err).NotTo(HaveOccurred()) // Check sizes expectedCapacity := resource.MustParse(expectedSize) pvCapacity := pv.Spec.Capacity[v1.ResourceName(v1.ResourceStorage)] Expect(pvCapacity.Value()).To(Equal(expectedCapacity.Value())) requestedCapacity := resource.MustParse(requestedSize) claimCapacity := claim.Spec.Resources.Requests[v1.ResourceName(v1.ResourceStorage)] Expect(claimCapacity.Value()).To(Equal(requestedCapacity.Value())) // Check PV properties Expect(pv.Spec.PersistentVolumeReclaimPolicy).To(Equal(v1.PersistentVolumeReclaimDelete)) expectedAccessModes := []v1.PersistentVolumeAccessMode{v1.ReadWriteOnce} Expect(pv.Spec.AccessModes).To(Equal(expectedAccessModes)) Expect(pv.Spec.ClaimRef.Name).To(Equal(claim.ObjectMeta.Name)) Expect(pv.Spec.ClaimRef.Namespace).To(Equal(claim.ObjectMeta.Namespace)) // 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") runInPodWithVolume(client, claim.Namespace, claim.Name, "echo 'hello world' > /mnt/test/data") By("checking the created volume is readable and retains data") runInPodWithVolume(client, claim.Namespace, claim.Name, "grep 'hello world' /mnt/test/data") By("deleting the claim") framework.ExpectNoError(client.Core().PersistentVolumeClaims(claim.Namespace).Delete(claim.Name, nil)) // Wait for the PV to get deleted. Technically, the first few delete // attempts may fail, as the volume is still attached to a node because // kubelet is slowly cleaning up a pod, however it should succeed in a // couple of minutes. Wait 20 minutes to recover from random cloud hiccups. framework.ExpectNoError(framework.WaitForPersistentVolumeDeleted(client, pv.Name, 5*time.Second, 20*time.Minute)) }
// Delete the PV. Fail test if delete fails. If success the returned PV should // be nil, which prevents the AfterEach from attempting to delete it. func deletePersistentVolume(c *client.Client, pv *api.PersistentVolume) (*api.PersistentVolume, error) { if pv == nil { return nil, fmt.Errorf("PV to be deleted is nil") } framework.Logf("Deleting PersistentVolume %v", pv.Name) err := c.PersistentVolumes().Delete(pv.Name) if err != nil { return pv, fmt.Errorf("Delete() PersistentVolume %v failed: %v", pv.Name, err) } // Wait for PersistentVolume to delete deleteDuration := 90 * time.Second err = framework.WaitForPersistentVolumeDeleted(c, pv.Name, 3*time.Second, deleteDuration) if err != nil { return pv, fmt.Errorf("Unable to delete PersistentVolume %s after waiting for %v: %v", pv.Name, deleteDuration, err) } return nil, nil // success }
func testDynamicProvisioning(client clientset.Interface, claim *api.PersistentVolumeClaim) { err := framework.WaitForPersistentVolumeClaimPhase(api.ClaimBound, client, claim.Namespace, claim.Name, framework.Poll, framework.ClaimProvisionTimeout) Expect(err).NotTo(HaveOccurred()) By("checking the claim") // Get new copy of the claim claim, err = client.Core().PersistentVolumeClaims(claim.Namespace).Get(claim.Name) Expect(err).NotTo(HaveOccurred()) // Get the bound PV pv, err := client.Core().PersistentVolumes().Get(claim.Spec.VolumeName) Expect(err).NotTo(HaveOccurred()) // Check sizes expectedCapacity := resource.MustParse(expectedSize) pvCapacity := pv.Spec.Capacity[api.ResourceName(api.ResourceStorage)] Expect(pvCapacity.Value()).To(Equal(expectedCapacity.Value())) requestedCapacity := resource.MustParse(requestedSize) claimCapacity := claim.Spec.Resources.Requests[api.ResourceName(api.ResourceStorage)] Expect(claimCapacity.Value()).To(Equal(requestedCapacity.Value())) // Check PV properties Expect(pv.Spec.PersistentVolumeReclaimPolicy).To(Equal(api.PersistentVolumeReclaimDelete)) expectedAccessModes := []api.PersistentVolumeAccessMode{api.ReadWriteOnce} Expect(pv.Spec.AccessModes).To(Equal(expectedAccessModes)) Expect(pv.Spec.ClaimRef.Name).To(Equal(claim.ObjectMeta.Name)) Expect(pv.Spec.ClaimRef.Namespace).To(Equal(claim.ObjectMeta.Namespace)) // 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") runInPodWithVolume(client, claim.Namespace, claim.Name, "echo 'hello world' > /mnt/test/data") By("checking the created volume is readable and retains data") runInPodWithVolume(client, claim.Namespace, claim.Name, "grep 'hello world' /mnt/test/data") // Ugly hack: if we delete the AWS/GCE/OpenStack volume here, it will // probably collide with destruction of the pods above - the pods // still have the volume attached (kubelet is slow...) and deletion // of attached volume is not allowed by AWS/GCE/OpenStack. // Kubernetes *will* retry deletion several times in // pvclaimbinder-sync-period. // So, technically, this sleep is not needed. On the other hand, // the sync perion is 10 minutes and we really don't want to wait // 10 minutes here. There is no way how to see if kubelet is // finished with cleaning volumes. A small sleep here actually // speeds up the test! // Three minutes should be enough to clean up the pods properly. // We've seen GCE PD detach to take more than 1 minute. By("Sleeping to let kubelet destroy all pods") time.Sleep(3 * time.Minute) By("deleting the claim") framework.ExpectNoError(client.Core().PersistentVolumeClaims(claim.Namespace).Delete(claim.Name, nil)) // Wait for the PV to get deleted too. framework.ExpectNoError(framework.WaitForPersistentVolumeDeleted(client, pv.Name, 5*time.Second, 20*time.Minute)) }
// pvclaimbinder-sync-period. // So, technically, this sleep is not needed. On the other hand, // the sync perion is 10 minutes and we really don't want to wait // 10 minutes here. There is no way how to see if kubelet is // finished with cleaning volumes. A small sleep here actually // speeds up the test! // Three minutes should be enough to clean up the pods properly. // We've seen GCE PD detach to take more than 1 minute. By("Sleeping to let kubelet destroy all pods") time.Sleep(3 * time.Minute) By("deleting the claim") framework.ExpectNoError(c.PersistentVolumeClaims(ns).Delete(claim.Name)) // Wait for the PV to get deleted too. framework.ExpectNoError(framework.WaitForPersistentVolumeDeleted(c, pv.Name, 5*time.Second, 20*time.Minute)) }) }) }) func createClaim(ns string) *api.PersistentVolumeClaim { return &api.PersistentVolumeClaim{ ObjectMeta: api.ObjectMeta{ GenerateName: "pvc-", Namespace: ns, Annotations: map[string]string{ "volume.alpha.kubernetes.io/storage-class": "", }, }, Spec: api.PersistentVolumeClaimSpec{ AccessModes: []api.PersistentVolumeAccessMode{