2016-05-17 08:55:23 -04:00
/ *
2016-06-02 20:25:58 -04:00
Copyright 2016 The Kubernetes Authors .
2016-05-17 08:55:23 -04: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 .
* /
package persistentvolume
import (
"errors"
"testing"
2021-06-21 13:30:58 -04:00
v1 "k8s.io/api/core/v1"
2017-06-22 14:04:37 -04:00
storage "k8s.io/api/storage/v1"
2022-11-03 05:19:04 -04:00
utilfeature "k8s.io/apiserver/pkg/util/feature"
featuregatetesting "k8s.io/component-base/featuregate/testing"
2021-08-18 03:12:42 -04:00
"k8s.io/component-helpers/storage/volume"
2022-11-03 05:19:04 -04:00
"k8s.io/klog/v2/ktesting"
2019-03-17 21:55:28 -04:00
pvtesting "k8s.io/kubernetes/pkg/controller/volume/persistentvolume/testing"
2022-11-03 05:19:04 -04:00
"k8s.io/kubernetes/pkg/features"
2016-05-17 08:55:23 -04:00
)
// Test single call to syncVolume, expecting recycling to happen.
// 1. Fill in the controller with initial data
// 2. Call the syncVolume *once*.
// 3. Compare resulting volumes with expected volumes.
func TestDeleteSync ( t * testing . T ) {
2022-03-31 11:46:53 -04:00
const gceDriver = "pd.csi.storage.gke.io"
// Default enable the HonorPVReclaimPolicy feature gate.
defer featuregatetesting . SetFeatureGateDuringTest ( t , utilfeature . DefaultFeatureGate , features . HonorPVReclaimPolicy , true ) ( )
2022-11-03 05:19:04 -04:00
_ , ctx := ktesting . NewTestContext ( t )
2016-05-17 08:55:23 -04:00
tests := [ ] controllerTest {
{
// delete volume bound by controller
2022-08-04 09:30:23 -04:00
name : "8-1 - successful delete" ,
initialVolumes : newVolumeArray ( "volume8-1" , "1Gi" , "uid8-1" , "claim8-1" , v1 . VolumeBound , v1 . PersistentVolumeReclaimDelete , classEmpty , volume . AnnBoundByController ) ,
expectedVolumes : novolumes ,
initialClaims : noclaims ,
expectedClaims : noclaims ,
expectedEvents : noevents ,
errors : noerrors ,
2016-05-17 08:55:23 -04:00
// Inject deleter into the controller and call syncVolume. The
// deleter simulates one delete() call that succeeds.
2022-08-04 09:30:23 -04:00
test : wrapTestWithReclaimCalls ( operationDelete , [ ] error { nil } , testSyncVolume ) ,
2016-05-17 08:55:23 -04:00
} ,
{
// delete volume bound by user
2022-08-04 09:30:23 -04:00
name : "8-2 - successful delete with prebound volume" ,
initialVolumes : newVolumeArray ( "volume8-2" , "1Gi" , "uid8-2" , "claim8-2" , v1 . VolumeBound , v1 . PersistentVolumeReclaimDelete , classEmpty ) ,
expectedVolumes : novolumes ,
initialClaims : noclaims ,
expectedClaims : noclaims ,
expectedEvents : noevents ,
errors : noerrors ,
2016-05-17 08:55:23 -04:00
// Inject deleter into the controller and call syncVolume. The
// deleter simulates one delete() call that succeeds.
2022-08-04 09:30:23 -04:00
test : wrapTestWithReclaimCalls ( operationDelete , [ ] error { nil } , testSyncVolume ) ,
2016-05-17 08:55:23 -04:00
} ,
{
// delete failure - plugin not found
2022-08-04 09:30:23 -04:00
name : "8-3 - plugin not found" ,
initialVolumes : newVolumeArray ( "volume8-3" , "1Gi" , "uid8-3" , "claim8-3" , v1 . VolumeBound , v1 . PersistentVolumeReclaimDelete , classEmpty ) ,
expectedVolumes : withMessage ( "error getting deleter volume plugin for volume \"volume8-3\": no volume plugin matched" , newVolumeArray ( "volume8-3" , "1Gi" , "uid8-3" , "claim8-3" , v1 . VolumeFailed , v1 . PersistentVolumeReclaimDelete , classEmpty ) ) ,
initialClaims : noclaims ,
expectedClaims : noclaims ,
expectedEvents : [ ] string { "Warning VolumeFailedDelete" } ,
errors : noerrors ,
test : testSyncVolume ,
2016-05-17 08:55:23 -04:00
} ,
{
// delete failure - newDeleter returns error
2022-08-04 09:30:23 -04:00
name : "8-4 - newDeleter returns error" ,
initialVolumes : newVolumeArray ( "volume8-4" , "1Gi" , "uid8-4" , "claim8-4" , v1 . VolumeBound , v1 . PersistentVolumeReclaimDelete , classEmpty ) ,
expectedVolumes : withMessage ( "failed to create deleter for volume \"volume8-4\": Mock plugin error: no deleteCalls configured" , newVolumeArray ( "volume8-4" , "1Gi" , "uid8-4" , "claim8-4" , v1 . VolumeFailed , v1 . PersistentVolumeReclaimDelete , classEmpty ) ) ,
initialClaims : noclaims ,
expectedClaims : noclaims ,
expectedEvents : [ ] string { "Warning VolumeFailedDelete" } ,
errors : noerrors ,
test : wrapTestWithReclaimCalls ( operationDelete , [ ] error { } , testSyncVolume ) ,
2016-05-17 08:55:23 -04:00
} ,
{
// delete failure - delete() returns error
2022-08-04 09:30:23 -04:00
name : "8-5 - delete returns error" ,
initialVolumes : newVolumeArray ( "volume8-5" , "1Gi" , "uid8-5" , "claim8-5" , v1 . VolumeBound , v1 . PersistentVolumeReclaimDelete , classEmpty ) ,
expectedVolumes : withMessage ( "Mock delete error" , newVolumeArray ( "volume8-5" , "1Gi" , "uid8-5" , "claim8-5" , v1 . VolumeFailed , v1 . PersistentVolumeReclaimDelete , classEmpty ) ) ,
initialClaims : noclaims ,
expectedClaims : noclaims ,
expectedEvents : [ ] string { "Warning VolumeFailedDelete" } ,
errors : noerrors ,
test : wrapTestWithReclaimCalls ( operationDelete , [ ] error { errors . New ( "Mock delete error" ) } , testSyncVolume ) ,
2016-05-17 08:55:23 -04:00
} ,
{
// delete success(?) - volume is deleted before doDelete() starts
2022-08-04 09:30:23 -04:00
name : "8-6 - volume is deleted before deleting" ,
initialVolumes : newVolumeArray ( "volume8-6" , "1Gi" , "uid8-6" , "claim8-6" , v1 . VolumeBound , v1 . PersistentVolumeReclaimDelete , classEmpty ) ,
expectedVolumes : novolumes ,
initialClaims : noclaims ,
expectedClaims : noclaims ,
expectedEvents : noevents ,
errors : noerrors ,
2022-11-03 05:19:04 -04:00
test : wrapTestWithInjectedOperation ( ctx , wrapTestWithReclaimCalls ( operationDelete , [ ] error { } , testSyncVolume ) , func ( ctrl * PersistentVolumeController , reactor * pvtesting . VolumeReactor ) {
2016-05-17 08:55:23 -04:00
// Delete the volume before delete operation starts
2019-03-17 21:55:28 -04:00
reactor . DeleteVolume ( "volume8-6" )
2016-05-17 08:55:23 -04:00
} ) ,
} ,
{
// delete success(?) - volume is bound just at the time doDelete()
// starts. This simulates "volume no longer needs recycling,
// skipping".
2022-08-04 09:30:23 -04:00
name : "8-7 - volume is bound before deleting" ,
initialVolumes : newVolumeArray ( "volume8-7" , "1Gi" , "uid8-7" , "claim8-7" , v1 . VolumeBound , v1 . PersistentVolumeReclaimDelete , classEmpty , volume . AnnBoundByController ) ,
expectedVolumes : newVolumeArray ( "volume8-7" , "1Gi" , "uid8-7" , "claim8-7" , v1 . VolumeBound , v1 . PersistentVolumeReclaimDelete , classEmpty , volume . AnnBoundByController ) ,
initialClaims : noclaims ,
expectedClaims : newClaimArray ( "claim8-7" , "uid8-7" , "10Gi" , "volume8-7" , v1 . ClaimBound , nil ) ,
expectedEvents : noevents ,
errors : noerrors ,
2022-11-03 05:19:04 -04:00
test : wrapTestWithInjectedOperation ( ctx , wrapTestWithReclaimCalls ( operationDelete , [ ] error { } , testSyncVolume ) , func ( ctrl * PersistentVolumeController , reactor * pvtesting . VolumeReactor ) {
2016-06-17 12:27:25 -04:00
// Bind the volume to resurrected claim (this should never
2016-05-17 08:55:23 -04:00
// happen)
2017-03-02 04:23:56 -05:00
claim := newClaim ( "claim8-7" , "uid8-7" , "10Gi" , "volume8-7" , v1 . ClaimBound , nil )
2019-03-17 21:55:28 -04:00
reactor . AddClaimBoundToVolume ( claim )
2016-05-17 08:55:23 -04:00
ctrl . claims . Add ( claim )
} ) ,
} ,
{
// delete success - volume bound by user is deleted, while a new
// claim is created with another UID.
2022-08-04 09:30:23 -04:00
name : "8-9 - prebound volume is deleted while the claim exists" ,
initialVolumes : newVolumeArray ( "volume8-9" , "1Gi" , "uid8-9" , "claim8-9" , v1 . VolumeBound , v1 . PersistentVolumeReclaimDelete , classEmpty ) ,
expectedVolumes : novolumes ,
initialClaims : newClaimArray ( "claim8-9" , "uid8-9-x" , "10Gi" , "" , v1 . ClaimPending , nil ) ,
expectedClaims : newClaimArray ( "claim8-9" , "uid8-9-x" , "10Gi" , "" , v1 . ClaimPending , nil ) ,
expectedEvents : noevents ,
errors : noerrors ,
2016-05-17 08:55:23 -04:00
// Inject deleter into the controller and call syncVolume. The
// deleter simulates one delete() call that succeeds.
2022-08-04 09:30:23 -04:00
test : wrapTestWithReclaimCalls ( operationDelete , [ ] error { nil } , testSyncVolume ) ,
2016-05-17 08:55:23 -04:00
} ,
2016-09-13 04:39:45 -04:00
{
// PV requires external deleter
2022-08-04 09:30:23 -04:00
name : "8-10 - external deleter" ,
initialVolumes : [ ] * v1 . PersistentVolume { newExternalProvisionedVolume ( "volume8-10" , "1Gi" , "uid10-1" , "claim10-1" , v1 . VolumeBound , v1 . PersistentVolumeReclaimDelete , classEmpty , gceDriver , nil , volume . AnnBoundByController ) } ,
expectedVolumes : [ ] * v1 . PersistentVolume { newExternalProvisionedVolume ( "volume8-10" , "1Gi" , "uid10-1" , "claim10-1" , v1 . VolumeReleased , v1 . PersistentVolumeReclaimDelete , classEmpty , gceDriver , nil , volume . AnnBoundByController ) } ,
initialClaims : noclaims ,
expectedClaims : noclaims ,
expectedEvents : noevents ,
errors : noerrors ,
test : func ( ctrl * PersistentVolumeController , reactor * pvtesting . VolumeReactor , test controllerTest ) error {
2016-09-13 04:39:45 -04:00
// Inject external deleter annotation
2021-08-18 03:12:42 -04:00
test . initialVolumes [ 0 ] . Annotations [ volume . AnnDynamicallyProvisioned ] = "external.io/test"
test . expectedVolumes [ 0 ] . Annotations [ volume . AnnDynamicallyProvisioned ] = "external.io/test"
2016-09-13 04:39:45 -04:00
return testSyncVolume ( ctrl , reactor , test )
} ,
} ,
2016-11-03 11:58:25 -04:00
{
// delete success - two PVs are provisioned for a single claim.
// One of the PVs is deleted.
2022-08-04 09:30:23 -04:00
name : "8-11 - two PVs provisioned for a single claim" ,
initialVolumes : [ ] * v1 . PersistentVolume {
2021-08-18 03:12:42 -04:00
newVolume ( "volume8-11-1" , "1Gi" , "uid8-11" , "claim8-11" , v1 . VolumeBound , v1 . PersistentVolumeReclaimDelete , classEmpty , volume . AnnDynamicallyProvisioned ) ,
newVolume ( "volume8-11-2" , "1Gi" , "uid8-11" , "claim8-11" , v1 . VolumeBound , v1 . PersistentVolumeReclaimDelete , classEmpty , volume . AnnDynamicallyProvisioned ) ,
2016-11-03 11:58:25 -04:00
} ,
2022-08-04 09:30:23 -04:00
expectedVolumes : [ ] * v1 . PersistentVolume {
2021-08-18 03:12:42 -04:00
newVolume ( "volume8-11-2" , "1Gi" , "uid8-11" , "claim8-11" , v1 . VolumeBound , v1 . PersistentVolumeReclaimDelete , classEmpty , volume . AnnDynamicallyProvisioned ) ,
2016-11-03 11:58:25 -04:00
} ,
// the claim is bound to volume8-11-2 -> volume8-11-1 has lost the race and will be deleted
2022-08-04 09:30:23 -04:00
initialClaims : newClaimArray ( "claim8-11" , "uid8-11" , "10Gi" , "volume8-11-2" , v1 . ClaimBound , nil ) ,
expectedClaims : newClaimArray ( "claim8-11" , "uid8-11" , "10Gi" , "volume8-11-2" , v1 . ClaimBound , nil ) ,
expectedEvents : noevents ,
errors : noerrors ,
2016-11-03 11:58:25 -04:00
// Inject deleter into the controller and call syncVolume. The
// deleter simulates one delete() call that succeeds.
2022-08-04 09:30:23 -04:00
test : wrapTestWithReclaimCalls ( operationDelete , [ ] error { nil } , testSyncVolume ) ,
2016-11-03 11:58:25 -04:00
} ,
{
// delete success - two PVs are externally provisioned for a single
// claim. One of the PVs is marked as Released to be deleted by the
// external provisioner.
2022-08-04 09:30:23 -04:00
name : "8-12 - two PVs externally provisioned for a single claim" ,
initialVolumes : [ ] * v1 . PersistentVolume {
2022-03-31 11:46:53 -04:00
newExternalProvisionedVolume ( "volume8-12-1" , "1Gi" , "uid8-12" , "claim8-12" , v1 . VolumeBound , v1 . PersistentVolumeReclaimDelete , classEmpty , gceDriver , nil , volume . AnnDynamicallyProvisioned ) ,
newExternalProvisionedVolume ( "volume8-12-2" , "1Gi" , "uid8-12" , "claim8-12" , v1 . VolumeBound , v1 . PersistentVolumeReclaimDelete , classEmpty , gceDriver , nil , volume . AnnDynamicallyProvisioned ) ,
2016-11-03 11:58:25 -04:00
} ,
2022-08-04 09:30:23 -04:00
expectedVolumes : [ ] * v1 . PersistentVolume {
2022-03-31 11:46:53 -04:00
newExternalProvisionedVolume ( "volume8-12-1" , "1Gi" , "uid8-12" , "claim8-12" , v1 . VolumeReleased , v1 . PersistentVolumeReclaimDelete , classEmpty , gceDriver , nil , volume . AnnDynamicallyProvisioned ) ,
newExternalProvisionedVolume ( "volume8-12-2" , "1Gi" , "uid8-12" , "claim8-12" , v1 . VolumeBound , v1 . PersistentVolumeReclaimDelete , classEmpty , gceDriver , nil , volume . AnnDynamicallyProvisioned ) ,
2016-11-03 11:58:25 -04:00
} ,
// the claim is bound to volume8-12-2 -> volume8-12-1 has lost the race and will be "Released"
2022-08-04 09:30:23 -04:00
initialClaims : newClaimArray ( "claim8-12" , "uid8-12" , "10Gi" , "volume8-12-2" , v1 . ClaimBound , nil ) ,
expectedClaims : newClaimArray ( "claim8-12" , "uid8-12" , "10Gi" , "volume8-12-2" , v1 . ClaimBound , nil ) ,
expectedEvents : noevents ,
errors : noerrors ,
test : func ( ctrl * PersistentVolumeController , reactor * pvtesting . VolumeReactor , test controllerTest ) error {
2016-11-03 11:58:25 -04:00
// Inject external deleter annotation
2021-08-18 03:12:42 -04:00
test . initialVolumes [ 0 ] . Annotations [ volume . AnnDynamicallyProvisioned ] = "external.io/test"
test . expectedVolumes [ 0 ] . Annotations [ volume . AnnDynamicallyProvisioned ] = "external.io/test"
2016-11-03 11:58:25 -04:00
return testSyncVolume ( ctrl , reactor , test )
} ,
} ,
2022-02-09 12:50:56 -05:00
{
// delete success - volume has deletion timestamp before doDelete() starts
2022-08-04 09:30:23 -04:00
name : "8-13 - volume has deletion timestamp and processed" ,
initialVolumes : volumesWithFinalizers ( withVolumeDeletionTimestamp ( newVolumeArray ( "volume8-13" , "1Gi" , "uid8-13" , "claim8-13" , v1 . VolumeBound , v1 . PersistentVolumeReclaimDelete , classEmpty , volume . AnnBoundByController ) ) , [ ] string { volume . PVDeletionInTreeProtectionFinalizer } ) ,
expectedVolumes : novolumes ,
initialClaims : noclaims ,
expectedClaims : noclaims ,
expectedEvents : noevents ,
errors : noerrors ,
test : wrapTestWithReclaimCalls ( operationDelete , [ ] error { nil } , testSyncVolume ) ,
2022-02-09 12:50:56 -05:00
} ,
2016-05-17 08:55:23 -04:00
}
2022-11-03 05:19:04 -04:00
runSyncTests ( t , ctx , tests , [ ] * storage . StorageClass { } , [ ] * v1 . Pod { } )
2016-05-17 08:55:23 -04:00
}
// Test multiple calls to syncClaim/syncVolume and periodic sync of all
// volume/claims. The test follows this pattern:
2022-07-19 20:54:13 -04:00
// 0. Load the controller with initial data.
// 1. Call controllerTest.testCall() once as in TestSync()
// 2. For all volumes/claims changed by previous syncVolume/syncClaim calls,
// call appropriate syncVolume/syncClaim (simulating "volume/claim changed"
// events). Go to 2. if these calls change anything.
// 3. When all changes are processed and no new changes were made, call
// syncVolume/syncClaim on all volumes/claims (simulating "periodic sync").
// 4. If some changes were done by step 3., go to 2. (simulation of
// "volume/claim updated" events, eventually performing step 3. again)
// 5. When 3. does not do any changes, finish the tests and compare final set
// of volumes/claims with expected claims/volumes and report differences.
//
2016-05-17 08:55:23 -04:00
// Some limit of calls in enforced to prevent endless loops.
func TestDeleteMultiSync ( t * testing . T ) {
tests := [ ] controllerTest {
{
// delete failure - delete returns error. The controller should
// try again.
2022-08-04 09:30:23 -04:00
name : "9-1 - delete returns error" ,
initialVolumes : volumesWithFinalizers ( newVolumeArray ( "volume9-1" , "1Gi" , "uid9-1" , "claim9-1" , v1 . VolumeBound , v1 . PersistentVolumeReclaimDelete , classEmpty ) , [ ] string { volume . PVDeletionInTreeProtectionFinalizer } ) ,
expectedVolumes : novolumes ,
initialClaims : noclaims ,
expectedClaims : noclaims ,
expectedEvents : [ ] string { "Warning VolumeFailedDelete" } ,
errors : noerrors ,
test : wrapTestWithReclaimCalls ( operationDelete , [ ] error { errors . New ( "Mock delete error" ) , nil } , testSyncVolume ) ,
2016-05-17 08:55:23 -04:00
} ,
}
2022-11-03 05:19:04 -04:00
_ , ctx := ktesting . NewTestContext ( t )
runMultisyncTests ( t , ctx , tests , [ ] * storage . StorageClass { } , "" )
2016-05-17 08:55:23 -04:00
}