// Wait for the pv and pvc to bind to each other. func waitOnPVandPVC(c clientset.Interface, ns string, pv *v1.PersistentVolume, pvc *v1.PersistentVolumeClaim) { // Wait for newly created PVC to bind to the PV framework.Logf("Waiting for PV %v to bind to PVC %v", pv.Name, pvc.Name) err := framework.WaitForPersistentVolumeClaimPhase(v1.ClaimBound, c, ns, pvc.Name, 3*time.Second, 300*time.Second) Expect(err).NotTo(HaveOccurred()) // Wait for PersistentVolume.Status.Phase to be Bound, which it should be // since the PVC is already bound. err = framework.WaitForPersistentVolumePhase(v1.VolumeBound, c, pv.Name, 3*time.Second, 300*time.Second) Expect(err).NotTo(HaveOccurred()) // Re-get the pv and pvc objects pv, err = c.Core().PersistentVolumes().Get(pv.Name, metav1.GetOptions{}) Expect(err).NotTo(HaveOccurred()) // Re-get the pvc and pvc, err = c.Core().PersistentVolumeClaims(ns).Get(pvc.Name, metav1.GetOptions{}) Expect(err).NotTo(HaveOccurred()) // The pv and pvc are both bound, but to each other? // Check that the PersistentVolume.ClaimRef matches the PVC Expect(pv.Spec.ClaimRef).NotTo(BeNil()) Expect(pv.Spec.ClaimRef.Name).To(Equal(pvc.Name)) Expect(pvc.Spec.VolumeName).To(Equal(pv.Name)) Expect(pv.Spec.ClaimRef.UID).To(Equal(pvc.UID)) }
// Delete the PVC and wait for the PV to become Available again. Validate that the PV // has recycled (assumption here about reclaimPolicy). Caller tells this func which // phase value to expect for the pv bound to the to-be-deleted claim. func deletePVCandValidatePV(c clientset.Interface, ns string, pvc *v1.PersistentVolumeClaim, pv *v1.PersistentVolume, expctPVPhase v1.PersistentVolumePhase) { pvname := pvc.Spec.VolumeName framework.Logf("Deleting PVC %v to trigger recycling of PV %v", pvc.Name, pvname) deletePersistentVolumeClaim(c, pvc.Name, ns) // Check that the PVC is really deleted. pvc, err := c.Core().PersistentVolumeClaims(ns).Get(pvc.Name, metav1.GetOptions{}) Expect(apierrs.IsNotFound(err)).To(BeTrue()) // Wait for the PV's phase to return to Available framework.Logf("Waiting for recycling process to complete.") err = framework.WaitForPersistentVolumePhase(expctPVPhase, c, pv.Name, 1*time.Second, 300*time.Second) Expect(err).NotTo(HaveOccurred()) // examine the pv's ClaimRef and UID and compare to expected values pv, err = c.Core().PersistentVolumes().Get(pv.Name, metav1.GetOptions{}) Expect(err).NotTo(HaveOccurred()) cr := pv.Spec.ClaimRef if expctPVPhase == v1.VolumeAvailable { if cr != nil { // may be ok if cr != nil Expect(len(cr.UID)).To(BeZero()) } } else if expctPVPhase == v1.VolumeBound { Expect(cr).NotTo(BeNil()) Expect(len(cr.UID)).NotTo(BeZero()) } framework.Logf("PV %v now in %q phase", pv.Name, expctPVPhase) }
// Wait for the pv and pvc to bind to each other. Fail test on errors. func waitOnPVandPVC(c *client.Client, ns string, pv *api.PersistentVolume, pvc *api.PersistentVolumeClaim) error { // Wait for newly created PVC to bind to the PV framework.Logf("Waiting for PV %v to bind to PVC %v", pv.Name, pvc.Name) err := framework.WaitForPersistentVolumeClaimPhase(api.ClaimBound, c, ns, pvc.Name, 3*time.Second, 300*time.Second) if err != nil { return fmt.Errorf("PersistentVolumeClaim failed to enter a bound state: %+v", err) } // Wait for PersistentVolume.Status.Phase to be Bound, which it should be // since the PVC is already bound. err = framework.WaitForPersistentVolumePhase(api.VolumeBound, c, pv.Name, 3*time.Second, 300*time.Second) if err != nil { return fmt.Errorf("PersistentVolume failed to enter a bound state even though PVC is Bound: %+v", err) } return nil }
// Delete the PVC and wait for the PV to become Available again. // Validate that the PV has recycled (assumption here about reclaimPolicy). func deletePVCandValidatePV(c *client.Client, ns string, pvc *api.PersistentVolumeClaim, pv *api.PersistentVolume) (*api.PersistentVolume, *api.PersistentVolumeClaim, error) { By("Deleting PersistentVolumeClaim to trigger PV Recycling") framework.Logf("Deleting PersistentVolumeClaim %v to trigger PV Recycling", pvc.Name) err := c.PersistentVolumeClaims(ns).Delete(pvc.Name) if err != nil { return pv, pvc, fmt.Errorf("Delete of PVC %v failed: %v", pvc.Name, err) } // Check that the PVC is really deleted. pvc, err = c.PersistentVolumeClaims(ns).Get(pvc.Name) if err == nil { return pv, pvc, fmt.Errorf("PVC %v deleted yet still exists", pvc.Name) } if !apierrs.IsNotFound(err) { return pv, pvc, fmt.Errorf("Get on deleted PVC %v failed with error other than \"not found\": %v", pvc.Name, err) } // Wait for the PV's phase to return to Available framework.Logf("Waiting for recycling process to complete.") err = framework.WaitForPersistentVolumePhase(api.VolumeAvailable, c, pv.Name, 3*time.Second, 300*time.Second) if err != nil { return pv, pvc, fmt.Errorf("Recycling failed: %v", err) } // Examine the pv.ClaimRef and UID. Expect nil values. pv, err = c.PersistentVolumes().Get(pv.Name) if err != nil { return pv, pvc, fmt.Errorf("Cannot re-get PersistentVolume %v:", pv.Name) } if pv.Spec.ClaimRef != nil && len(pv.Spec.ClaimRef.UID) > 0 { crJSON, _ := json.Marshal(pv.Spec.ClaimRef) return pv, pvc, fmt.Errorf("Expected PV %v's ClaimRef to be nil, or the claimRef's UID to be blank. Instead claimRef is: %v", pv.Name, string(crJSON)) } return pv, pvc, nil }
// Search for bound PVs and PVCs by examining pvols for non-nil claimRefs. // NOTE: Each iteration waits for a maximum of 3 minutes per PV and, if the PV is bound, // up to 3 minutes for the PVC. When the number of PVs != number of PVCs, this can lead // to situations where the maximum wait times are reached several times in succession, // extending test time. Thus, it is recommended to keep the delta between PVs and PVCs // small. func waitAndVerifyBinds(c clientset.Interface, ns string, pvols pvmap, claims pvcmap, testExpected bool) { var actualBinds int expectedBinds := len(pvols) if expectedBinds > len(claims) { // want the min of # pvs or #pvcs expectedBinds = len(claims) } for pvName := range pvols { err := framework.WaitForPersistentVolumePhase(v1.VolumeBound, c, pvName, 3*time.Second, 180*time.Second) if err != nil && len(pvols) > len(claims) { framework.Logf("WARN: pv %v is not bound after max wait", pvName) framework.Logf(" This may be ok since there are more pvs than pvcs") continue } Expect(err).NotTo(HaveOccurred()) pv, err := c.Core().PersistentVolumes().Get(pvName, metav1.GetOptions{}) Expect(err).NotTo(HaveOccurred()) if cr := pv.Spec.ClaimRef; cr != nil && len(cr.Name) > 0 { // Assert bound pvc is a test resource. Failing assertion could // indicate non-test PVC interference or a bug in the test pvcKey := makePvcKey(ns, cr.Name) _, found := claims[pvcKey] Expect(found).To(BeTrue()) err = framework.WaitForPersistentVolumeClaimPhase(v1.ClaimBound, c, ns, cr.Name, 3*time.Second, 180*time.Second) Expect(err).NotTo(HaveOccurred()) actualBinds++ } } if testExpected { Expect(actualBinds).To(Equal(expectedBinds)) } }
serverIP := pod.Status.PodIP framework.Logf("NFS server IP address: %v", serverIP) pv := makePersistentVolume(serverIP) pvc := makePersistentVolumeClaim(ns) framework.Logf("Creating PersistentVolume using NFS") pv, err := c.PersistentVolumes().Create(pv) Expect(err).NotTo(HaveOccurred()) framework.Logf("Creating PersistentVolumeClaim") pvc, err = c.PersistentVolumeClaims(ns).Create(pvc) Expect(err).NotTo(HaveOccurred()) // allow the binder a chance to catch up. should not be more than 20s. framework.WaitForPersistentVolumePhase(api.VolumeBound, c, pv.Name, 1*time.Second, 30*time.Second) pv, err = c.PersistentVolumes().Get(pv.Name) Expect(err).NotTo(HaveOccurred()) if pv.Spec.ClaimRef == nil { framework.Failf("Expected PersistentVolume to be bound, but got nil ClaimRef: %+v", pv) } framework.Logf("Deleting PersistentVolumeClaim to trigger PV Recycling") err = c.PersistentVolumeClaims(ns).Delete(pvc.Name) Expect(err).NotTo(HaveOccurred()) // allow the recycler a chance to catch up. it has to perform NFS scrub, which can be slow in e2e. framework.WaitForPersistentVolumePhase(api.VolumeAvailable, c, pv.Name, 5*time.Second, 300*time.Second) pv, err = c.PersistentVolumes().Get(pv.Name)