2015-05-29 20:34:32 +00:00
/ *
2016-06-03 00:25:58 +00:00
Copyright 2015 The Kubernetes Authors .
2015-05-29 20:34:32 +00:00
Licensed under the Apache License , Version 2.0 ( the "License" ) ;
you may not use this file except in compliance with the License .
You may obtain a copy of the License at
http : //www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing , software
distributed under the License is distributed on an "AS IS" BASIS ,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
See the License for the specific language governing permissions and
limitations under the License .
* /
2017-03-19 19:25:40 +00:00
package storage
2015-05-29 20:34:32 +00:00
import (
2017-02-14 21:43:20 +00:00
"fmt"
2017-04-01 04:42:52 +00:00
"strings"
2016-10-28 22:15:28 +00:00
"time"
2015-08-05 22:05:17 +00:00
. "github.com/onsi/ginkgo"
2016-08-29 22:26:16 +00:00
. "github.com/onsi/gomega"
2017-06-22 18:24:23 +00:00
"k8s.io/api/core/v1"
2017-01-11 14:09:48 +00:00
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2017-03-20 22:55:24 +00:00
"k8s.io/apimachinery/pkg/labels"
2017-04-01 04:42:52 +00:00
utilerrors "k8s.io/apimachinery/pkg/util/errors"
2017-06-23 20:56:37 +00:00
clientset "k8s.io/client-go/kubernetes"
2016-04-07 17:21:31 +00:00
"k8s.io/kubernetes/test/e2e/framework"
2015-05-29 20:34:32 +00:00
)
2016-08-29 22:26:16 +00:00
// 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.
2016-11-18 20:55:17 +00:00
func completeTest ( f * framework . Framework , c clientset . Interface , ns string , pv * v1 . PersistentVolume , pvc * v1 . PersistentVolumeClaim ) {
2017-02-14 21:43:20 +00:00
// 1. verify that the PV and PVC have bound correctly
2016-08-08 20:27:20 +00:00
By ( "Validating the PV-PVC binding" )
2017-04-01 04:42:52 +00:00
framework . ExpectNoError ( framework . WaitOnPVandPVC ( c , ns , pv , pvc ) )
2016-08-08 20:27:20 +00:00
// 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" )
2017-04-01 04:42:52 +00:00
framework . ExpectNoError ( framework . CreateWaitAndDeletePod ( f , c , ns , pvc ) )
2016-08-08 20:27:20 +00:00
2017-02-14 21:43:20 +00:00
// 3. delete the PVC, wait for PV to become "Released"
By ( "Deleting the PVC to invoke the reclaim policy." )
2017-04-01 04:42:52 +00:00
framework . ExpectNoError ( framework . DeletePVCandValidatePV ( c , ns , pvc , pv , v1 . VolumeReleased ) )
2016-08-29 22:26:16 +00:00
}
2016-08-08 20:27:20 +00:00
2016-08-29 22:26:16 +00:00
// Validate pairs of PVs and PVCs, create and verify writer pod, delete PVC and validate
// PV. Ensure each step succeeds.
// 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.
2017-04-01 04:42:52 +00:00
func completeMultiTest ( f * framework . Framework , c clientset . Interface , ns string , pvols framework . PVMap , claims framework . PVCMap , expectPhase v1 . PersistentVolumePhase ) error {
var err error
2016-08-29 22:26:16 +00:00
// 1. verify each PV permits write access to a client pod
By ( "Checking pod has write access to PersistentVolumes" )
for pvcKey := range claims {
2017-02-27 16:09:59 +00:00
pvc , err := c . CoreV1 ( ) . PersistentVolumeClaims ( pvcKey . Namespace ) . Get ( pvcKey . Name , metav1 . GetOptions { } )
2017-04-01 04:42:52 +00:00
if err != nil {
return fmt . Errorf ( "error getting pvc %q: %v" , pvcKey . Name , err )
}
2016-08-29 22:26:16 +00:00
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 ]
2017-04-01 04:42:52 +00:00
if ! found {
return fmt . Errorf ( "internal: pvols map is missing volume %q" , pvc . Spec . VolumeName )
}
2016-08-29 22:26:16 +00:00
// TODO: currently a serialized test of each PV
2017-04-01 04:42:52 +00:00
if err = framework . CreateWaitAndDeletePod ( f , c , pvcKey . Namespace , pvc ) ; err != nil {
return err
}
2016-08-08 20:27:20 +00:00
}
2017-02-14 21:43:20 +00:00
// 2. delete each PVC, wait for its bound PV to reach `expectedPhase`
2017-04-01 04:42:52 +00:00
By ( "Deleting PVCs to invoke reclaim policy" )
if err = framework . DeletePVCandValidatePVGroup ( c , ns , pvols , claims , expectPhase ) ; err != nil {
return err
}
return nil
2016-08-08 20:27:20 +00:00
}
2017-07-11 21:55:45 +00:00
var _ = SIGDescribe ( "PersistentVolumes" , func ( ) {
2016-06-21 03:54:11 +00:00
2016-08-29 22:26:16 +00:00
// global vars for the Context()s and It()'s below
2016-04-07 17:21:31 +00:00
f := framework . NewDefaultFramework ( "pv" )
2017-03-20 22:55:24 +00:00
var (
c clientset . Interface
ns string
pvConfig framework . PersistentVolumeConfig
pvcConfig framework . PersistentVolumeClaimConfig
volLabel labels . Set
selector * metav1 . LabelSelector
pv * v1 . PersistentVolume
pvc * v1 . PersistentVolumeClaim
2017-04-01 04:42:52 +00:00
err error
2017-03-20 22:55:24 +00:00
)
2016-06-03 20:06:05 +00:00
2015-05-29 20:34:32 +00:00
BeforeEach ( func ( ) {
2016-10-18 13:00:38 +00:00
c = f . ClientSet
2016-04-07 17:21:31 +00:00
ns = f . Namespace . Name
2017-03-20 22:55:24 +00:00
// Enforce binding only within test space via selector labels
volLabel = labels . Set { framework . VolumeSelectorKey : ns }
selector = metav1 . SetAsLabelSelector ( volLabel )
2015-05-29 20:34:32 +00:00
} )
2016-12-05 18:44:07 +00:00
// Testing configurations of a single a PV/PVC pair, multiple evenly paired PVs/PVCs,
// and multiple unevenly paired PV/PVCs
2017-07-18 23:34:47 +00:00
Describe ( "NFS" , func ( ) {
2016-12-05 18:44:07 +00:00
var (
nfsServerPod * v1 . Pod
serverIP string
)
BeforeEach ( func ( ) {
2017-06-02 02:21:14 +00:00
_ , nfsServerPod , serverIP = framework . NewNFSServer ( c , ns , [ ] string { "-G" , "777" , "/exports" } )
2017-02-17 04:33:41 +00:00
pvConfig = framework . PersistentVolumeConfig {
NamePrefix : "nfs-" ,
2017-03-20 22:55:24 +00:00
Labels : volLabel ,
2017-02-17 04:33:41 +00:00
PVSource : v1 . PersistentVolumeSource {
2016-12-05 18:44:07 +00:00
NFS : & v1 . NFSVolumeSource {
Server : serverIP ,
Path : "/exports" ,
ReadOnly : false ,
} ,
} ,
}
2017-03-20 22:55:24 +00:00
pvcConfig = framework . PersistentVolumeClaimConfig {
Annotations : map [ string ] string {
v1 . BetaStorageClassAnnotation : "" ,
} ,
Selector : selector ,
}
2016-12-05 18:44:07 +00:00
} )
2017-02-02 17:44:12 +00:00
AfterEach ( func ( ) {
2017-04-01 04:42:52 +00:00
framework . ExpectNoError ( framework . DeletePodWithWait ( f , c , nfsServerPod ) , "AfterEach: Failed to delete pod " , nfsServerPod . Name )
2017-03-20 22:55:24 +00:00
pv , pvc = nil , nil
pvConfig , pvcConfig = framework . PersistentVolumeConfig { } , framework . PersistentVolumeClaimConfig { }
2016-12-05 18:44:07 +00:00
} )
2016-08-29 22:26:16 +00:00
2016-12-05 18:44:07 +00:00
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." )
2017-04-01 04:42:52 +00:00
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 ) )
}
2016-12-05 18:44:07 +00:00
} )
// Individual tests follow:
//
// Create an nfs PV, then a claim that matches the PV, 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.
2017-01-27 16:04:36 +00:00
It ( "should create a non-pre-bound PV and PVC: test write access " , func ( ) {
2017-04-01 04:42:52 +00:00
pv , pvc , err = framework . CreatePVPVC ( c , pvConfig , pvcConfig , ns , false )
Expect ( err ) . NotTo ( HaveOccurred ( ) )
2016-12-05 18:44:07 +00:00
completeTest ( f , c , ns , pv , pvc )
} )
// Create a claim first, then a nfs PV that matches the claim, 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.
2017-01-27 16:04:36 +00:00
It ( "create a PVC and non-pre-bound PV: test write access" , func ( ) {
2017-04-01 04:42:52 +00:00
pv , pvc , err = framework . CreatePVCPV ( c , pvConfig , pvcConfig , ns , false )
Expect ( err ) . NotTo ( HaveOccurred ( ) )
2016-12-05 18:44:07 +00:00
completeTest ( f , c , ns , pv , pvc )
} )
// Create a claim first, then a pre-bound nfs PV that matches the claim,
// 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.
2017-01-27 16:04:36 +00:00
It ( "create a PVC and a pre-bound PV: test write access" , func ( ) {
2017-04-01 04:42:52 +00:00
pv , pvc , err = framework . CreatePVCPV ( c , pvConfig , pvcConfig , ns , true )
Expect ( err ) . NotTo ( HaveOccurred ( ) )
2016-12-05 18:44:07 +00:00
completeTest ( f , c , ns , pv , pvc )
} )
// Create a nfs PV first, then a pre-bound PVC that matches the PV,
// 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.
2017-01-27 16:04:36 +00:00
It ( "create a PV and a pre-bound PVC: test write access" , func ( ) {
2017-04-01 04:42:52 +00:00
pv , pvc , err = framework . CreatePVPVC ( c , pvConfig , pvcConfig , ns , true )
Expect ( err ) . NotTo ( HaveOccurred ( ) )
2016-12-05 18:44:07 +00:00
completeTest ( f , c , ns , pv , pvc )
} )
} )
2016-08-29 22:26:16 +00:00
2016-12-05 18:44:07 +00:00
// Create multiple pvs and pvcs, all in the same namespace. The PVs-PVCs are
// verified to bind, though it's not known in advanced which PV will bind to
// which claim. For each pv-pvc pair create a pod that writes to the nfs mount.
// Note: when the number of PVs exceeds the number of PVCs the max binding wait
// time will occur for each PV in excess. This is expected but the delta
// should be kept small so that the tests aren't unnecessarily slow.
// Note: future tests may wish to incorporate the following:
// a) pre-binding, b) create pvcs before pvs, c) create pvcs and pods
// in different namespaces.
Context ( "with multiple PVs and PVCs all in same ns" , func ( ) {
2017-06-02 02:21:14 +00:00
2017-04-01 04:42:52 +00:00
// 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
2016-12-05 18:44:07 +00:00
AfterEach ( func ( ) {
framework . Logf ( "AfterEach: deleting %v PVCs and %v PVs..." , len ( claims ) , len ( pvols ) )
2017-04-01 04:42:52 +00:00
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 , "; " ) )
}
2016-12-05 18:44:07 +00:00
} )
// Create 2 PVs and 4 PVCs.
// Note: PVs are created before claims and no pre-binding
2017-01-27 16:04:36 +00:00
It ( "should create 2 PVs and 4 PVCs: test write access" , func ( ) {
2016-12-05 18:44:07 +00:00
numPVs , numPVCs := 2 , 4
2017-04-01 04:42:52 +00:00
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 ) )
2016-12-05 18:44:07 +00:00
} )
// Create 3 PVs and 3 PVCs.
// Note: PVs are created before claims and no pre-binding
2017-01-27 16:04:36 +00:00
It ( "should create 3 PVs and 3 PVCs: test write access" , func ( ) {
2016-12-05 18:44:07 +00:00
numPVs , numPVCs := 3 , 3
2017-04-01 04:42:52 +00:00
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 ) )
2016-12-05 18:44:07 +00:00
} )
// Create 4 PVs and 2 PVCs.
// Note: PVs are created before claims and no pre-binding.
2017-06-14 21:08:56 +00:00
It ( "should create 4 PVs and 2 PVCs: test write access [Slow]" , func ( ) {
2016-12-05 18:44:07 +00:00
numPVs , numPVCs := 4 , 2
2017-04-01 04:42:52 +00:00
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 ) )
2017-02-14 21:43:20 +00:00
} )
} )
// This Context isolates and tests the "Recycle" reclaim behavior. On deprecation of the
// Recycler, this entire context can be removed without affecting the test suite or leaving behind
// dead code.
Context ( "when invoking the Recycle reclaim policy" , func ( ) {
BeforeEach ( func ( ) {
2017-02-17 04:33:41 +00:00
pvConfig . ReclaimPolicy = v1 . PersistentVolumeReclaimRecycle
2017-04-01 04:42:52 +00:00
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" )
2017-02-14 21:43:20 +00:00
} )
AfterEach ( func ( ) {
framework . Logf ( "AfterEach: Cleaning up test resources." )
2017-04-01 04:42:52 +00:00
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 ) )
}
2017-02-14 21:43:20 +00:00
} )
// This It() tests a scenario where a PV is written to by a Pod, recycled, then the volume checked
// for files. If files are found, the checking Pod fails, failing the test. Otherwise, the pod
// (and test) succeed.
2017-07-12 01:38:01 +00:00
It ( "should test that a PV becomes Available and is clean after the PVC is deleted." , func ( ) {
2017-02-14 21:43:20 +00:00
By ( "Writing to the volume." )
2017-03-31 17:15:23 +00:00
pod := framework . MakeWritePod ( ns , pvc )
2017-04-01 04:42:52 +00:00
pod , err = c . CoreV1 ( ) . Pods ( ns ) . Create ( pod )
2017-02-14 21:43:20 +00:00
Expect ( err ) . NotTo ( HaveOccurred ( ) )
2017-04-01 04:42:52 +00:00
framework . ExpectNoError ( framework . WaitForPodSuccessInNamespace ( c , pod . Name , ns ) )
2017-02-14 21:43:20 +00:00
2017-04-01 04:42:52 +00:00
By ( "Deleting the claim" )
framework . ExpectNoError ( framework . DeletePVCandValidatePV ( c , ns , pvc , pv , v1 . VolumeAvailable ) )
2017-02-14 21:43:20 +00:00
By ( "Re-mounting the volume." )
2017-03-20 22:55:24 +00:00
pvc = framework . MakePersistentVolumeClaim ( pvcConfig , ns )
2017-04-01 04:42:52 +00:00
pvc , err = framework . CreatePVC ( c , ns , pvc )
2017-02-14 21:43:20 +00:00
Expect ( err ) . NotTo ( HaveOccurred ( ) )
2017-04-01 04:42:52 +00:00
framework . ExpectNoError ( framework . WaitForPersistentVolumeClaimPhase ( v1 . ClaimBound , c , ns , pvc . Name , 2 * time . Second , 60 * time . Second ) , "Failed to reach 'Bound' for PVC " , pvc . Name )
2017-02-14 21:43:20 +00:00
// If a file is detected in /mnt, fail the pod and do not restart it.
By ( "Verifying the mount has been cleaned." )
mount := pod . Spec . Containers [ 0 ] . VolumeMounts [ 0 ] . MountPath
2017-11-07 23:33:27 +00:00
pod = framework . MakePod ( ns , nil , [ ] * v1 . PersistentVolumeClaim { pvc } , true , fmt . Sprintf ( "[ $(ls -A %s | wc -l) -eq 0 ] && exit 0 || exit 1" , mount ) )
2017-02-27 16:09:59 +00:00
pod , err = c . CoreV1 ( ) . Pods ( ns ) . Create ( pod )
2017-02-14 21:43:20 +00:00
Expect ( err ) . NotTo ( HaveOccurred ( ) )
2017-04-01 04:42:52 +00:00
framework . ExpectNoError ( framework . WaitForPodSuccessInNamespace ( c , pod . Name , ns ) )
2017-02-14 21:43:20 +00:00
framework . Logf ( "Pod exited without failure; the volume has been recycled." )
2016-12-05 18:44:07 +00:00
} )
} )
} )
2015-05-29 20:34:32 +00:00
} )