improve error handling in e2e helpers by always returning error

This commit is contained in:
Jeff Vance 2017-03-31 21:42:52 -07:00
parent 55042b0ba9
commit 0d81e4c87c
16 changed files with 481 additions and 325 deletions

View File

@ -26,7 +26,6 @@ import (
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/ec2"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"google.golang.org/api/googleapi"
apierrs "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/api/resource"
@ -92,93 +91,133 @@ type PersistentVolumeClaimConfig struct {
}
// Clean up a pv and pvc in a single pv/pvc test case.
func PVPVCCleanup(c clientset.Interface, ns string, pv *v1.PersistentVolume, pvc *v1.PersistentVolumeClaim) {
DeletePersistentVolumeClaim(c, pvc.Name, ns)
DeletePersistentVolume(c, pv.Name)
// Note: delete errors are appended to []error so that we can attempt to delete both the pvc and pv.
func PVPVCCleanup(c clientset.Interface, ns string, pv *v1.PersistentVolume, pvc *v1.PersistentVolumeClaim) []error {
var errs []error
if pvc != nil {
err := DeletePersistentVolumeClaim(c, pvc.Name, ns)
if err != nil {
errs = append(errs, fmt.Errorf("failed to delete PVC %q: %v", pvc.Name, err))
}
} else {
Logf("pvc is nil")
}
if pv != nil {
err := DeletePersistentVolume(c, pv.Name)
if err != nil {
errs = append(errs, fmt.Errorf("failed to delete PV %q: %v", pv.Name, err))
}
} else {
Logf("pv is nil")
}
return errs
}
// Clean up pvs and pvcs in multi-pv-pvc test cases. All entries found in the pv and
// claims maps are deleted.
func PVPVCMapCleanup(c clientset.Interface, ns string, pvols PVMap, claims PVCMap) {
// Clean up pvs and pvcs in multi-pv-pvc test cases. Entries found in the pv and claim maps are
// deleted as long as the Delete api call succeeds.
// Note: delete errors are appended to []error so that as many pvcs and pvs as possible are deleted.
func PVPVCMapCleanup(c clientset.Interface, ns string, pvols PVMap, claims PVCMap) []error {
var errs []error
for pvcKey := range claims {
DeletePersistentVolumeClaim(c, pvcKey.Name, ns)
delete(claims, pvcKey)
err := DeletePersistentVolumeClaim(c, pvcKey.Name, ns)
if err != nil {
errs = append(errs, fmt.Errorf("failed to delete PVC %q: %v", pvcKey.Name, err))
} else {
delete(claims, pvcKey)
}
}
for pvKey := range pvols {
DeletePersistentVolume(c, pvKey)
delete(pvols, pvKey)
err := DeletePersistentVolume(c, pvKey)
if err != nil {
errs = append(errs, fmt.Errorf("failed to delete PV %q: %v", pvKey, err))
} else {
delete(pvols, pvKey)
}
}
return errs
}
// Delete the PV.
func DeletePersistentVolume(c clientset.Interface, pvName string) {
func DeletePersistentVolume(c clientset.Interface, pvName string) error {
if c != nil && len(pvName) > 0 {
Logf("Deleting PersistentVolume %v", pvName)
Logf("Deleting PersistentVolume %q", pvName)
err := c.CoreV1().PersistentVolumes().Delete(pvName, nil)
if err != nil && !apierrs.IsNotFound(err) {
Expect(err).NotTo(HaveOccurred())
return fmt.Errorf("PV Delete API error: %v", err)
}
}
return nil
}
// Delete the Claim
func DeletePersistentVolumeClaim(c clientset.Interface, pvcName string, ns string) {
func DeletePersistentVolumeClaim(c clientset.Interface, pvcName string, ns string) error {
if c != nil && len(pvcName) > 0 {
Logf("Deleting PersistentVolumeClaim %v", pvcName)
Logf("Deleting PersistentVolumeClaim %q", pvcName)
err := c.CoreV1().PersistentVolumeClaims(ns).Delete(pvcName, nil)
if err != nil && !apierrs.IsNotFound(err) {
Expect(err).NotTo(HaveOccurred())
return fmt.Errorf("PVC Delete API error: %v", err)
}
}
return nil
}
// Delete the PVC and wait for the PV to enter its expected phase. Validate that the PV
// has been reclaimed (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, expectPVPhase v1.PersistentVolumePhase) {
func DeletePVCandValidatePV(c clientset.Interface, ns string, pvc *v1.PersistentVolumeClaim, pv *v1.PersistentVolume, expectPVPhase v1.PersistentVolumePhase) error {
pvname := pvc.Spec.VolumeName
Logf("Deleting PVC %v to trigger reclamation of PV %v", pvc.Name, pvname)
DeletePersistentVolumeClaim(c, pvc.Name, ns)
// Check that the PVC is really deleted.
pvc, err := c.CoreV1().PersistentVolumeClaims(ns).Get(pvc.Name, metav1.GetOptions{})
Expect(apierrs.IsNotFound(err)).To(BeTrue())
err := DeletePersistentVolumeClaim(c, pvc.Name, ns)
if err != nil {
return err
}
// Wait for the PV's phase to return to be `expectPVPhase`
Logf("Waiting for reclaim process to complete.")
err = WaitForPersistentVolumePhase(expectPVPhase, c, pv.Name, 1*time.Second, 300*time.Second)
Expect(err).NotTo(HaveOccurred())
if err != nil {
return fmt.Errorf("pv %q phase did not become %v: %v", pv.Name, expectPVPhase, err)
}
// examine the pv's ClaimRef and UID and compare to expected values
pv, err = c.CoreV1().PersistentVolumes().Get(pv.Name, metav1.GetOptions{})
Expect(err).NotTo(HaveOccurred())
if err != nil {
return fmt.Errorf("PV Get API error: %v", err)
}
cr := pv.Spec.ClaimRef
if expectPVPhase == v1.VolumeAvailable {
if cr != nil { // may be ok if cr != nil
Expect(cr.UID).To(BeEmpty())
if cr != nil && len(cr.UID) > 0 {
return fmt.Errorf("PV is 'Available' but ClaimRef.UID is not empty")
}
} else if expectPVPhase == v1.VolumeBound {
Expect(cr).NotTo(BeNil())
Expect(cr.UID).NotTo(BeEmpty())
if cr == nil {
return fmt.Errorf("PV is 'Bound' but ClaimRef is nil")
}
if len(cr.UID) == 0 {
return fmt.Errorf("PV is 'Bound' but ClaimRef.UID is empty")
}
}
Logf("PV %v now in %q phase", pv.Name, expectPVPhase)
return nil
}
// Wraps deletePVCandValidatePV() by calling the function in a loop over the PV map. Only
// bound PVs are deleted. Validates that the claim was deleted and the PV is in the relevant Phase (Released, Available,
// Bound).
// Note: if there are more claims than pvs then some of the remaining claims will bind to
// the just-made-available pvs.
func DeletePVCandValidatePVGroup(c clientset.Interface, ns string, pvols PVMap, claims PVCMap, expectPVPhase v1.PersistentVolumePhase) {
// Wraps deletePVCandValidatePV() by calling the function in a loop over the PV map. Only bound PVs
// are deleted. Validates that the claim was deleted and the PV is in the expected Phase (Released,
// Available, Bound).
// Note: if there are more claims than pvs then some of the remaining claims may bind to just made
// available pvs.
func DeletePVCandValidatePVGroup(c clientset.Interface, ns string, pvols PVMap, claims PVCMap, expectPVPhase v1.PersistentVolumePhase) error {
var boundPVs, deletedPVCs int
for pvName := range pvols {
pv, err := c.CoreV1().PersistentVolumes().Get(pvName, metav1.GetOptions{})
Expect(apierrs.IsNotFound(err)).To(BeFalse())
if err != nil {
return fmt.Errorf("PV Get API error: %v", err)
}
cr := pv.Spec.ClaimRef
// if pv is bound then delete the pvc it is bound to
if cr != nil && len(cr.Name) > 0 {
@ -186,30 +225,46 @@ func DeletePVCandValidatePVGroup(c clientset.Interface, ns string, pvols PVMap,
// Assert bound PVC is tracked in this test. Failing this might
// indicate external PVCs interfering with the test.
pvcKey := makePvcKey(ns, cr.Name)
_, found := claims[pvcKey]
Expect(found).To(BeTrue())
if _, found := claims[pvcKey]; !found {
return fmt.Errorf("internal: claims map is missing pvc %q", pvcKey)
}
// get the pvc for the delete call below
pvc, err := c.CoreV1().PersistentVolumeClaims(ns).Get(cr.Name, metav1.GetOptions{})
Expect(apierrs.IsNotFound(err)).To(BeFalse())
DeletePVCandValidatePV(c, ns, pvc, pv, expectPVPhase)
if err == nil {
if err = DeletePVCandValidatePV(c, ns, pvc, pv, expectPVPhase); err != nil {
return err
}
} else if !apierrs.IsNotFound(err) {
return fmt.Errorf("PVC Get API error: %v", err)
}
// delete pvckey from map even if apierrs.IsNotFound above is true and thus the
// claim was not actually deleted here
delete(claims, pvcKey)
deletedPVCs++
}
}
Expect(boundPVs).To(Equal(deletedPVCs))
if boundPVs != deletedPVCs {
return fmt.Errorf("expect number of bound PVs (%v) to equal number of deleted PVCs (%v)", boundPVs, deletedPVCs)
}
return nil
}
// create the PV resource. Fails test on error.
func createPV(c clientset.Interface, pv *v1.PersistentVolume) *v1.PersistentVolume {
func createPV(c clientset.Interface, pv *v1.PersistentVolume) (*v1.PersistentVolume, error) {
pv, err := c.CoreV1().PersistentVolumes().Create(pv)
Expect(err).NotTo(HaveOccurred())
return pv
if err != nil {
return nil, fmt.Errorf("PV Create API error: %v", err)
}
return pv, nil
}
// create the PVC resource. Fails test on error.
func CreatePVC(c clientset.Interface, ns string, pvc *v1.PersistentVolumeClaim) *v1.PersistentVolumeClaim {
func CreatePVC(c clientset.Interface, ns string, pvc *v1.PersistentVolumeClaim) (*v1.PersistentVolumeClaim, error) {
pvc, err := c.CoreV1().PersistentVolumeClaims(ns).Create(pvc)
Expect(err).NotTo(HaveOccurred())
return pvc
if err != nil {
return nil, fmt.Errorf("PVC Create API error: %v", err)
}
return pvc, nil
}
// Create a PVC followed by the PV based on the passed in nfs-server ip and
@ -218,12 +273,10 @@ func CreatePVC(c clientset.Interface, ns string, pvc *v1.PersistentVolumeClaim)
// Note: in the pre-bind case the real PVC name, which is generated, is not
// known until after the PVC is instantiated. This is why the pvc is created
// before the pv.
func CreatePVCPV(c clientset.Interface, pvConfig PersistentVolumeConfig, pvcConfig PersistentVolumeClaimConfig, ns string, preBind bool) (*v1.PersistentVolume, *v1.PersistentVolumeClaim) {
var preBindMsg string
// make the pvc definition first
func CreatePVCPV(c clientset.Interface, pvConfig PersistentVolumeConfig, pvcConfig PersistentVolumeClaimConfig, ns string, preBind bool) (*v1.PersistentVolume, *v1.PersistentVolumeClaim, error) {
// make the pvc spec
pvc := MakePersistentVolumeClaim(pvcConfig, ns)
preBindMsg := ""
if preBind {
preBindMsg = " pre-bound"
pvConfig.Prebind = pvc
@ -232,16 +285,20 @@ func CreatePVCPV(c clientset.Interface, pvConfig PersistentVolumeConfig, pvcConf
pv := MakePersistentVolume(pvConfig)
By(fmt.Sprintf("Creating a PVC followed by a%s PV", preBindMsg))
// instantiate the pvc
pvc = CreatePVC(c, ns, pvc)
pvc, err := CreatePVC(c, ns, pvc)
if err != nil {
return nil, nil, err
}
// instantiate the pv, handle pre-binding by ClaimRef if needed
if preBind {
pv.Spec.ClaimRef.Name = pvc.Name
}
pv = createPV(c, pv)
return pv, pvc
pv, err = createPV(c, pv)
if err != nil {
return nil, pvc, err
}
return pv, pvc, nil
}
// Create a PV followed by the PVC based on the passed in nfs-server ip and
@ -251,8 +308,7 @@ func CreatePVCPV(c clientset.Interface, pvConfig PersistentVolumeConfig, pvcConf
// Note: in the pre-bind case the real PV name, which is generated, is not
// known until after the PV is instantiated. This is why the pv is created
// before the pvc.
func CreatePVPVC(c clientset.Interface, pvConfig PersistentVolumeConfig, pvcConfig PersistentVolumeClaimConfig, ns string, preBind bool) (*v1.PersistentVolume, *v1.PersistentVolumeClaim) {
func CreatePVPVC(c clientset.Interface, pvConfig PersistentVolumeConfig, pvcConfig PersistentVolumeClaimConfig, ns string, preBind bool) (*v1.PersistentVolume, *v1.PersistentVolumeClaim, error) {
preBindMsg := ""
if preBind {
preBindMsg = " pre-bound"
@ -264,29 +320,33 @@ func CreatePVPVC(c clientset.Interface, pvConfig PersistentVolumeConfig, pvcConf
pvc := MakePersistentVolumeClaim(pvcConfig, ns)
// instantiate the pv
pv = createPV(c, pv)
pv, err := createPV(c, pv)
if err != nil {
return nil, nil, err
}
// instantiate the pvc, handle pre-binding by VolumeName if needed
if preBind {
pvc.Spec.VolumeName = pv.Name
}
pvc = CreatePVC(c, ns, pvc)
return pv, pvc
pvc, err = CreatePVC(c, ns, pvc)
if err != nil {
return pv, nil, err
}
return pv, pvc, nil
}
// Create the desired number of PVs and PVCs and return them in separate maps. If the
// number of PVs != the number of PVCs then the min of those two counts is the number of
// PVs expected to bind.
func CreatePVsPVCs(numpvs, numpvcs int, c clientset.Interface, ns string, pvConfig PersistentVolumeConfig, pvcConfig PersistentVolumeClaimConfig) (PVMap, PVCMap) {
var i int
var pv *v1.PersistentVolume
var pvc *v1.PersistentVolumeClaim
// PVs expected to bind. If a Create error occurs, the returned maps may contain pv and pvc
// entries for the resources that were successfully created. In other words, when the caller
// sees an error returned, it needs to decide what to do about entries in the maps.
// Note: when the test suite deletes the namespace orphaned pvcs and pods are deleted. However,
// orphaned pvs are not deleted and will remain after the suite completes.
func CreatePVsPVCs(numpvs, numpvcs int, c clientset.Interface, ns string, pvConfig PersistentVolumeConfig, pvcConfig PersistentVolumeClaimConfig) (PVMap, PVCMap, error) {
pvMap := make(PVMap, numpvs)
pvcMap := make(PVCMap, numpvcs)
var extraPVs, extraPVCs int
extraPVs = numpvs - numpvcs
extraPVCs := 0
extraPVs := numpvs - numpvcs
if extraPVs < 0 {
extraPVCs = -extraPVs
extraPVs = 0
@ -294,54 +354,76 @@ func CreatePVsPVCs(numpvs, numpvcs int, c clientset.Interface, ns string, pvConf
pvsToCreate := numpvs - extraPVs // want the min(numpvs, numpvcs)
// create pvs and pvcs
for i = 0; i < pvsToCreate; i++ {
pv, pvc = CreatePVPVC(c, pvConfig, pvcConfig, ns, false)
for i := 0; i < pvsToCreate; i++ {
pv, pvc, err := CreatePVPVC(c, pvConfig, pvcConfig, ns, false)
if err != nil {
return pvMap, pvcMap, err
}
pvMap[pv.Name] = pvval{}
pvcMap[makePvcKey(ns, pvc.Name)] = pvcval{}
}
// create extra pvs or pvcs as needed
for i = 0; i < extraPVs; i++ {
pv = MakePersistentVolume(pvConfig)
pv = createPV(c, pv)
for i := 0; i < extraPVs; i++ {
pv := MakePersistentVolume(pvConfig)
pv, err := createPV(c, pv)
if err != nil {
return pvMap, pvcMap, err
}
pvMap[pv.Name] = pvval{}
}
for i = 0; i < extraPVCs; i++ {
pvc = MakePersistentVolumeClaim(pvcConfig, ns)
pvc = CreatePVC(c, ns, pvc)
for i := 0; i < extraPVCs; i++ {
pvc := MakePersistentVolumeClaim(pvcConfig, ns)
pvc, err := CreatePVC(c, ns, pvc)
if err != nil {
return pvMap, pvcMap, err
}
pvcMap[makePvcKey(ns, pvc.Name)] = pvcval{}
}
return pvMap, pvcMap
return pvMap, pvcMap, nil
}
// Wait for the pv and pvc to bind to each other.
func WaitOnPVandPVC(c clientset.Interface, ns string, pv *v1.PersistentVolume, pvc *v1.PersistentVolumeClaim) {
func WaitOnPVandPVC(c clientset.Interface, ns string, pv *v1.PersistentVolume, pvc *v1.PersistentVolumeClaim) error {
// Wait for newly created PVC to bind to the PV
Logf("Waiting for PV %v to bind to PVC %v", pv.Name, pvc.Name)
err := WaitForPersistentVolumeClaimPhase(v1.ClaimBound, c, ns, pvc.Name, 3*time.Second, 300*time.Second)
Expect(err).NotTo(HaveOccurred())
if err != nil {
return fmt.Errorf("PVC %q did not become Bound: %v", pvc.Name, err)
}
// Wait for PersistentVolume.Status.Phase to be Bound, which it should be
// since the PVC is already bound.
err = WaitForPersistentVolumePhase(v1.VolumeBound, c, pv.Name, 3*time.Second, 300*time.Second)
Expect(err).NotTo(HaveOccurred())
if err != nil {
return fmt.Errorf("PV %q did not become Bound: %v", pv.Name, err)
}
// Re-get the pv and pvc objects
pv, err = c.CoreV1().PersistentVolumes().Get(pv.Name, metav1.GetOptions{})
Expect(err).NotTo(HaveOccurred())
// Re-get the pvc and
if err != nil {
return fmt.Errorf("PV Get API error: %v", err)
}
pvc, err = c.CoreV1().PersistentVolumeClaims(ns).Get(pvc.Name, metav1.GetOptions{})
Expect(err).NotTo(HaveOccurred())
if err != nil {
return fmt.Errorf("PVC Get API error: %v", err)
}
// 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))
if pv.Spec.ClaimRef == nil {
return fmt.Errorf("PV %q ClaimRef is nil", pv.Name)
}
if pv.Spec.ClaimRef.Name != pvc.Name {
return fmt.Errorf("PV %q ClaimRef's name (%q) should be %q", pv.Name, pv.Spec.ClaimRef.Name, pvc.Name)
}
if pvc.Spec.VolumeName != pv.Name {
return fmt.Errorf("PVC %q VolumeName (%q) should be %q", pvc.Name, pvc.Spec.VolumeName, pv.Name)
}
if pv.Spec.ClaimRef.UID != pvc.UID {
return fmt.Errorf("PV %q ClaimRef's UID (%q) should be %q", pv.Name, pv.Spec.ClaimRef.UID, pvc.UID)
}
return nil
}
// Search for bound PVs and PVCs by examining pvols for non-nil claimRefs.
@ -350,8 +432,7 @@ func WaitOnPVandPVC(c clientset.Interface, ns string, pv *v1.PersistentVolume, p
// 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) {
func WaitAndVerifyBinds(c clientset.Interface, ns string, pvols PVMap, claims PVCMap, testExpected bool) error {
var actualBinds int
expectedBinds := len(pvols)
if expectedBinds > len(claims) { // want the min of # pvs or #pvcs
@ -365,69 +446,108 @@ func WaitAndVerifyBinds(c clientset.Interface, ns string, pvols PVMap, claims PV
Logf(" This may be ok since there are more pvs than pvcs")
continue
}
Expect(err).NotTo(HaveOccurred())
if err != nil {
return fmt.Errorf("PV %q did not become Bound: %v", pvName, err)
}
pv, err := c.CoreV1().PersistentVolumes().Get(pvName, metav1.GetOptions{})
Expect(err).NotTo(HaveOccurred())
if cr := pv.Spec.ClaimRef; cr != nil && len(cr.Name) > 0 {
if err != nil {
return fmt.Errorf("PV Get API error: %v", err)
}
cr := pv.Spec.ClaimRef
if 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(), fmt.Sprintf("PersistentVolume (%q) ClaimRef (%q) does not match any test claims.", pv.Name, cr.Name))
if _, found := claims[pvcKey]; !found {
return fmt.Errorf("internal: claims map is missing pvc %q", pvcKey)
}
err = WaitForPersistentVolumeClaimPhase(v1.ClaimBound, c, ns, cr.Name, 3*time.Second, 180*time.Second)
Expect(err).NotTo(HaveOccurred())
err := WaitForPersistentVolumeClaimPhase(v1.ClaimBound, c, ns, cr.Name, 3*time.Second, 180*time.Second)
if err != nil {
return fmt.Errorf("PVC %q did not become Bound: %v", cr.Name, err)
}
actualBinds++
}
}
if testExpected {
Expect(actualBinds).To(Equal(expectedBinds))
if testExpected && actualBinds != expectedBinds {
return fmt.Errorf("expect number of bound PVs (%v) to equal number of claims (%v)", actualBinds, expectedBinds)
}
return nil
}
// Test the pod's exit code to be zero.
func testPodSuccessOrFail(c clientset.Interface, ns string, pod *v1.Pod) {
func testPodSuccessOrFail(c clientset.Interface, ns string, pod *v1.Pod) error {
By("Pod should terminate with exitcode 0 (success)")
err := WaitForPodSuccessInNamespace(c, pod.Name, ns)
Expect(err).NotTo(HaveOccurred())
if err := WaitForPodSuccessInNamespace(c, pod.Name, ns); err != nil {
return fmt.Errorf("pod %q failed to reach Success: %v", pod.Name, err)
}
Logf("Pod %v succeeded ", pod.Name)
return nil
}
// Deletes the passed-in pod and waits for the pod to be terminated. Resilient to the pod
// not existing.
func DeletePodWithWait(f *Framework, c clientset.Interface, pod *v1.Pod) {
func DeletePodWithWait(f *Framework, c clientset.Interface, pod *v1.Pod) error {
if pod == nil {
return
return nil
}
Logf("Deleting pod %v", pod.Name)
err := c.CoreV1().Pods(pod.Namespace).Delete(pod.Name, nil)
if err != nil {
if apierrs.IsNotFound(err) {
return // assume pod was deleted already
return nil // assume pod was deleted already
}
Expect(err).NotTo(HaveOccurred())
return fmt.Errorf("pod Get API error: %v", err)
}
// wait for pod to terminate
err = f.WaitForPodTerminated(pod.Name, "")
if err != nil {
Expect(apierrs.IsNotFound(err)).To(BeTrue(), fmt.Sprintf("Expected 'IsNotFound' error deleting pod \"%v/%v\", instead got: %v", pod.Namespace, pod.Name, err))
Logf("Ignore \"not found\" error above")
if err != nil && !apierrs.IsNotFound(err) {
return fmt.Errorf("error deleting pod %q: %v", pod.Name, err)
}
Logf("Pod %q successfully deleted", pod.Name)
if apierrs.IsNotFound(err) {
Logf("Ignore \"not found\" error above. Pod %q successfully deleted", pod.Name)
}
return nil
}
// Create the test pod, wait for (hopefully) success, and then delete the pod.
// Note: need named return value so that the err assignment in the defer sets the returned error.
// Has been shown to be necessary using Go 1.7.
func CreateWaitAndDeletePod(f *Framework, c clientset.Interface, ns string, pvc *v1.PersistentVolumeClaim) (err error) {
Logf("Creating nfs test pod")
pod := MakeWritePod(ns, pvc)
runPod, err := c.CoreV1().Pods(ns).Create(pod)
if err != nil {
return fmt.Errorf("pod Create API error: %v", err)
}
defer func() {
delErr := DeletePodWithWait(f, c, runPod)
if err == nil { // don't override previous err value
err = delErr // assign to returned err, can be nil
}
}()
err = testPodSuccessOrFail(c, ns, runPod)
if err != nil {
return fmt.Errorf("pod %q did not exit with Success: %v", runPod.Name, err)
}
return // note: named return value
}
// Sanity check for GCE testing. Verify the persistent disk attached to the node.
func VerifyGCEDiskAttached(diskName string, nodeName types.NodeName) bool {
func VerifyGCEDiskAttached(diskName string, nodeName types.NodeName) (bool, error) {
gceCloud, err := GetGCECloud()
Expect(err).NotTo(HaveOccurred())
if err != nil {
return false, fmt.Errorf("GetGCECloud error: %v", err)
}
isAttached, err := gceCloud.DiskIsAttached(diskName, nodeName)
Expect(err).NotTo(HaveOccurred())
return isAttached
if err != nil {
return false, fmt.Errorf("cannot verify if GCE disk is attached: %v", err)
}
return isAttached, nil
}
// Return a pvckey struct.
@ -438,14 +558,11 @@ func makePvcKey(ns, name string) types.NamespacedName {
// Returns a PV definition based on the nfs server IP. If the PVC is not nil
// then the PV is defined with a ClaimRef which includes the PVC's namespace.
// If the PVC is nil then the PV is not defined with a ClaimRef. If no reclaimPolicy
// is assigned, assumes "Retain".
// Note: the passed-in claim does not have a name until it is created
// (instantiated) and thus the PV's ClaimRef cannot be completely filled-in in
// this func. Therefore, the ClaimRef's name is added later in
// createPVCPV.
// is assigned, assumes "Retain". Specs are expected to match the test's PVC.
// Note: the passed-in claim does not have a name until it is created and thus the PV's
// ClaimRef cannot be completely filled-in in this func. Therefore, the ClaimRef's name
// is added later in createPVCPV.
func MakePersistentVolume(pvConfig PersistentVolumeConfig) *v1.PersistentVolume {
// Specs are expected to match the test's PersistentVolumeClaim
var claimRef *v1.ObjectReference
// If the reclaimPolicy is not provided, assume Retain
if pvConfig.ReclaimPolicy == "" {
@ -513,30 +630,31 @@ func MakePersistentVolumeClaim(cfg PersistentVolumeClaimConfig, ns string) *v1.P
}
func CreatePDWithRetry() (string, error) {
newDiskName := ""
var err error
for start := time.Now(); time.Since(start) < PDRetryTimeout; time.Sleep(PDRetryPollTime) {
if newDiskName, err = createPD(); err != nil {
Logf("Couldn't create a new PD. Sleeping 5 seconds (%v)", err)
newDiskName, err := createPD()
if err != nil {
Logf("Couldn't create a new PD, sleeping 5 seconds: %v", err)
continue
}
Logf("Successfully created a new PD: %q.", newDiskName)
break
return newDiskName, nil
}
return newDiskName, err
return "", err
}
func DeletePDWithRetry(diskName string) {
func DeletePDWithRetry(diskName string) error {
var err error
for start := time.Now(); time.Since(start) < PDRetryTimeout; time.Sleep(PDRetryPollTime) {
if err = deletePD(diskName); err != nil {
Logf("Couldn't delete PD %q. Sleeping 5 seconds (%v)", diskName, err)
err = deletePD(diskName)
if err != nil {
Logf("Couldn't delete PD %q, sleeping %v: %v", diskName, PDRetryPollTime, err)
continue
}
Logf("Successfully deleted PD %q.", diskName)
break
return nil
}
ExpectNoError(err, "Error deleting PD")
return fmt.Errorf("unable to delete PD %q: %v", diskName, err)
}
func createPD() (string, error) {
@ -572,7 +690,7 @@ func createPD() (string, error) {
volumeName := "aws://" + az + "/" + awsID
return volumeName, nil
} else {
return "", fmt.Errorf("Provider does not support volume creation")
return "", fmt.Errorf("provider does not support volume creation")
}
}
@ -591,7 +709,7 @@ func deletePD(pdName string) error {
return nil
}
Logf("Error deleting PD %q: %v", pdName, err)
Logf("error deleting PD %q: %v", pdName, err)
}
return err
} else if TestContext.Provider == "aws" {
@ -604,30 +722,17 @@ func deletePD(pdName string) error {
_, err := client.DeleteVolume(request)
if err != nil {
if awsError, ok := err.(awserr.Error); ok && awsError.Code() == "InvalidVolume.NotFound" {
Logf("Volume deletion implicitly succeeded because volume %q does not exist.", pdName)
Logf("volume deletion implicitly succeeded because volume %q does not exist.", pdName)
} else {
return fmt.Errorf("error deleting EBS volumes: %v", err)
}
}
return nil
} else {
return fmt.Errorf("Provider does not support volume deletion")
return fmt.Errorf("provider does not support volume deletion")
}
}
// Create the test pod, wait for success, and then delete the pod.
func CreateWaitAndDeletePod(f *Framework, c clientset.Interface, ns string, pvc *v1.PersistentVolumeClaim) {
Logf("Creating nfs test pod")
pod := MakeWritePod(ns, pvc)
runPod, err := c.CoreV1().Pods(ns).Create(pod)
Expect(err).NotTo(HaveOccurred())
Expect(runPod).NotTo(BeNil())
defer DeletePodWithWait(f, c, runPod)
// Wait for the test pod to complete its lifecycle
testPodSuccessOrFail(c, ns, runPod)
}
// Returns a pod definition based on the namespace. The pod references the PVC's
// name.
func MakeWritePod(ns string, pvc *v1.PersistentVolumeClaim) *v1.Pod {
@ -677,38 +782,49 @@ func MakePod(ns string, pvclaims []*v1.PersistentVolumeClaim, isPrivileged bool,
}
// create pod with given claims
func CreatePod(client clientset.Interface, namespace string, pvclaims []*v1.PersistentVolumeClaim, isPrivileged bool, command string) *v1.Pod {
podSpec := MakePod(namespace, pvclaims, isPrivileged, command)
pod, err := client.CoreV1().Pods(namespace).Create(podSpec)
Expect(err).NotTo(HaveOccurred())
func CreatePod(client clientset.Interface, namespace string, pvclaims []*v1.PersistentVolumeClaim, isPrivileged bool, command string) (*v1.Pod, error) {
pod := MakePod(namespace, pvclaims, isPrivileged, command)
pod, err := client.CoreV1().Pods(namespace).Create(pod)
if err != nil {
return nil, fmt.Errorf("pod Create API error: %v", err)
}
// Waiting for pod to be running
Expect(WaitForPodNameRunningInNamespace(client, pod.Name, namespace)).To(Succeed())
err = WaitForPodNameRunningInNamespace(client, pod.Name, namespace)
if err != nil {
return pod, fmt.Errorf("pod %q is not Running: %v", pod.Name, err)
}
// get fresh pod info
pod, err = client.CoreV1().Pods(namespace).Get(pod.Name, metav1.GetOptions{})
Expect(err).NotTo(HaveOccurred())
return pod
if err != nil {
return pod, fmt.Errorf("pod Get API error: %v", err)
}
return pod, nil
}
// Define and create a pod with a mounted PV. Pod runs infinite loop until killed.
func CreateClientPod(c clientset.Interface, ns string, pvc *v1.PersistentVolumeClaim) *v1.Pod {
func CreateClientPod(c clientset.Interface, ns string, pvc *v1.PersistentVolumeClaim) (*v1.Pod, error) {
return CreatePod(c, ns, []*v1.PersistentVolumeClaim{pvc}, true, "")
}
// wait until all pvcs phase set to bound
func WaitForPVClaimBoundPhase(client clientset.Interface, pvclaims []*v1.PersistentVolumeClaim) []*v1.PersistentVolume {
var persistentvolumes = make([]*v1.PersistentVolume, len(pvclaims))
func WaitForPVClaimBoundPhase(client clientset.Interface, pvclaims []*v1.PersistentVolumeClaim) ([]*v1.PersistentVolume, error) {
persistentvolumes := make([]*v1.PersistentVolume, len(pvclaims))
for index, claim := range pvclaims {
err := WaitForPersistentVolumeClaimPhase(v1.ClaimBound, client, claim.Namespace, claim.Name, Poll, ClaimProvisionTimeout)
Expect(err).NotTo(HaveOccurred())
if err != nil {
return persistentvolumes, err
}
// Get new copy of the claim
claim, err := client.CoreV1().PersistentVolumeClaims(claim.Namespace).Get(claim.Name, metav1.GetOptions{})
Expect(err).NotTo(HaveOccurred())
claim, err = client.CoreV1().PersistentVolumeClaims(claim.Namespace).Get(claim.Name, metav1.GetOptions{})
if err != nil {
return persistentvolumes, fmt.Errorf("PVC Get API error: %v", err)
}
// Get the bounded PV
persistentvolumes[index], err = client.CoreV1().PersistentVolumes().Get(claim.Spec.VolumeName, metav1.GetOptions{})
Expect(err).NotTo(HaveOccurred())
if err != nil {
return persistentvolumes, fmt.Errorf("PV Get API error: %v", err)
}
}
return persistentvolumes
return persistentvolumes, nil
}

View File

@ -457,8 +457,8 @@ var _ = framework.KubeDescribe("kubelet", func() {
})
AfterEach(func() {
framework.DeletePodWithWait(f, c, pod)
framework.DeletePodWithWait(f, c, nfsServerPod)
framework.ExpectNoError(framework.DeletePodWithWait(f, c, pod), "AfterEach: Failed to delete pod ", pod.Name)
framework.ExpectNoError(framework.DeletePodWithWait(f, c, nfsServerPod), "AfterEach: Failed to delete pod ", nfsServerPod.Name)
})
// execute It blocks from above table of tests
@ -470,7 +470,7 @@ var _ = framework.KubeDescribe("kubelet", func() {
stopNfsServer(nfsServerPod)
By("Delete the pod mounted to the NFS volume")
framework.DeletePodWithWait(f, c, pod)
framework.ExpectNoError(framework.DeletePodWithWait(f, c, pod), "Failed to delete pod ", pod.Name)
// pod object is now stale, but is intentionally not nil
By("Check if pod's host has been cleaned up -- expect not")

View File

@ -52,6 +52,7 @@ go_library(
"//vendor/k8s.io/apimachinery/pkg/labels:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/errors:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/uuid:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/wait:go_default_library",

View File

@ -521,7 +521,7 @@ var _ = framework.KubeDescribe("Pod Disks", func() {
framework.SkipUnlessProviderIs("gce")
By("delete a PD")
framework.DeletePDWithRetry("non-exist")
framework.ExpectNoError(framework.DeletePDWithRetry("non-exist"))
})
})
@ -697,7 +697,7 @@ func detachAndDeletePDs(diskName string, hosts []types.NodeName) {
waitForPDDetach(diskName, host)
}
By(fmt.Sprintf("Deleting PD %q", diskName))
framework.DeletePDWithRetry(diskName)
framework.ExpectNoError(framework.DeletePDWithRetry(diskName))
}
func waitForPDInVolumesInUse(

View File

@ -184,7 +184,7 @@ func testVolumeUnmountsFromDeletedPod(c clientset.Interface, f *framework.Framew
By("Restarting the kubelet.")
kubeletCommand(kStop, c, clientPod)
framework.DeletePodWithWait(f, c, clientPod)
framework.ExpectNoError(framework.DeletePodWithWait(f, c, clientPod), "Failed to delete pod ", clientPod.Name)
kubeletCommand(kStart, c, clientPod)
By("Expecting the volume mount not to be found.")
@ -195,13 +195,16 @@ func testVolumeUnmountsFromDeletedPod(c clientset.Interface, f *framework.Framew
framework.Logf("Volume mount detected on pod and written file is readable post-restart.")
}
// initTestCase initializes spec resources (pv, pvc, and pod) and returns pointers to be consumed by the test
// initTestCase initializes spec resources (pv, pvc, and pod) and returns pointers to be consumed
// by the test.
func initTestCase(f *framework.Framework, c clientset.Interface, pvConfig framework.PersistentVolumeConfig, pvcConfig framework.PersistentVolumeClaimConfig, ns, nodeName string) (*v1.Pod, *v1.PersistentVolume, *v1.PersistentVolumeClaim) {
pv, pvc := framework.CreatePVPVC(c, pvConfig, pvcConfig, ns, false)
pv, pvc, err := framework.CreatePVPVC(c, pvConfig, pvcConfig, ns, false)
Expect(err).NotTo(HaveOccurred())
pod := framework.MakePod(ns, []*v1.PersistentVolumeClaim{pvc}, true, "")
pod.Spec.NodeName = nodeName
framework.Logf("Creating nfs client Pod %s on node %s", pod.Name, nodeName)
pod, err := c.CoreV1().Pods(ns).Create(pod)
pod, err = c.CoreV1().Pods(ns).Create(pod)
Expect(err).NotTo(HaveOccurred())
err = framework.WaitForPodRunningInNamespace(c, pod)
Expect(err).NotTo(HaveOccurred())
@ -217,9 +220,9 @@ func initTestCase(f *framework.Framework, c clientset.Interface, pvConfig framew
// tearDownTestCase destroy resources created by initTestCase.
func tearDownTestCase(c clientset.Interface, f *framework.Framework, ns string, pod *v1.Pod, pvc *v1.PersistentVolumeClaim, pv *v1.PersistentVolume) {
framework.DeletePodWithWait(f, c, pod)
framework.DeletePersistentVolumeClaim(c, pvc.Name, ns)
framework.DeletePersistentVolume(c, pv.Name)
framework.ExpectNoError(framework.DeletePodWithWait(f, c, pod), "tearDown: Failed to delete pod ", pod.Name)
framework.ExpectNoError(framework.DeletePersistentVolumeClaim(c, pvc.Name, ns), "tearDown: Failed to delete PVC ", pvc.Name)
framework.ExpectNoError(framework.DeletePersistentVolume(c, pv.Name), "tearDown: Failed to delete PV ", pv.Name)
}
// kubeletCommand performs `start`, `restart`, or `stop` on the kubelet running on the node of the target pod.

View File

@ -24,6 +24,7 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/types"
utilerrors "k8s.io/apimachinery/pkg/util/errors"
"k8s.io/kubernetes/pkg/api/v1"
"k8s.io/kubernetes/pkg/client/clientset_generated/clientset"
"k8s.io/kubernetes/test/e2e/framework"
@ -41,11 +42,13 @@ func verifyGCEDiskAttached(diskName string, nodeName types.NodeName) bool {
// initializeGCETestSpec creates a PV, PVC, and ClientPod that will run until killed by test or clean up.
func initializeGCETestSpec(c clientset.Interface, ns string, pvConfig framework.PersistentVolumeConfig, pvcConfig framework.PersistentVolumeClaimConfig, isPrebound bool) (*v1.Pod, *v1.PersistentVolume, *v1.PersistentVolumeClaim) {
By("Creating the PV and PVC")
pv, pvc := framework.CreatePVPVC(c, pvConfig, pvcConfig, ns, isPrebound)
framework.WaitOnPVandPVC(c, ns, pv, pvc)
pv, pvc, err := framework.CreatePVPVC(c, pvConfig, pvcConfig, ns, isPrebound)
Expect(err).NotTo(HaveOccurred())
framework.ExpectNoError(framework.WaitOnPVandPVC(c, ns, pv, pvc))
By("Creating the Client Pod")
clientPod := framework.CreateClientPod(c, ns, pvc)
clientPod, err := framework.CreateClientPod(c, ns, pvc)
Expect(err).NotTo(HaveOccurred())
return clientPod, pv, pvc
}
@ -104,11 +107,13 @@ var _ = framework.KubeDescribe("PersistentVolumes:GCEPD [Volume]", func() {
AfterEach(func() {
framework.Logf("AfterEach: Cleaning up test resources")
if c != nil {
framework.DeletePodWithWait(f, c, clientPod)
framework.PVPVCCleanup(c, ns, pv, pvc)
framework.ExpectNoError(framework.DeletePodWithWait(f, c, clientPod))
if errs := framework.PVPVCCleanup(c, ns, pv, pvc); len(errs) > 0 {
framework.Failf("AfterEach: Failed to delete PVC and/or PV. Errors: %v", utilerrors.NewAggregate(errs))
}
clientPod, pv, pvc, node = nil, nil, nil, ""
if diskName != "" {
framework.DeletePDWithRetry(diskName)
framework.ExpectNoError(framework.DeletePDWithRetry(diskName))
}
}
})
@ -118,15 +123,14 @@ var _ = framework.KubeDescribe("PersistentVolumes:GCEPD [Volume]", func() {
It("should test that deleting a PVC before the pod does not cause pod deletion to fail on PD detach", func() {
By("Deleting the Claim")
framework.DeletePersistentVolumeClaim(c, pvc.Name, ns)
verifyGCEDiskAttached(diskName, node)
framework.ExpectNoError(framework.DeletePersistentVolumeClaim(c, pvc.Name, ns), "Unable to delete PVC ", pvc.Name)
Expect(verifyGCEDiskAttached(diskName, node)).To(BeTrue())
By("Deleting the Pod")
framework.DeletePodWithWait(f, c, clientPod)
framework.ExpectNoError(framework.DeletePodWithWait(f, c, clientPod), "Failed to delete pod ", clientPod.Name)
By("Verifying Persistent Disk detach")
err = waitForPDDetach(diskName, node)
Expect(err).NotTo(HaveOccurred())
framework.ExpectNoError(waitForPDDetach(diskName, node), "PD ", diskName, " did not detach")
})
// Attach a persistent disk to a pod using a PVC.
@ -134,15 +138,14 @@ var _ = framework.KubeDescribe("PersistentVolumes:GCEPD [Volume]", func() {
It("should test that deleting the PV before the pod does not cause pod deletion to fail on PD detach", func() {
By("Deleting the Persistent Volume")
framework.DeletePersistentVolume(c, pv.Name)
verifyGCEDiskAttached(diskName, node)
framework.ExpectNoError(framework.DeletePersistentVolume(c, pv.Name), "Failed to delete PV ", pv.Name)
Expect(verifyGCEDiskAttached(diskName, node)).To(BeTrue())
By("Deleting the client pod")
framework.DeletePodWithWait(f, c, clientPod)
framework.ExpectNoError(framework.DeletePodWithWait(f, c, clientPod), "Failed to delete pod ", clientPod.Name)
By("Verifying Persistent Disk detaches")
err = waitForPDDetach(diskName, node)
Expect(err).NotTo(HaveOccurred())
framework.ExpectNoError(waitForPDDetach(diskName, node), "PD ", diskName, " did not detach")
})
// Test that a Pod and PVC attached to a GCEPD successfully unmounts and detaches when the encompassing Namespace is deleted.
@ -156,7 +159,6 @@ var _ = framework.KubeDescribe("PersistentVolumes:GCEPD [Volume]", func() {
Expect(err).NotTo(HaveOccurred())
By("Verifying Persistent Disk detaches")
err = waitForPDDetach(diskName, node)
Expect(err).NotTo(HaveOccurred())
framework.ExpectNoError(waitForPDDetach(diskName, node), "PD ", diskName, " did not detach")
})
})

View File

@ -17,7 +17,6 @@ limitations under the License.
package storage
import (
apierrs "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/kubernetes/pkg/api/v1"
@ -95,11 +94,13 @@ var _ = framework.KubeDescribe("PersistentVolumes:vsphere", func() {
}
}
By("Creating the PV and PVC")
pv, pvc = framework.CreatePVPVC(c, pvConfig, pvcConfig, ns, false)
framework.WaitOnPVandPVC(c, ns, pv, pvc)
pv, pvc, err = framework.CreatePVPVC(c, pvConfig, pvcConfig, ns, false)
Expect(err).NotTo(HaveOccurred())
framework.ExpectNoError(framework.WaitOnPVandPVC(c, ns, pv, pvc))
By("Creating the Client Pod")
clientPod = framework.CreateClientPod(c, ns, pvc)
clientPod, err = framework.CreateClientPod(c, ns, pvc)
Expect(err).NotTo(HaveOccurred())
node := types.NodeName(clientPod.Spec.NodeName)
By("Verify disk should be attached to the node")
@ -111,18 +112,13 @@ var _ = framework.KubeDescribe("PersistentVolumes:vsphere", func() {
AfterEach(func() {
framework.Logf("AfterEach: Cleaning up test resources")
if c != nil {
if clientPod != nil {
clientPod, err = c.CoreV1().Pods(ns).Get(clientPod.Name, metav1.GetOptions{})
if !apierrs.IsNotFound(err) {
framework.DeletePodWithWait(f, c, clientPod)
}
}
framework.ExpectNoError(framework.DeletePodWithWait(f, c, clientPod), "AfterEach: failed to delete pod ", clientPod.Name)
if pv != nil {
framework.DeletePersistentVolume(c, pv.Name)
framework.ExpectNoError(framework.DeletePersistentVolume(c, pv.Name), "AfterEach: failed to delete PV ", pv.Name)
}
if pvc != nil {
framework.DeletePersistentVolumeClaim(c, pvc.Name, ns)
framework.ExpectNoError(framework.DeletePersistentVolumeClaim(c, pvc.Name, ns), "AfterEach: failed to delete PVC ", pvc.Name)
}
}
})
@ -150,16 +146,11 @@ var _ = framework.KubeDescribe("PersistentVolumes:vsphere", func() {
It("should test that deleting a PVC before the pod does not cause pod deletion to fail on PD detach", func() {
By("Deleting the Claim")
framework.DeletePersistentVolumeClaim(c, pvc.Name, ns)
pvc, err = c.CoreV1().PersistentVolumeClaims(ns).Get(pvc.Name, metav1.GetOptions{})
if !apierrs.IsNotFound(err) {
Expect(err).NotTo(HaveOccurred())
}
framework.ExpectNoError(framework.DeletePersistentVolumeClaim(c, pvc.Name, ns), "Failed to delete PVC ", pvc.Name)
pvc = nil
By("Deleting the Pod")
framework.DeletePodWithWait(f, c, clientPod)
By("Deleting the Pod")
framework.ExpectNoError(framework.DeletePodWithWait(f, c, clientPod), "Failed to delete pod ", clientPod.Name)
})
/*
@ -171,13 +162,10 @@ var _ = framework.KubeDescribe("PersistentVolumes:vsphere", func() {
*/
It("should test that deleting the PV before the pod does not cause pod deletion to fail on PD detach", func() {
By("Deleting the Persistent Volume")
framework.DeletePersistentVolume(c, pv.Name)
pv, err = c.CoreV1().PersistentVolumes().Get(pv.Name, metav1.GetOptions{})
if !apierrs.IsNotFound(err) {
Expect(err).NotTo(HaveOccurred())
}
framework.ExpectNoError(framework.DeletePersistentVolume(c, pv.Name), "Failed to delete PV ", pv.Name)
pv = nil
By("Deleting the pod")
framework.DeletePodWithWait(f, c, clientPod)
framework.ExpectNoError(framework.DeletePodWithWait(f, c, clientPod), "Failed to delete pod ", clientPod.Name)
})
})

View File

@ -18,12 +18,14 @@ package storage
import (
"fmt"
"strings"
"time"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
utilerrors "k8s.io/apimachinery/pkg/util/errors"
"k8s.io/kubernetes/pkg/api/v1"
"k8s.io/kubernetes/pkg/client/clientset_generated/clientset"
"k8s.io/kubernetes/test/e2e/framework"
@ -32,19 +34,18 @@ import (
// Validate PV/PVC, create and verify writer pod, delete the PVC, and validate the PV's
// phase. Note: the PV is deleted in the AfterEach, not here.
func completeTest(f *framework.Framework, c clientset.Interface, ns string, pv *v1.PersistentVolume, pvc *v1.PersistentVolumeClaim) {
// 1. verify that the PV and PVC have bound correctly
By("Validating the PV-PVC binding")
framework.WaitOnPVandPVC(c, ns, pv, pvc)
framework.ExpectNoError(framework.WaitOnPVandPVC(c, ns, pv, pvc))
// 2. create the nfs writer pod, test if the write was successful,
// then delete the pod and verify that it was deleted
By("Checking pod has write access to PersistentVolume")
framework.CreateWaitAndDeletePod(f, c, ns, pvc)
framework.ExpectNoError(framework.CreateWaitAndDeletePod(f, c, ns, pvc))
// 3. delete the PVC, wait for PV to become "Released"
By("Deleting the PVC to invoke the reclaim policy.")
framework.DeletePVCandValidatePV(c, ns, pvc, pv, v1.VolumeReleased)
framework.ExpectNoError(framework.DeletePVCandValidatePV(c, ns, pvc, pv, v1.VolumeReleased))
}
// Validate pairs of PVs and PVCs, create and verify writer pod, delete PVC and validate
@ -52,26 +53,36 @@ func completeTest(f *framework.Framework, c clientset.Interface, ns string, pv *
// Note: the PV is deleted in the AfterEach, not here.
// Note: this func is serialized, we wait for each pod to be deleted before creating the
// next pod. Adding concurrency is a TODO item.
func completeMultiTest(f *framework.Framework, c clientset.Interface, ns string, pvols framework.PVMap, claims framework.PVCMap, expectPhase v1.PersistentVolumePhase) {
func completeMultiTest(f *framework.Framework, c clientset.Interface, ns string, pvols framework.PVMap, claims framework.PVCMap, expectPhase v1.PersistentVolumePhase) error {
var err error
// 1. verify each PV permits write access to a client pod
By("Checking pod has write access to PersistentVolumes")
for pvcKey := range claims {
pvc, err := c.CoreV1().PersistentVolumeClaims(pvcKey.Namespace).Get(pvcKey.Name, metav1.GetOptions{})
Expect(err).NotTo(HaveOccurred())
if err != nil {
return fmt.Errorf("error getting pvc %q: %v", pvcKey.Name, err)
}
if len(pvc.Spec.VolumeName) == 0 {
continue // claim is not bound
}
// sanity test to ensure our maps are in sync
_, found := pvols[pvc.Spec.VolumeName]
Expect(found).To(BeTrue())
if !found {
return fmt.Errorf("internal: pvols map is missing volume %q", pvc.Spec.VolumeName)
}
// TODO: currently a serialized test of each PV
framework.CreateWaitAndDeletePod(f, c, pvcKey.Namespace, pvc)
if err = framework.CreateWaitAndDeletePod(f, c, pvcKey.Namespace, pvc); err != nil {
return err
}
}
// 2. delete each PVC, wait for its bound PV to reach `expectedPhase`
By("Deleting PVCs to invoke recycler")
framework.DeletePVCandValidatePVGroup(c, ns, pvols, claims, expectPhase)
By("Deleting PVCs to invoke reclaim policy")
if err = framework.DeletePVCandValidatePVGroup(c, ns, pvols, claims, expectPhase); err != nil {
return err
}
return nil
}
// initNFSserverPod wraps volumes.go's startVolumeServer to return a running nfs host pod
@ -99,6 +110,7 @@ var _ = framework.KubeDescribe("PersistentVolumes [Volume]", func() {
selector *metav1.LabelSelector
pv *v1.PersistentVolume
pvc *v1.PersistentVolumeClaim
err error
)
BeforeEach(func() {
@ -143,17 +155,18 @@ var _ = framework.KubeDescribe("PersistentVolumes [Volume]", func() {
})
AfterEach(func() {
framework.DeletePodWithWait(f, c, nfsServerPod)
framework.ExpectNoError(framework.DeletePodWithWait(f, c, nfsServerPod), "AfterEach: Failed to delete pod ", nfsServerPod.Name)
pv, pvc = nil, nil
pvConfig, pvcConfig = framework.PersistentVolumeConfig{}, framework.PersistentVolumeClaimConfig{}
})
Context("with Single PV - PVC pairs", func() {
// Note: this is the only code where the pv is deleted.
AfterEach(func() {
framework.Logf("AfterEach: Cleaning up test resources.")
framework.PVPVCCleanup(c, ns, pv, pvc)
if errs := framework.PVPVCCleanup(c, ns, pv, pvc); len(errs) > 0 {
framework.Failf("AfterEach: Failed to delete PVC and/or PV. Errors: %v", utilerrors.NewAggregate(errs))
}
})
// Individual tests follow:
@ -162,7 +175,8 @@ var _ = framework.KubeDescribe("PersistentVolumes [Volume]", func() {
// contains the claim. Verify that the PV and PVC bind correctly, and
// that the pod can write to the nfs volume.
It("should create a non-pre-bound PV and PVC: test write access ", func() {
pv, pvc = framework.CreatePVPVC(c, pvConfig, pvcConfig, ns, false)
pv, pvc, err = framework.CreatePVPVC(c, pvConfig, pvcConfig, ns, false)
Expect(err).NotTo(HaveOccurred())
completeTest(f, c, ns, pv, pvc)
})
@ -170,7 +184,8 @@ var _ = framework.KubeDescribe("PersistentVolumes [Volume]", func() {
// pod that contains the claim. Verify that the PV and PVC bind
// correctly, and that the pod can write to the nfs volume.
It("create a PVC and non-pre-bound PV: test write access", func() {
pv, pvc = framework.CreatePVCPV(c, pvConfig, pvcConfig, ns, false)
pv, pvc, err = framework.CreatePVCPV(c, pvConfig, pvcConfig, ns, false)
Expect(err).NotTo(HaveOccurred())
completeTest(f, c, ns, pv, pvc)
})
@ -178,7 +193,8 @@ var _ = framework.KubeDescribe("PersistentVolumes [Volume]", func() {
// and a pod that contains the claim. Verify that the PV and PVC bind
// correctly, and that the pod can write to the nfs volume.
It("create a PVC and a pre-bound PV: test write access", func() {
pv, pvc = framework.CreatePVCPV(c, pvConfig, pvcConfig, ns, true)
pv, pvc, err = framework.CreatePVCPV(c, pvConfig, pvcConfig, ns, true)
Expect(err).NotTo(HaveOccurred())
completeTest(f, c, ns, pv, pvc)
})
@ -186,7 +202,8 @@ var _ = framework.KubeDescribe("PersistentVolumes [Volume]", func() {
// and a pod that contains the claim. Verify that the PV and PVC bind
// correctly, and that the pod can write to the nfs volume.
It("create a PV and a pre-bound PVC: test write access", func() {
pv, pvc = framework.CreatePVPVC(c, pvConfig, pvcConfig, ns, true)
pv, pvc, err = framework.CreatePVPVC(c, pvConfig, pvcConfig, ns, true)
Expect(err).NotTo(HaveOccurred())
completeTest(f, c, ns, pv, pvc)
})
})
@ -205,40 +222,51 @@ var _ = framework.KubeDescribe("PersistentVolumes [Volume]", func() {
// define the maximum number of PVs and PVCs supported by these tests
const maxNumPVs = 10
const maxNumPVCs = 10
// create the pv and pvc maps to be reused in the It blocks
pvols := make(framework.PVMap, maxNumPVs)
claims := make(framework.PVCMap, maxNumPVCs)
// scope the pv and pvc maps to be available in the AfterEach
// note: these maps are created fresh in CreatePVsPVCs()
var pvols framework.PVMap
var claims framework.PVCMap
AfterEach(func() {
framework.Logf("AfterEach: deleting %v PVCs and %v PVs...", len(claims), len(pvols))
framework.PVPVCMapCleanup(c, ns, pvols, claims)
errs := framework.PVPVCMapCleanup(c, ns, pvols, claims)
if len(errs) > 0 {
errmsg := []string{}
for _, e := range errs {
errmsg = append(errmsg, e.Error())
}
framework.Failf("AfterEach: Failed to delete 1 or more PVs/PVCs. Errors: %v", strings.Join(errmsg, "; "))
}
})
// Create 2 PVs and 4 PVCs.
// Note: PVs are created before claims and no pre-binding
It("should create 2 PVs and 4 PVCs: test write access", func() {
numPVs, numPVCs := 2, 4
pvols, claims = framework.CreatePVsPVCs(numPVs, numPVCs, c, ns, pvConfig, pvcConfig)
framework.WaitAndVerifyBinds(c, ns, pvols, claims, true)
completeMultiTest(f, c, ns, pvols, claims, v1.VolumeReleased)
pvols, claims, err = framework.CreatePVsPVCs(numPVs, numPVCs, c, ns, pvConfig, pvcConfig)
Expect(err).NotTo(HaveOccurred())
framework.ExpectNoError(framework.WaitAndVerifyBinds(c, ns, pvols, claims, true))
framework.ExpectNoError(completeMultiTest(f, c, ns, pvols, claims, v1.VolumeReleased))
})
// Create 3 PVs and 3 PVCs.
// Note: PVs are created before claims and no pre-binding
It("should create 3 PVs and 3 PVCs: test write access", func() {
numPVs, numPVCs := 3, 3
pvols, claims = framework.CreatePVsPVCs(numPVs, numPVCs, c, ns, pvConfig, pvcConfig)
framework.WaitAndVerifyBinds(c, ns, pvols, claims, true)
completeMultiTest(f, c, ns, pvols, claims, v1.VolumeReleased)
pvols, claims, err = framework.CreatePVsPVCs(numPVs, numPVCs, c, ns, pvConfig, pvcConfig)
Expect(err).NotTo(HaveOccurred())
framework.ExpectNoError(framework.WaitAndVerifyBinds(c, ns, pvols, claims, true))
framework.ExpectNoError(completeMultiTest(f, c, ns, pvols, claims, v1.VolumeReleased))
})
// Create 4 PVs and 2 PVCs.
// Note: PVs are created before claims and no pre-binding.
It("should create 4 PVs and 2 PVCs: test write access", func() {
numPVs, numPVCs := 4, 2
pvols, claims = framework.CreatePVsPVCs(numPVs, numPVCs, c, ns, pvConfig, pvcConfig)
framework.WaitAndVerifyBinds(c, ns, pvols, claims, true)
completeMultiTest(f, c, ns, pvols, claims, v1.VolumeReleased)
pvols, claims, err = framework.CreatePVsPVCs(numPVs, numPVCs, c, ns, pvConfig, pvcConfig)
Expect(err).NotTo(HaveOccurred())
framework.ExpectNoError(framework.WaitAndVerifyBinds(c, ns, pvols, claims, true))
framework.ExpectNoError(completeMultiTest(f, c, ns, pvols, claims, v1.VolumeReleased))
})
})
@ -248,13 +276,16 @@ var _ = framework.KubeDescribe("PersistentVolumes [Volume]", func() {
Context("when invoking the Recycle reclaim policy", func() {
BeforeEach(func() {
pvConfig.ReclaimPolicy = v1.PersistentVolumeReclaimRecycle
pv, pvc = framework.CreatePVPVC(c, pvConfig, pvcConfig, ns, false)
framework.WaitOnPVandPVC(c, ns, pv, pvc)
pv, pvc, err = framework.CreatePVPVC(c, pvConfig, pvcConfig, ns, false)
Expect(err).NotTo(HaveOccurred(), "BeforeEach: Failed to create PV/PVC")
framework.ExpectNoError(framework.WaitOnPVandPVC(c, ns, pv, pvc), "BeforeEach: WaitOnPVandPVC failed")
})
AfterEach(func() {
framework.Logf("AfterEach: Cleaning up test resources.")
framework.PVPVCCleanup(c, ns, pv, pvc)
if errs := framework.PVPVCCleanup(c, ns, pv, pvc); len(errs) > 0 {
framework.Failf("AfterEach: Failed to delete PVC and/or PV. Errors: %v", utilerrors.NewAggregate(errs))
}
})
// This It() tests a scenario where a PV is written to by a Pod, recycled, then the volume checked
@ -263,18 +294,18 @@ var _ = framework.KubeDescribe("PersistentVolumes [Volume]", func() {
It("should test that a PV becomes Available and is clean after the PVC is deleted. [Volume]", func() {
By("Writing to the volume.")
pod := framework.MakeWritePod(ns, pvc)
pod, err := c.CoreV1().Pods(ns).Create(pod)
Expect(err).NotTo(HaveOccurred())
err = framework.WaitForPodSuccessInNamespace(c, pod.Name, ns)
pod, err = c.CoreV1().Pods(ns).Create(pod)
Expect(err).NotTo(HaveOccurred())
framework.ExpectNoError(framework.WaitForPodSuccessInNamespace(c, pod.Name, ns))
framework.DeletePVCandValidatePV(c, ns, pvc, pv, v1.VolumeAvailable)
By("Deleting the claim")
framework.ExpectNoError(framework.DeletePVCandValidatePV(c, ns, pvc, pv, v1.VolumeAvailable))
By("Re-mounting the volume.")
pvc = framework.MakePersistentVolumeClaim(pvcConfig, ns)
pvc = framework.CreatePVC(c, ns, pvc)
err = framework.WaitForPersistentVolumeClaimPhase(v1.ClaimBound, c, ns, pvc.Name, 2*time.Second, 60*time.Second)
pvc, err = framework.CreatePVC(c, ns, pvc)
Expect(err).NotTo(HaveOccurred())
framework.ExpectNoError(framework.WaitForPersistentVolumeClaimPhase(v1.ClaimBound, c, ns, pvc.Name, 2*time.Second, 60*time.Second), "Failed to reach 'Bound' for PVC ", pvc.Name)
// If a file is detected in /mnt, fail the pod and do not restart it.
By("Verifying the mount has been cleaned.")
@ -282,8 +313,7 @@ var _ = framework.KubeDescribe("PersistentVolumes [Volume]", func() {
pod = framework.MakePod(ns, []*v1.PersistentVolumeClaim{pvc}, true, fmt.Sprintf("[ $(ls -A %s | wc -l) -eq 0 ] && exit 0 || exit 1", mount))
pod, err = c.CoreV1().Pods(ns).Create(pod)
Expect(err).NotTo(HaveOccurred())
err = framework.WaitForPodSuccessInNamespace(c, pod.Name, ns)
Expect(err).NotTo(HaveOccurred())
framework.ExpectNoError(framework.WaitForPodSuccessInNamespace(c, pod.Name, ns))
framework.Logf("Pod exited without failure; the volume has been recycled.")
})
})

View File

@ -119,14 +119,14 @@ var _ = framework.KubeDescribe("PersistentVolumes [Feature:ReclaimPolicy]", func
writeContentToVSpherePV(c, pvc, volumeFileContent)
By("Delete PVC")
framework.DeletePersistentVolumeClaim(c, pvc.Name, ns)
framework.ExpectNoError(framework.DeletePersistentVolumeClaim(c, pvc.Name, ns), "Failed to delete PVC ", pvc.Name)
pvc = nil
By("Verify PV is retained")
framework.Logf("Waiting for PV %v to become Released", pv.Name)
err = framework.WaitForPersistentVolumePhase(v1.VolumeReleased, c, pv.Name, 3*time.Second, 300*time.Second)
Expect(err).NotTo(HaveOccurred())
framework.DeletePersistentVolume(c, pv.Name)
framework.ExpectNoError(framework.DeletePersistentVolume(c, pv.Name), "Failed to delete PV ", pv.Name)
By("Creating the PV for same volume path")
pv = getVSpherePersistentVolumeSpec(volumePath, v1.PersistentVolumeReclaimRetain, nil)
@ -139,7 +139,7 @@ var _ = framework.KubeDescribe("PersistentVolumes [Feature:ReclaimPolicy]", func
Expect(err).NotTo(HaveOccurred())
By("wait for the pv and pvc to bind")
framework.WaitOnPVandPVC(c, ns, pv, pvc)
framework.ExpectNoError(framework.WaitOnPVandPVC(c, ns, pv, pvc))
verifyContentOfVSpherePV(c, pvc, volumeFileContent)
})
@ -173,10 +173,10 @@ func testCleanupVSpherePersistentVolumeReclaim(vsp *vsphere.VSphere, c clientset
vsp.DeleteVolume(volumePath)
}
if pv != nil {
framework.DeletePersistentVolume(c, pv.Name)
framework.ExpectNoError(framework.DeletePersistentVolume(c, pv.Name), "Failed to delete PV ", pv.Name)
}
if pvc != nil {
framework.DeletePersistentVolumeClaim(c, pvc.Name, ns)
framework.ExpectNoError(framework.DeletePersistentVolumeClaim(c, pvc.Name, ns), "Failed to delete PVC ", pvc.Name)
}
}
@ -185,10 +185,10 @@ func deletePVCAfterBind(c clientset.Interface, ns string, pvc *v1.PersistentVolu
var err error
By("wait for the pv and pvc to bind")
framework.WaitOnPVandPVC(c, ns, pv, pvc)
framework.ExpectNoError(framework.WaitOnPVandPVC(c, ns, pv, pvc))
By("delete pvc")
framework.DeletePersistentVolumeClaim(c, pvc.Name, ns)
framework.ExpectNoError(framework.DeletePersistentVolumeClaim(c, pvc.Name, ns), "Failed to delete PVC ", pvc.Name)
pvc, err = c.CoreV1().PersistentVolumeClaims(ns).Get(pvc.Name, metav1.GetOptions{})
if !apierrs.IsNotFound(err) {
Expect(err).NotTo(HaveOccurred())

View File

@ -81,14 +81,14 @@ var _ = framework.KubeDescribe("PersistentVolumes [Feature:LabelSelector]", func
Expect(err).NotTo(HaveOccurred())
By("wait for the pvc_ssd to bind with pv_ssd")
framework.WaitOnPVandPVC(c, ns, pv_ssd, pvc_ssd)
framework.ExpectNoError(framework.WaitOnPVandPVC(c, ns, pv_ssd, pvc_ssd))
By("Verify status of pvc_vvol is pending")
err = framework.WaitForPersistentVolumeClaimPhase(v1.ClaimPending, c, ns, pvc_vvol.Name, 3*time.Second, 300*time.Second)
Expect(err).NotTo(HaveOccurred())
By("delete pvc_ssd")
framework.DeletePersistentVolumeClaim(c, pvc_ssd.Name, ns)
framework.ExpectNoError(framework.DeletePersistentVolumeClaim(c, pvc_ssd.Name, ns), "Failed to delete PVC ", pvc_ssd.Name)
By("verify pv_ssd is deleted")
err = framework.WaitForPersistentVolumeDeleted(c, pv_ssd.Name, 3*time.Second, 300*time.Second)
@ -96,7 +96,7 @@ var _ = framework.KubeDescribe("PersistentVolumes [Feature:LabelSelector]", func
volumePath = ""
By("delete pvc_vvol")
framework.DeletePersistentVolumeClaim(c, pvc_vvol.Name, ns)
framework.ExpectNoError(framework.DeletePersistentVolumeClaim(c, pvc_vvol.Name, ns), "Failed to delete PVC ", pvc_vvol.Name)
})
})
})
@ -139,12 +139,12 @@ func testCleanupVSpherePVClabelselector(c clientset.Interface, ns string, volume
vsp.DeleteVolume(volumePath)
}
if pvc_ssd != nil {
framework.DeletePersistentVolumeClaim(c, pvc_ssd.Name, ns)
framework.ExpectNoError(framework.DeletePersistentVolumeClaim(c, pvc_ssd.Name, ns), "Failed to delete PVC ", pvc_ssd.Name)
}
if pvc_vvol != nil {
framework.DeletePersistentVolumeClaim(c, pvc_vvol.Name, ns)
framework.ExpectNoError(framework.DeletePersistentVolumeClaim(c, pvc_vvol.Name, ns), "Failed to delete PVC ", pvc_vvol.Name)
}
if pv_ssd != nil {
framework.DeletePersistentVolume(c, pv_ssd.Name)
framework.ExpectNoError(framework.DeletePersistentVolume(c, pv_ssd.Name), "Faled to delete PV ", pv_ssd.Name)
}
}

View File

@ -68,7 +68,7 @@ func testDynamicProvisioning(t storageClassTest, client clientset.Interface, cla
Expect(err).NotTo(HaveOccurred())
defer func() {
framework.Logf("deleting storage class %s", class.Name)
client.StorageV1().StorageClasses().Delete(class.Name, nil)
framework.ExpectNoError(client.StorageV1().StorageClasses().Delete(class.Name, nil))
}()
}
@ -76,8 +76,12 @@ func testDynamicProvisioning(t storageClassTest, client clientset.Interface, cla
claim, err = client.CoreV1().PersistentVolumeClaims(claim.Namespace).Create(claim)
Expect(err).NotTo(HaveOccurred())
defer func() {
framework.Logf("deleting claim %s/%s", claim.Namespace, claim.Name)
client.CoreV1().PersistentVolumeClaims(claim.Namespace).Delete(claim.Name, nil)
framework.Logf("deleting claim %q/%q", claim.Namespace, claim.Name)
// typically this claim has already been deleted
err = client.CoreV1().PersistentVolumeClaims(claim.Namespace).Delete(claim.Name, nil)
if err != nil && !apierrs.IsNotFound(err) {
framework.Failf("Error deleting claim %q. Error: %v", claim.Name, err)
}
}()
err = framework.WaitForPersistentVolumeClaimPhase(v1.ClaimBound, client, claim.Namespace, claim.Name, framework.Poll, framework.ClaimProvisionTimeout)
Expect(err).NotTo(HaveOccurred())
@ -125,7 +129,7 @@ func testDynamicProvisioning(t storageClassTest, client clientset.Interface, cla
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")
By(fmt.Sprintf("deleting claim %q/%q", claim.Namespace, claim.Name))
framework.ExpectNoError(client.CoreV1().PersistentVolumeClaims(claim.Namespace).Delete(claim.Name, nil))
// Wait for the PV to get deleted. Technically, the first few delete
@ -133,6 +137,7 @@ func testDynamicProvisioning(t storageClassTest, client clientset.Interface, cla
// kubelet is slowly cleaning up the previous pod, however it should succeed
// in a couple of minutes. Wait 20 minutes to recover from random cloud
// hiccups.
By(fmt.Sprintf("deleting the claim's PV %q", pv.Name))
framework.ExpectNoError(framework.WaitForPersistentVolumeDeleted(client, pv.Name, 5*time.Second, 20*time.Minute))
}
@ -391,8 +396,8 @@ var _ = framework.KubeDescribe("Dynamic Provisioning", func() {
}
})
// NOTE: Slow! The test will wait up to 5 minutes (framework.ClaimProvisionTimeout) when there is
// no regression.
// NOTE: Slow! The test will wait up to 5 minutes (framework.ClaimProvisionTimeout)
// when there is no regression.
It("should not provision a volume in an unmanaged GCE zone. [Slow] [Volume]", func() {
framework.SkipUnlessProviderIs("gce", "gke")
var suffix string = "unmananged"
@ -410,6 +415,7 @@ var _ = framework.KubeDescribe("Dynamic Provisioning", func() {
// Get a list of all zones in the project
zones, err := gceCloud.GetComputeService().Zones.List(framework.TestContext.CloudConfig.ProjectID).Do()
Expect(err).NotTo(HaveOccurred())
for _, z := range zones.Items {
allZones.Insert(z.Name)
}
@ -440,7 +446,9 @@ var _ = framework.KubeDescribe("Dynamic Provisioning", func() {
pvc.Spec.StorageClassName = &sc.Name
pvc, err = c.CoreV1().PersistentVolumeClaims(ns).Create(pvc)
Expect(err).NotTo(HaveOccurred())
defer framework.DeletePersistentVolumeClaim(c, pvc.Name, ns)
defer func() {
framework.ExpectNoError(framework.DeletePersistentVolumeClaim(c, pvc.Name, ns), "Failed to delete PVC ", pvc.Name)
}()
// The claim should timeout phase:Pending
err = framework.WaitForPersistentVolumeClaimPhase(v1.ClaimBound, c, ns, pvc.Name, 2*time.Second, framework.ClaimProvisionTimeout)
@ -475,17 +483,16 @@ var _ = framework.KubeDescribe("Dynamic Provisioning", func() {
suffix := fmt.Sprintf("race-%d", i)
claim := newClaim(test, ns, suffix)
claim.Spec.StorageClassName = &class.Name
tmpClaim := framework.CreatePVC(c, ns, claim)
framework.DeletePersistentVolumeClaim(c, tmpClaim.Name, ns)
tmpClaim, err := framework.CreatePVC(c, ns, claim)
Expect(err).NotTo(HaveOccurred())
framework.ExpectNoError(framework.DeletePersistentVolumeClaim(c, tmpClaim.Name, ns))
}
By(fmt.Sprintf("Checking for residual PersistentVolumes associated with StorageClass %s", class.Name))
residualPVs, err = waitForProvisionedVolumesDeleted(c, class.Name)
if err != nil {
// Cleanup the test resources before breaking
deleteProvisionedVolumesAndDisks(c, residualPVs)
Expect(err).NotTo(HaveOccurred())
}
Expect(err).NotTo(HaveOccurred())
// Cleanup the test resources before breaking
defer deleteProvisionedVolumesAndDisks(c, residualPVs)
// Report indicators of regression
if len(residualPVs) > 0 {
@ -548,9 +555,6 @@ var _ = framework.KubeDescribe("Dynamic Provisioning", func() {
expectedSize: "2Gi",
}
claim := newClaim(test, ns, "default")
defer func() {
framework.DeletePersistentVolumeClaim(c, claim.Name, ns)
}()
testDynamicProvisioning(test, c, claim, nil)
})
@ -573,7 +577,7 @@ var _ = framework.KubeDescribe("Dynamic Provisioning", func() {
claim, err := c.CoreV1().PersistentVolumeClaims(ns).Create(claim)
Expect(err).NotTo(HaveOccurred())
defer func() {
framework.DeletePersistentVolumeClaim(c, claim.Name, ns)
framework.ExpectNoError(framework.DeletePersistentVolumeClaim(c, claim.Name, ns))
}()
// The claim should timeout phase:Pending
@ -604,7 +608,7 @@ var _ = framework.KubeDescribe("Dynamic Provisioning", func() {
claim, err := c.CoreV1().PersistentVolumeClaims(ns).Create(claim)
Expect(err).NotTo(HaveOccurred())
defer func() {
framework.DeletePersistentVolumeClaim(c, claim.Name, ns)
framework.ExpectNoError(framework.DeletePersistentVolumeClaim(c, claim.Name, ns))
}()
// The claim should timeout phase:Pending
@ -731,10 +735,10 @@ func runInPodWithVolume(c clientset.Interface, ns, claimName, command string) {
},
}
pod, err := c.CoreV1().Pods(ns).Create(pod)
framework.ExpectNoError(err, "Failed to create pod: %v", err)
defer func() {
framework.DeletePodOrFail(c, ns, pod.Name)
}()
framework.ExpectNoError(err, "Failed to create pod: %v", err)
framework.ExpectNoError(framework.WaitForPodSuccessInNamespaceSlow(c, pod.Name, pod.Namespace))
}
@ -907,8 +911,8 @@ func deleteStorageClass(c clientset.Interface, className string) {
// deleteProvisionedVolumes [gce||gke only] iteratively deletes persistent volumes and attached GCE PDs.
func deleteProvisionedVolumesAndDisks(c clientset.Interface, pvs []*v1.PersistentVolume) {
for _, pv := range pvs {
framework.DeletePDWithRetry(pv.Spec.PersistentVolumeSource.GCEPersistentDisk.PDName)
framework.DeletePersistentVolume(c, pv.Name)
framework.ExpectNoError(framework.DeletePDWithRetry(pv.Spec.PersistentVolumeSource.GCEPersistentDisk.PDName))
framework.ExpectNoError(framework.DeletePersistentVolume(c, pv.Name))
}
}

View File

@ -517,9 +517,8 @@ var _ = framework.KubeDescribe("Volumes [Volume]", func() {
By("creating a test gce pd volume")
volumeName, err := framework.CreatePDWithRetry()
Expect(err).NotTo(HaveOccurred())
defer func() {
framework.DeletePDWithRetry(volumeName)
framework.ExpectNoError(framework.DeletePDWithRetry(volumeName))
}()
defer func() {

View File

@ -99,21 +99,24 @@ var _ = framework.KubeDescribe("vsphere volume operations storm [Volume]", func(
By("Creating PVCs using the Storage Class")
count := 0
for count < volume_ops_scale {
pvclaims[count] = framework.CreatePVC(client, namespace, getVSphereClaimSpecWithStorageClassAnnotation(namespace, storageclass))
pvclaims[count], err = framework.CreatePVC(client, namespace, getVSphereClaimSpecWithStorageClassAnnotation(namespace, storageclass))
Expect(err).NotTo(HaveOccurred())
count++
}
By("Waiting for all claims to be in bound phase")
persistentvolumes = framework.WaitForPVClaimBoundPhase(client, pvclaims)
persistentvolumes, err = framework.WaitForPVClaimBoundPhase(client, pvclaims)
Expect(err).NotTo(HaveOccurred())
By("Creating pod to attach PVs to the node")
pod := framework.CreatePod(client, namespace, pvclaims, false, "")
pod, err := framework.CreatePod(client, namespace, pvclaims, false, "")
Expect(err).NotTo(HaveOccurred())
By("Verify all volumes are accessible and available in the pod")
verifyVSphereVolumesAccessible(pod, persistentvolumes, vsp)
By("Deleting pod")
framework.DeletePodWithWait(f, client, pod)
framework.ExpectNoError(framework.DeletePodWithWait(f, client, pod))
By("Waiting for volumes to be detached from the node")
for _, pv := range persistentvolumes {

View File

@ -277,8 +277,8 @@ var _ = framework.KubeDescribe("Volume Placement [Volume]", func() {
defer func() {
By("clean up undeleted pods")
framework.DeletePodWithWait(f, c, podA)
framework.DeletePodWithWait(f, c, podB)
framework.ExpectNoError(framework.DeletePodWithWait(f, c, podA), "defer: Failed to delete pod ", podA.Name)
framework.ExpectNoError(framework.DeletePodWithWait(f, c, podB), "defer: Failed to delete pod ", podB.Name)
By(fmt.Sprintf("wait for volumes to be detached from the node: %v", node1Name))
for _, volumePath := range volumePaths {
waitForVSphereDiskToDetach(vsp, volumePath, types.NodeName(node1Name))
@ -319,9 +319,9 @@ var _ = framework.KubeDescribe("Volume Placement [Volume]", func() {
verifyFilesExistOnVSphereVolume(ns, podB.Name, podBFiles)
By("Deleting pod-A")
framework.DeletePodWithWait(f, c, podA)
framework.ExpectNoError(framework.DeletePodWithWait(f, c, podA), "Failed to delete pod ", podA.Name)
By("Deleting pod-B")
framework.DeletePodWithWait(f, c, podB)
framework.ExpectNoError(framework.DeletePodWithWait(f, c, podB), "Failed to delete pod ", podB.Name)
}
})
})
@ -377,7 +377,7 @@ func createAndVerifyFilesOnVolume(namespace string, podname string, newEmptyfile
func deletePodAndWaitForVolumeToDetach(f *framework.Framework, c clientset.Interface, pod *v1.Pod, vsp *vsphere.VSphere, nodeName string, volumePaths []string) {
By("Deleting pod")
framework.DeletePodWithWait(f, c, pod)
framework.ExpectNoError(framework.DeletePodWithWait(f, c, pod), "Failed to delete pod ", pod.Name)
By("Waiting for volume to be detached from the node")
for _, volumePath := range volumePaths {

View File

@ -42,6 +42,7 @@ go_library(
"//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/labels:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/errors:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/uuid:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/wait:go_default_library",
],

View File

@ -17,10 +17,12 @@ limitations under the License.
package upgrades
import (
utilerrors "k8s.io/apimachinery/pkg/util/errors"
"k8s.io/kubernetes/pkg/api/v1"
"k8s.io/kubernetes/test/e2e/framework"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)
// PersistentVolumeUpgradeTest test that a pv is available before and after a cluster upgrade.
@ -50,13 +52,14 @@ func (t *PersistentVolumeUpgradeTest) createGCEVolume() *v1.PersistentVolumeSour
},
}
}
func (t *PersistentVolumeUpgradeTest) deleteGCEVolume(pvSource *v1.PersistentVolumeSource) {
framework.DeletePDWithRetry(pvSource.GCEPersistentDisk.PDName)
func (t *PersistentVolumeUpgradeTest) deleteGCEVolume(pvSource *v1.PersistentVolumeSource) error {
return framework.DeletePDWithRetry(pvSource.GCEPersistentDisk.PDName)
}
// Setup creates a pv and then verifies that a pod can consume it. The pod writes data to the volume.
func (t *PersistentVolumeUpgradeTest) Setup(f *framework.Framework) {
var err error
// TODO: generalize this to other providers
framework.SkipUnlessProviderIs("gce", "gke")
@ -76,8 +79,9 @@ func (t *PersistentVolumeUpgradeTest) Setup(f *framework.Framework) {
}
By("Creating the PV and PVC")
t.pv, t.pvc = framework.CreatePVPVC(f.ClientSet, pvConfig, pvcConfig, ns, true)
framework.WaitOnPVandPVC(f.ClientSet, ns, t.pv, t.pvc)
t.pv, t.pvc, err = framework.CreatePVPVC(f.ClientSet, pvConfig, pvcConfig, ns, true)
Expect(err).NotTo(HaveOccurred())
framework.ExpectNoError(framework.WaitOnPVandPVC(f.ClientSet, ns, t.pv, t.pvc))
By("Consuming the PV before upgrade")
t.testPod(f, pvWriteCmd+";"+pvReadCmd)
@ -93,8 +97,13 @@ func (t *PersistentVolumeUpgradeTest) Test(f *framework.Framework, done <-chan s
// Teardown cleans up any remaining resources.
func (t *PersistentVolumeUpgradeTest) Teardown(f *framework.Framework) {
framework.PVPVCCleanup(f.ClientSet, f.Namespace.Name, t.pv, t.pvc)
t.deleteGCEVolume(t.pvSource)
errs := framework.PVPVCCleanup(f.ClientSet, f.Namespace.Name, t.pv, t.pvc)
if err := t.deleteGCEVolume(t.pvSource); err != nil {
errs = append(errs, err)
}
if len(errs) > 0 {
framework.Failf("Failed to delete 1 or more PVs/PVCs and/or the GCE volume. Errors: %v", utilerrors.NewAggregate(errs))
}
}
// testPod creates a pod that consumes a pv and prints it out. The output is then verified.