Split snapshot controller using beta APIs
This commit is contained in:
1469
pkg/common-controller/framework_test.go
Normal file
1469
pkg/common-controller/framework_test.go
Normal file
File diff suppressed because it is too large
Load Diff
1190
pkg/common-controller/snapshot_controller.go
Normal file
1190
pkg/common-controller/snapshot_controller.go
Normal file
File diff suppressed because it is too large
Load Diff
462
pkg/common-controller/snapshot_controller_base.go
Normal file
462
pkg/common-controller/snapshot_controller_base.go
Normal file
@@ -0,0 +1,462 @@
|
||||
/*
|
||||
Copyright 2019 The Kubernetes Authors.
|
||||
|
||||
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 common_controller
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
crdv1 "github.com/kubernetes-csi/external-snapshotter/pkg/apis/volumesnapshot/v1beta1"
|
||||
clientset "github.com/kubernetes-csi/external-snapshotter/pkg/client/clientset/versioned"
|
||||
storageinformers "github.com/kubernetes-csi/external-snapshotter/pkg/client/informers/externalversions/volumesnapshot/v1beta1"
|
||||
storagelisters "github.com/kubernetes-csi/external-snapshotter/pkg/client/listers/volumesnapshot/v1beta1"
|
||||
"github.com/kubernetes-csi/external-snapshotter/pkg/utils"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
coreinformers "k8s.io/client-go/informers/core/v1"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/kubernetes/scheme"
|
||||
corev1 "k8s.io/client-go/kubernetes/typed/core/v1"
|
||||
corelisters "k8s.io/client-go/listers/core/v1"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
"k8s.io/client-go/tools/record"
|
||||
"k8s.io/client-go/util/workqueue"
|
||||
"k8s.io/klog"
|
||||
"k8s.io/kubernetes/pkg/util/goroutinemap"
|
||||
)
|
||||
|
||||
type csiSnapshotCommonController struct {
|
||||
clientset clientset.Interface
|
||||
client kubernetes.Interface
|
||||
eventRecorder record.EventRecorder
|
||||
snapshotQueue workqueue.RateLimitingInterface
|
||||
contentQueue workqueue.RateLimitingInterface
|
||||
|
||||
snapshotLister storagelisters.VolumeSnapshotLister
|
||||
snapshotListerSynced cache.InformerSynced
|
||||
contentLister storagelisters.VolumeSnapshotContentLister
|
||||
contentListerSynced cache.InformerSynced
|
||||
classLister storagelisters.VolumeSnapshotClassLister
|
||||
classListerSynced cache.InformerSynced
|
||||
pvcLister corelisters.PersistentVolumeClaimLister
|
||||
pvcListerSynced cache.InformerSynced
|
||||
|
||||
snapshotStore cache.Store
|
||||
contentStore cache.Store
|
||||
|
||||
// Map of scheduled/running operations.
|
||||
runningOperations goroutinemap.GoRoutineMap
|
||||
|
||||
createSnapshotContentRetryCount int
|
||||
createSnapshotContentInterval time.Duration
|
||||
resyncPeriod time.Duration
|
||||
}
|
||||
|
||||
// NewCSISnapshotController returns a new *csiSnapshotCommonController
|
||||
func NewCSISnapshotCommonController(
|
||||
clientset clientset.Interface,
|
||||
client kubernetes.Interface,
|
||||
volumeSnapshotInformer storageinformers.VolumeSnapshotInformer,
|
||||
volumeSnapshotContentInformer storageinformers.VolumeSnapshotContentInformer,
|
||||
volumeSnapshotClassInformer storageinformers.VolumeSnapshotClassInformer,
|
||||
pvcInformer coreinformers.PersistentVolumeClaimInformer,
|
||||
createSnapshotContentRetryCount int,
|
||||
createSnapshotContentInterval time.Duration,
|
||||
resyncPeriod time.Duration,
|
||||
) *csiSnapshotCommonController {
|
||||
broadcaster := record.NewBroadcaster()
|
||||
broadcaster.StartLogging(klog.Infof)
|
||||
broadcaster.StartRecordingToSink(&corev1.EventSinkImpl{Interface: client.CoreV1().Events(v1.NamespaceAll)})
|
||||
var eventRecorder record.EventRecorder
|
||||
eventRecorder = broadcaster.NewRecorder(scheme.Scheme, v1.EventSource{Component: fmt.Sprintf("snapshot-controller")})
|
||||
|
||||
ctrl := &csiSnapshotCommonController{
|
||||
clientset: clientset,
|
||||
client: client,
|
||||
eventRecorder: eventRecorder,
|
||||
runningOperations: goroutinemap.NewGoRoutineMap(true),
|
||||
createSnapshotContentRetryCount: createSnapshotContentRetryCount,
|
||||
createSnapshotContentInterval: createSnapshotContentInterval,
|
||||
resyncPeriod: resyncPeriod,
|
||||
snapshotStore: cache.NewStore(cache.DeletionHandlingMetaNamespaceKeyFunc),
|
||||
contentStore: cache.NewStore(cache.DeletionHandlingMetaNamespaceKeyFunc),
|
||||
snapshotQueue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "snapshot-controller-snapshot"),
|
||||
contentQueue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "snapshot-controller-content"),
|
||||
}
|
||||
|
||||
ctrl.pvcLister = pvcInformer.Lister()
|
||||
ctrl.pvcListerSynced = pvcInformer.Informer().HasSynced
|
||||
|
||||
volumeSnapshotInformer.Informer().AddEventHandlerWithResyncPeriod(
|
||||
cache.ResourceEventHandlerFuncs{
|
||||
AddFunc: func(obj interface{}) { ctrl.enqueueSnapshotWork(obj) },
|
||||
UpdateFunc: func(oldObj, newObj interface{}) { ctrl.enqueueSnapshotWork(newObj) },
|
||||
DeleteFunc: func(obj interface{}) { ctrl.enqueueSnapshotWork(obj) },
|
||||
},
|
||||
ctrl.resyncPeriod,
|
||||
)
|
||||
ctrl.snapshotLister = volumeSnapshotInformer.Lister()
|
||||
ctrl.snapshotListerSynced = volumeSnapshotInformer.Informer().HasSynced
|
||||
|
||||
volumeSnapshotContentInformer.Informer().AddEventHandlerWithResyncPeriod(
|
||||
cache.ResourceEventHandlerFuncs{
|
||||
AddFunc: func(obj interface{}) { ctrl.enqueueContentWork(obj) },
|
||||
UpdateFunc: func(oldObj, newObj interface{}) { ctrl.enqueueContentWork(newObj) },
|
||||
DeleteFunc: func(obj interface{}) { ctrl.enqueueContentWork(obj) },
|
||||
},
|
||||
ctrl.resyncPeriod,
|
||||
)
|
||||
ctrl.contentLister = volumeSnapshotContentInformer.Lister()
|
||||
ctrl.contentListerSynced = volumeSnapshotContentInformer.Informer().HasSynced
|
||||
|
||||
ctrl.classLister = volumeSnapshotClassInformer.Lister()
|
||||
ctrl.classListerSynced = volumeSnapshotClassInformer.Informer().HasSynced
|
||||
|
||||
return ctrl
|
||||
}
|
||||
|
||||
func (ctrl *csiSnapshotCommonController) Run(workers int, stopCh <-chan struct{}) {
|
||||
defer ctrl.snapshotQueue.ShutDown()
|
||||
defer ctrl.contentQueue.ShutDown()
|
||||
|
||||
klog.Infof("Starting snapshot controller")
|
||||
defer klog.Infof("Shutting snapshot controller")
|
||||
|
||||
if !cache.WaitForCacheSync(stopCh, ctrl.snapshotListerSynced, ctrl.contentListerSynced, ctrl.classListerSynced, ctrl.pvcListerSynced) {
|
||||
klog.Errorf("Cannot sync caches")
|
||||
return
|
||||
}
|
||||
|
||||
ctrl.initializeCaches(ctrl.snapshotLister, ctrl.contentLister)
|
||||
|
||||
for i := 0; i < workers; i++ {
|
||||
go wait.Until(ctrl.snapshotWorker, 0, stopCh)
|
||||
go wait.Until(ctrl.contentWorker, 0, stopCh)
|
||||
}
|
||||
|
||||
<-stopCh
|
||||
}
|
||||
|
||||
// enqueueSnapshotWork adds snapshot to given work queue.
|
||||
func (ctrl *csiSnapshotCommonController) enqueueSnapshotWork(obj interface{}) {
|
||||
// Beware of "xxx deleted" events
|
||||
if unknown, ok := obj.(cache.DeletedFinalStateUnknown); ok && unknown.Obj != nil {
|
||||
obj = unknown.Obj
|
||||
}
|
||||
if snapshot, ok := obj.(*crdv1.VolumeSnapshot); ok {
|
||||
objName, err := cache.DeletionHandlingMetaNamespaceKeyFunc(snapshot)
|
||||
if err != nil {
|
||||
klog.Errorf("failed to get key from object: %v, %v", err, snapshot)
|
||||
return
|
||||
}
|
||||
klog.V(5).Infof("enqueued %q for sync", objName)
|
||||
ctrl.snapshotQueue.Add(objName)
|
||||
}
|
||||
}
|
||||
|
||||
// enqueueContentWork adds snapshot content to given work queue.
|
||||
func (ctrl *csiSnapshotCommonController) enqueueContentWork(obj interface{}) {
|
||||
// Beware of "xxx deleted" events
|
||||
if unknown, ok := obj.(cache.DeletedFinalStateUnknown); ok && unknown.Obj != nil {
|
||||
obj = unknown.Obj
|
||||
}
|
||||
if content, ok := obj.(*crdv1.VolumeSnapshotContent); ok {
|
||||
objName, err := cache.DeletionHandlingMetaNamespaceKeyFunc(content)
|
||||
if err != nil {
|
||||
klog.Errorf("failed to get key from object: %v, %v", err, content)
|
||||
return
|
||||
}
|
||||
klog.V(5).Infof("enqueued %q for sync", objName)
|
||||
ctrl.contentQueue.Add(objName)
|
||||
}
|
||||
}
|
||||
|
||||
// snapshotWorker processes items from snapshotQueue. It must run only once,
|
||||
// syncSnapshot is not assured to be reentrant.
|
||||
func (ctrl *csiSnapshotCommonController) snapshotWorker() {
|
||||
workFunc := func() bool {
|
||||
keyObj, quit := ctrl.snapshotQueue.Get()
|
||||
if quit {
|
||||
return true
|
||||
}
|
||||
defer ctrl.snapshotQueue.Done(keyObj)
|
||||
key := keyObj.(string)
|
||||
klog.V(5).Infof("snapshotWorker[%s]", key)
|
||||
|
||||
namespace, name, err := cache.SplitMetaNamespaceKey(key)
|
||||
klog.V(5).Infof("snapshotWorker: snapshot namespace [%s] name [%s]", namespace, name)
|
||||
if err != nil {
|
||||
klog.Errorf("error getting namespace & name of snapshot %q to get snapshot from informer: %v", key, err)
|
||||
return false
|
||||
}
|
||||
snapshot, err := ctrl.snapshotLister.VolumeSnapshots(namespace).Get(name)
|
||||
if err == nil {
|
||||
// The volume snapshot still exists in informer cache, the event must have
|
||||
// been add/update/sync
|
||||
newSnapshot, err := ctrl.checkAndUpdateSnapshotClass(snapshot)
|
||||
if err == nil {
|
||||
klog.V(5).Infof("passed checkAndUpdateSnapshotClass for snapshot %q", key)
|
||||
ctrl.updateSnapshot(newSnapshot)
|
||||
}
|
||||
return false
|
||||
}
|
||||
if err != nil && !errors.IsNotFound(err) {
|
||||
klog.V(2).Infof("error getting snapshot %q from informer: %v", key, err)
|
||||
return false
|
||||
}
|
||||
// The snapshot is not in informer cache, the event must have been "delete"
|
||||
vsObj, found, err := ctrl.snapshotStore.GetByKey(key)
|
||||
if err != nil {
|
||||
klog.V(2).Infof("error getting snapshot %q from cache: %v", key, err)
|
||||
return false
|
||||
}
|
||||
if !found {
|
||||
// The controller has already processed the delete event and
|
||||
// deleted the snapshot from its cache
|
||||
klog.V(2).Infof("deletion of snapshot %q was already processed", key)
|
||||
return false
|
||||
}
|
||||
snapshot, ok := vsObj.(*crdv1.VolumeSnapshot)
|
||||
if !ok {
|
||||
klog.Errorf("expected vs, got %+v", vsObj)
|
||||
return false
|
||||
}
|
||||
newSnapshot, err := ctrl.checkAndUpdateSnapshotClass(snapshot)
|
||||
if err == nil {
|
||||
ctrl.deleteSnapshot(newSnapshot)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
for {
|
||||
if quit := workFunc(); quit {
|
||||
klog.Infof("snapshot worker queue shutting down")
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// contentWorker processes items from contentQueue. It must run only once,
|
||||
// syncContent is not assured to be reentrant.
|
||||
func (ctrl *csiSnapshotCommonController) contentWorker() {
|
||||
workFunc := func() bool {
|
||||
keyObj, quit := ctrl.contentQueue.Get()
|
||||
if quit {
|
||||
return true
|
||||
}
|
||||
defer ctrl.contentQueue.Done(keyObj)
|
||||
key := keyObj.(string)
|
||||
klog.V(5).Infof("contentWorker[%s]", key)
|
||||
|
||||
_, name, err := cache.SplitMetaNamespaceKey(key)
|
||||
if err != nil {
|
||||
klog.V(4).Infof("error getting name of snapshotContent %q to get snapshotContent from informer: %v", key, err)
|
||||
return false
|
||||
}
|
||||
content, err := ctrl.contentLister.Get(name)
|
||||
// The content still exists in informer cache, the event must have
|
||||
// been add/update/sync
|
||||
if err == nil {
|
||||
ctrl.updateContent(content)
|
||||
return false
|
||||
}
|
||||
if !errors.IsNotFound(err) {
|
||||
klog.V(2).Infof("error getting content %q from informer: %v", key, err)
|
||||
return false
|
||||
}
|
||||
|
||||
// The content is not in informer cache, the event must have been
|
||||
// "delete"
|
||||
contentObj, found, err := ctrl.contentStore.GetByKey(key)
|
||||
if err != nil {
|
||||
klog.V(2).Infof("error getting content %q from cache: %v", key, err)
|
||||
return false
|
||||
}
|
||||
if !found {
|
||||
// The controller has already processed the delete event and
|
||||
// deleted the content from its cache
|
||||
klog.V(2).Infof("deletion of content %q was already processed", key)
|
||||
return false
|
||||
}
|
||||
content, ok := contentObj.(*crdv1.VolumeSnapshotContent)
|
||||
if !ok {
|
||||
klog.Errorf("expected content, got %+v", content)
|
||||
return false
|
||||
}
|
||||
ctrl.deleteContent(content)
|
||||
return false
|
||||
}
|
||||
|
||||
for {
|
||||
if quit := workFunc(); quit {
|
||||
klog.Infof("content worker queue shutting down")
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// checkAndUpdateSnapshotClass gets the VolumeSnapshotClass from VolumeSnapshot. If it is not set,
|
||||
// gets it from default VolumeSnapshotClass and sets it.
|
||||
func (ctrl *csiSnapshotCommonController) checkAndUpdateSnapshotClass(snapshot *crdv1.VolumeSnapshot) (*crdv1.VolumeSnapshot, error) {
|
||||
className := snapshot.Spec.VolumeSnapshotClassName
|
||||
var class *crdv1.VolumeSnapshotClass
|
||||
var err error
|
||||
newSnapshot := snapshot
|
||||
if className != nil {
|
||||
klog.V(5).Infof("checkAndUpdateSnapshotClass [%s]: VolumeSnapshotClassName [%s]", snapshot.Name, *className)
|
||||
class, err = ctrl.getSnapshotClass(*className)
|
||||
if err != nil {
|
||||
klog.Errorf("checkAndUpdateSnapshotClass failed to getSnapshotClass %v", err)
|
||||
ctrl.updateSnapshotErrorStatusWithEvent(snapshot, v1.EventTypeWarning, "GetSnapshotClassFailed", fmt.Sprintf("Failed to get snapshot class with error %v", err))
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
klog.V(5).Infof("checkAndUpdateSnapshotClass [%s]: SetDefaultSnapshotClass", snapshot.Name)
|
||||
class, newSnapshot, err = ctrl.SetDefaultSnapshotClass(snapshot)
|
||||
if err != nil {
|
||||
klog.Errorf("checkAndUpdateSnapshotClass failed to setDefaultClass %v", err)
|
||||
ctrl.updateSnapshotErrorStatusWithEvent(snapshot, v1.EventTypeWarning, "SetDefaultSnapshotClassFailed", fmt.Sprintf("Failed to set default snapshot class with error %v", err))
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// For pre-provisioned snapshots, we may not have snapshot class
|
||||
if class != nil {
|
||||
klog.V(5).Infof("VolumeSnapshotClass [%s] Driver [%s]", class.Name, class.Driver)
|
||||
}
|
||||
return newSnapshot, nil
|
||||
}
|
||||
|
||||
// updateSnapshot runs in worker thread and handles "snapshot added",
|
||||
// "snapshot updated" and "periodic sync" events.
|
||||
func (ctrl *csiSnapshotCommonController) updateSnapshot(snapshot *crdv1.VolumeSnapshot) {
|
||||
// Store the new snapshot version in the cache and do not process it if this is
|
||||
// an old version.
|
||||
klog.V(5).Infof("updateSnapshot %q", utils.SnapshotKey(snapshot))
|
||||
newSnapshot, err := ctrl.storeSnapshotUpdate(snapshot)
|
||||
if err != nil {
|
||||
klog.Errorf("%v", err)
|
||||
}
|
||||
if !newSnapshot {
|
||||
return
|
||||
}
|
||||
err = ctrl.syncSnapshot(snapshot)
|
||||
if err != nil {
|
||||
if errors.IsConflict(err) {
|
||||
// Version conflict error happens quite often and the controller
|
||||
// recovers from it easily.
|
||||
klog.V(3).Infof("could not sync claim %q: %+v", utils.SnapshotKey(snapshot), err)
|
||||
} else {
|
||||
klog.Errorf("could not sync volume %q: %+v", utils.SnapshotKey(snapshot), err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// updateContent runs in worker thread and handles "content added",
|
||||
// "content updated" and "periodic sync" events.
|
||||
func (ctrl *csiSnapshotCommonController) updateContent(content *crdv1.VolumeSnapshotContent) {
|
||||
// Store the new content version in the cache and do not process it if this is
|
||||
// an old version.
|
||||
new, err := ctrl.storeContentUpdate(content)
|
||||
if err != nil {
|
||||
klog.Errorf("%v", err)
|
||||
}
|
||||
if !new {
|
||||
return
|
||||
}
|
||||
err = ctrl.syncContent(content)
|
||||
if err != nil {
|
||||
if errors.IsConflict(err) {
|
||||
// Version conflict error happens quite often and the controller
|
||||
// recovers from it easily.
|
||||
klog.V(3).Infof("could not sync content %q: %+v", content.Name, err)
|
||||
} else {
|
||||
klog.Errorf("could not sync content %q: %+v", content.Name, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// deleteSnapshot runs in worker thread and handles "snapshot deleted" event.
|
||||
func (ctrl *csiSnapshotCommonController) deleteSnapshot(snapshot *crdv1.VolumeSnapshot) {
|
||||
_ = ctrl.snapshotStore.Delete(snapshot)
|
||||
klog.V(4).Infof("snapshot %q deleted", utils.SnapshotKey(snapshot))
|
||||
|
||||
snapshotContentName := ""
|
||||
if snapshot.Status != nil && snapshot.Status.BoundVolumeSnapshotContentName != nil {
|
||||
snapshotContentName = *snapshot.Status.BoundVolumeSnapshotContentName
|
||||
}
|
||||
if snapshotContentName == "" {
|
||||
klog.V(5).Infof("deleteSnapshot[%q]: content not bound", utils.SnapshotKey(snapshot))
|
||||
return
|
||||
}
|
||||
// sync the content when its snapshot is deleted. Explicitly sync'ing the
|
||||
// content here in response to snapshot deletion prevents the content from
|
||||
// waiting until the next sync period for its Release.
|
||||
klog.V(5).Infof("deleteSnapshot[%q]: scheduling sync of content %s", utils.SnapshotKey(snapshot), snapshotContentName)
|
||||
ctrl.contentQueue.Add(snapshotContentName)
|
||||
}
|
||||
|
||||
// deleteContent runs in worker thread and handles "content deleted" event.
|
||||
func (ctrl *csiSnapshotCommonController) deleteContent(content *crdv1.VolumeSnapshotContent) {
|
||||
_ = ctrl.contentStore.Delete(content)
|
||||
klog.V(4).Infof("content %q deleted", content.Name)
|
||||
|
||||
snapshotName := utils.SnapshotRefKey(&content.Spec.VolumeSnapshotRef)
|
||||
if snapshotName == "" {
|
||||
klog.V(5).Infof("deleteContent[%q]: content not bound", content.Name)
|
||||
return
|
||||
}
|
||||
// sync the snapshot when its content is deleted. Explicitly sync'ing the
|
||||
// snapshot here in response to content deletion prevents the snapshot from
|
||||
// waiting until the next sync period for its Release.
|
||||
klog.V(5).Infof("deleteContent[%q]: scheduling sync of snapshot %s", content.Name, snapshotName)
|
||||
ctrl.snapshotQueue.Add(snapshotName)
|
||||
}
|
||||
|
||||
// initializeCaches fills all controller caches with initial data from etcd in
|
||||
// order to have the caches already filled when first addSnapshot/addContent to
|
||||
// perform initial synchronization of the controller.
|
||||
func (ctrl *csiSnapshotCommonController) initializeCaches(snapshotLister storagelisters.VolumeSnapshotLister, contentLister storagelisters.VolumeSnapshotContentLister) {
|
||||
snapshotList, err := snapshotLister.List(labels.Everything())
|
||||
if err != nil {
|
||||
klog.Errorf("CSISnapshotController can't initialize caches: %v", err)
|
||||
return
|
||||
}
|
||||
for _, snapshot := range snapshotList {
|
||||
snapshotClone := snapshot.DeepCopy()
|
||||
if _, err = ctrl.storeSnapshotUpdate(snapshotClone); err != nil {
|
||||
klog.Errorf("error updating volume snapshot cache: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
contentList, err := contentLister.List(labels.Everything())
|
||||
if err != nil {
|
||||
klog.Errorf("CSISnapshotController can't initialize caches: %v", err)
|
||||
return
|
||||
}
|
||||
for _, content := range contentList {
|
||||
contentClone := content.DeepCopy()
|
||||
if _, err = ctrl.storeContentUpdate(contentClone); err != nil {
|
||||
klog.Errorf("error updating volume snapshot content cache: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
klog.V(4).Infof("controller initialized")
|
||||
}
|
94
pkg/common-controller/snapshot_controller_test.go
Normal file
94
pkg/common-controller/snapshot_controller_test.go
Normal file
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
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 common_controller
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
crdv1 "github.com/kubernetes-csi/external-snapshotter/pkg/apis/volumesnapshot/v1beta1"
|
||||
"github.com/kubernetes-csi/external-snapshotter/pkg/utils"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
)
|
||||
|
||||
var deletionPolicy = crdv1.VolumeSnapshotContentDelete
|
||||
|
||||
func storeVersion(t *testing.T, prefix string, c cache.Store, version string, expectedReturn bool) {
|
||||
content := newContent("contentName", "snapuid1-1", "snap1-1", "sid1-1", classGold, "", "pv-handle-1-1", deletionPolicy, nil, nil, false, true)
|
||||
content.ResourceVersion = version
|
||||
ret, err := utils.StoreObjectUpdate(c, content, "content")
|
||||
if err != nil {
|
||||
t.Errorf("%s: expected storeObjectUpdate to succeed, got: %v", prefix, err)
|
||||
}
|
||||
if expectedReturn != ret {
|
||||
t.Errorf("%s: expected storeObjectUpdate to return %v, got: %v", prefix, expectedReturn, ret)
|
||||
}
|
||||
|
||||
// find the stored version
|
||||
|
||||
contentObj, found, err := c.GetByKey("contentName")
|
||||
if err != nil {
|
||||
t.Errorf("expected content 'contentName' in the cache, got error instead: %v", err)
|
||||
}
|
||||
if !found {
|
||||
t.Errorf("expected content 'contentName' in the cache but it was not found")
|
||||
}
|
||||
content, ok := contentObj.(*crdv1.VolumeSnapshotContent)
|
||||
if !ok {
|
||||
t.Errorf("expected content in the cache, got different object instead: %#v", contentObj)
|
||||
}
|
||||
|
||||
if ret {
|
||||
if content.ResourceVersion != version {
|
||||
t.Errorf("expected content with version %s in the cache, got %s instead", version, content.ResourceVersion)
|
||||
}
|
||||
} else {
|
||||
if content.ResourceVersion == version {
|
||||
t.Errorf("expected content with version other than %s in the cache, got %s instead", version, content.ResourceVersion)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestControllerCache tests func storeObjectUpdate()
|
||||
func TestControllerCache(t *testing.T) {
|
||||
// Cache under test
|
||||
c := cache.NewStore(cache.DeletionHandlingMetaNamespaceKeyFunc)
|
||||
|
||||
// Store new PV
|
||||
storeVersion(t, "Step1", c, "1", true)
|
||||
// Store the same PV
|
||||
storeVersion(t, "Step2", c, "1", true)
|
||||
// Store newer PV
|
||||
storeVersion(t, "Step3", c, "2", true)
|
||||
// Store older PV - simulating old "PV updated" event or periodic sync with
|
||||
// old data
|
||||
storeVersion(t, "Step4", c, "1", false)
|
||||
// Store newer PV - test integer parsing ("2" > "10" as string,
|
||||
// while 2 < 10 as integers)
|
||||
storeVersion(t, "Step5", c, "10", true)
|
||||
}
|
||||
|
||||
func TestControllerCacheParsingError(t *testing.T) {
|
||||
c := cache.NewStore(cache.DeletionHandlingMetaNamespaceKeyFunc)
|
||||
// There must be something in the cache to compare with
|
||||
storeVersion(t, "Step1", c, "1", true)
|
||||
content := newContent("contentName", "snapuid1-1", "snap1-1", "sid1-1", classGold, "", "pv-handle-1-1", deletionPolicy, nil, nil, false, true)
|
||||
content.ResourceVersion = "xxx"
|
||||
_, err := utils.StoreObjectUpdate(c, content, "content")
|
||||
if err == nil {
|
||||
t.Errorf("Expected parsing error, got nil instead")
|
||||
}
|
||||
}
|
295
pkg/common-controller/snapshot_create_test.go
Normal file
295
pkg/common-controller/snapshot_create_test.go
Normal file
@@ -0,0 +1,295 @@
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
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 common_controller
|
||||
|
||||
import (
|
||||
//"errors"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
crdv1 "github.com/kubernetes-csi/external-snapshotter/pkg/apis/volumesnapshot/v1beta1"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
storage "k8s.io/api/storage/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
var timeNow = time.Now()
|
||||
var timeNowStamp = timeNow.UnixNano()
|
||||
var False = false
|
||||
var True = true
|
||||
|
||||
var metaTimeNowUnix = &metav1.Time{
|
||||
Time: timeNow,
|
||||
}
|
||||
|
||||
var defaultSize int64 = 1000
|
||||
var deletePolicy = crdv1.VolumeSnapshotContentDelete
|
||||
var retainPolicy = crdv1.VolumeSnapshotContentRetain
|
||||
var sameDriverStorageClass = &storage.StorageClass{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "StorageClass",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "sameDriver",
|
||||
},
|
||||
Provisioner: mockDriverName,
|
||||
Parameters: class1Parameters,
|
||||
}
|
||||
|
||||
var diffDriverStorageClass = &storage.StorageClass{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "StorageClass",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "diffDriver",
|
||||
},
|
||||
Provisioner: mockDriverName,
|
||||
Parameters: class1Parameters,
|
||||
}
|
||||
|
||||
// Test single call to SyncSnapshot, expecting create snapshot to happen.
|
||||
// 1. Fill in the controller with initial data
|
||||
// 2. Call the SyncSnapshot *once*.
|
||||
// 3. Compare resulting contents with expected contents.
|
||||
func TestCreateSnapshotSync(t *testing.T) {
|
||||
|
||||
tests := []controllerTest{
|
||||
{
|
||||
name: "6-1 - successful create snapshot with snapshot class gold",
|
||||
initialContents: nocontents,
|
||||
expectedContents: newContentArrayNoStatus("snapcontent-snapuid6-1", "snapuid6-1", "snap6-1", "sid6-1", classGold, "", "pv-handle6-1", deletionPolicy, nil, nil, false, false),
|
||||
initialSnapshots: newSnapshotArray("snap6-1", "snapuid6-1", "claim6-1", "", classGold, "", &False, nil, nil, nil, false),
|
||||
expectedSnapshots: newSnapshotArray("snap6-1", "snapuid6-1", "claim6-1", "", classGold, "snapcontent-snapuid6-1", &False, nil, nil, nil, false),
|
||||
initialClaims: newClaimArray("claim6-1", "pvc-uid6-1", "1Gi", "volume6-1", v1.ClaimBound, &classEmpty),
|
||||
initialVolumes: newVolumeArray("volume6-1", "pv-uid6-1", "pv-handle6-1", "1Gi", "pvc-uid6-1", "claim6-1", v1.VolumeBound, v1.PersistentVolumeReclaimDelete, classEmpty),
|
||||
/*expectedCreateCalls: []createCall{
|
||||
{
|
||||
snapshotName: "snapshot-snapuid6-1",
|
||||
volume: newVolume("volume6-1", "pv-uid6-1", "pv-handle6-1", "1Gi", "pvc-uid6-1", "claim6-1", v1.VolumeBound, v1.PersistentVolumeReclaimDelete, classEmpty),
|
||||
parameters: map[string]string{"param1": "value1"},
|
||||
// information to return
|
||||
driverName: mockDriverName,
|
||||
size: defaultSize,
|
||||
snapshotId: "sid6-1",
|
||||
creationTime: timeNow,
|
||||
readyToUse: True,
|
||||
},
|
||||
},*/
|
||||
errors: noerrors,
|
||||
test: testSyncSnapshot,
|
||||
},
|
||||
{
|
||||
name: "6-2 - successful create snapshot with snapshot class silver",
|
||||
initialContents: nocontents,
|
||||
expectedContents: newContentArrayNoStatus("snapcontent-snapuid6-2", "snapuid6-2", "snap6-2", "sid6-2", classSilver, "", "pv-handle6-2", deletionPolicy, nil, nil, false, false),
|
||||
initialSnapshots: newSnapshotArray("snap6-2", "snapuid6-2", "claim6-2", "", classSilver, "", &False, nil, nil, nil, false),
|
||||
expectedSnapshots: newSnapshotArray("snap6-2", "snapuid6-2", "claim6-2", "", classSilver, "snapcontent-snapuid6-2", &False, nil, nil, nil, false),
|
||||
initialClaims: newClaimArray("claim6-2", "pvc-uid6-2", "1Gi", "volume6-2", v1.ClaimBound, &classEmpty),
|
||||
initialVolumes: newVolumeArray("volume6-2", "pv-uid6-2", "pv-handle6-2", "1Gi", "pvc-uid6-2", "claim6-2", v1.VolumeBound, v1.PersistentVolumeReclaimDelete, classEmpty),
|
||||
/*expectedCreateCalls: []createCall{
|
||||
{
|
||||
snapshotName: "snapshot-snapuid6-2",
|
||||
volume: newVolume("volume6-2", "pv-uid6-2", "pv-handle6-2", "1Gi", "pvc-uid6-2", "claim6-2", v1.VolumeBound, v1.PersistentVolumeReclaimDelete, classEmpty),
|
||||
parameters: map[string]string{"param2": "value2"},
|
||||
// information to return
|
||||
driverName: mockDriverName,
|
||||
size: defaultSize,
|
||||
snapshotId: "sid6-2",
|
||||
creationTime: timeNow,
|
||||
readyToUse: True,
|
||||
},
|
||||
},*/
|
||||
errors: noerrors,
|
||||
test: testSyncSnapshot,
|
||||
},
|
||||
{
|
||||
name: "7-1 - fail to create snapshot with non-existing snapshot class",
|
||||
initialContents: nocontents,
|
||||
expectedContents: nocontents,
|
||||
initialSnapshots: newSnapshotArray("snap7-1", "snapuid7-1", "claim7-1", "", classNonExisting, "", &False, nil, nil, nil, false),
|
||||
expectedSnapshots: newSnapshotArray("snap7-1", "snapuid7-1", "claim7-1", "", classNonExisting, "", &False, nil, nil, newVolumeError("Failed to create snapshot content with error failed to get input parameters to create snapshot snap7-1: \"failed to retrieve snapshot class non-existing from the informer: \\\"volumesnapshotclass.snapshot.storage.k8s.io \\\\\\\"non-existing\\\\\\\" not found\\\"\""), false),
|
||||
initialClaims: newClaimArray("claim7-1", "pvc-uid7-1", "1Gi", "volume7-1", v1.ClaimBound, &classEmpty),
|
||||
initialVolumes: newVolumeArray("volume7-1", "pv-uid7-1", "pv-handle7-1", "1Gi", "pvc-uid7-1", "claim7-1", v1.VolumeBound, v1.PersistentVolumeReclaimDelete, classEmpty),
|
||||
expectedEvents: []string{"Warning SnapshotContentCreationFailed"},
|
||||
errors: noerrors,
|
||||
expectSuccess: false,
|
||||
test: testSyncSnapshot,
|
||||
},
|
||||
/*{
|
||||
name: "7-2 - fail to create snapshot with snapshot class invalid-secret-class",
|
||||
initialContents: nocontents,
|
||||
expectedContents: nocontents,
|
||||
initialSnapshots: newSnapshotArray("snap7-2", "snapuid7-2", "claim7-2", "", invalidSecretClass, "", &False, nil, nil, nil),
|
||||
expectedSnapshots: newSnapshotArray("snap7-2", "snapuid7-2", "claim7-2", "", invalidSecretClass, "", &False, nil, nil, newVolumeError("Failed to create snapshot: failed to get input parameters to create snapshot snap7-2: \"failed to get name and namespace template from params: either name and namespace for Snapshotter secrets specified, Both must be specified\"")),
|
||||
initialClaims: newClaimArray("claim7-2", "pvc-uid7-2", "1Gi", "volume7-2", v1.ClaimBound, &classEmpty),
|
||||
initialVolumes: newVolumeArray("volume7-2", "pv-uid7-2", "pv-handle7-2", "1Gi", "pvc-uid7-2", "claim7-2", v1.VolumeBound, v1.PersistentVolumeReclaimDelete, classEmpty),
|
||||
expectedEvents: []string{"Warning SnapshotCreationFailed"},
|
||||
errors: noerrors,
|
||||
test: testSyncSnapshot,
|
||||
},*/
|
||||
{
|
||||
name: "7-3 - fail to create snapshot without snapshot class ",
|
||||
initialContents: nocontents,
|
||||
expectedContents: nocontents,
|
||||
initialSnapshots: newSnapshotArray("snap7-3", "snapuid7-3", "claim7-3", "", "", "", &False, nil, nil, nil, false),
|
||||
expectedSnapshots: newSnapshotArray("snap7-3", "snapuid7-3", "claim7-3", "", "", "", &False, nil, nil, newVolumeError("Failed to create snapshot content with error failed to get input parameters to create snapshot snap7-3: \"failed to retrieve snapshot class from the informer: \\\"volumesnapshotclass.snapshot.storage.k8s.io \\\\\\\"\\\\\\\" not found\\\"\""), false),
|
||||
initialClaims: newClaimArray("claim7-3", "pvc-uid7-3", "1Gi", "volume7-3", v1.ClaimBound, &classEmpty),
|
||||
initialVolumes: newVolumeArray("volume7-3", "pv-uid7-3", "pv-handle7-3", "1Gi", "pvc-uid7-3", "claim7-3", v1.VolumeBound, v1.PersistentVolumeReclaimDelete, classEmpty),
|
||||
initialStorageClasses: []*storage.StorageClass{diffDriverStorageClass},
|
||||
expectedEvents: []string{"Warning SnapshotContentCreationFailed"},
|
||||
errors: noerrors,
|
||||
expectSuccess: false,
|
||||
test: testSyncSnapshot,
|
||||
},
|
||||
{
|
||||
name: "7-4 - fail create snapshot with no-existing claim",
|
||||
initialContents: nocontents,
|
||||
expectedContents: nocontents,
|
||||
initialSnapshots: newSnapshotArray("snap7-4", "snapuid7-4", "claim7-4", "", classGold, "", &False, nil, nil, nil, false),
|
||||
expectedSnapshots: newSnapshotArray("snap7-4", "snapuid7-4", "claim7-4", "", classGold, "", &False, nil, nil, newVolumeError("Failed to create snapshot content with error failed to get input parameters to create snapshot snap7-4: \"failed to retrieve PVC claim7-4 from the lister: \\\"persistentvolumeclaim \\\\\\\"claim7-4\\\\\\\" not found\\\"\""), false),
|
||||
initialVolumes: newVolumeArray("volume7-4", "pv-uid7-4", "pv-handle7-4", "1Gi", "pvc-uid7-4", "claim7-4", v1.VolumeBound, v1.PersistentVolumeReclaimDelete, classEmpty),
|
||||
expectedEvents: []string{"Warning SnapshotContentCreationFailed"},
|
||||
errors: noerrors,
|
||||
expectSuccess: false,
|
||||
test: testSyncSnapshot,
|
||||
},
|
||||
{
|
||||
name: "7-5 - fail create snapshot with no-existing volume",
|
||||
initialContents: nocontents,
|
||||
expectedContents: nocontents,
|
||||
initialSnapshots: newSnapshotArray("snap7-5", "snapuid7-5", "claim7-5", "", classGold, "", &False, nil, nil, nil, false),
|
||||
expectedSnapshots: newSnapshotArray("snap7-5", "snapuid7-5", "claim7-5", "", classGold, "", &False, nil, nil, newVolumeError("Failed to create snapshot content with error failed to get input parameters to create snapshot snap7-5: \"failed to retrieve PV volume7-5 from the API server: \\\"cannot find volume volume7-5\\\"\""), false),
|
||||
initialClaims: newClaimArray("claim7-5", "pvc-uid7-5", "1Gi", "volume7-5", v1.ClaimBound, &classEmpty),
|
||||
expectedEvents: []string{"Warning SnapshotContentCreationFailed"},
|
||||
errors: noerrors,
|
||||
expectSuccess: false,
|
||||
test: testSyncSnapshot,
|
||||
},
|
||||
{
|
||||
name: "7-6 - fail create snapshot with claim that is not yet bound",
|
||||
initialContents: nocontents,
|
||||
expectedContents: nocontents,
|
||||
initialSnapshots: newSnapshotArray("snap7-6", "snapuid7-6", "claim7-6", "", classGold, "", &False, nil, nil, nil, false),
|
||||
expectedSnapshots: newSnapshotArray("snap7-6", "snapuid7-6", "claim7-6", "", classGold, "", &False, nil, nil, newVolumeError("Failed to create snapshot content with error failed to get input parameters to create snapshot snap7-6: \"the PVC claim7-6 is not yet bound to a PV, will not attempt to take a snapshot\""), false),
|
||||
initialClaims: newClaimArray("claim7-6", "pvc-uid7-6", "1Gi", "", v1.ClaimPending, &classEmpty),
|
||||
expectedEvents: []string{"Warning SnapshotContentCreationFailed"},
|
||||
errors: noerrors,
|
||||
expectSuccess: false,
|
||||
test: testSyncSnapshot,
|
||||
},
|
||||
/*{
|
||||
name: "7-7 - fail create snapshot due to csi driver error",
|
||||
initialContents: nocontents,
|
||||
expectedContents: nocontents,
|
||||
initialSnapshots: newSnapshotArray("snap7-7", "snapuid7-7", "claim7-7", "", classGold, "", &False, nil, nil, nil),
|
||||
expectedSnapshots: newSnapshotArray("snap7-7", "snapuid7-7", "claim7-7", "", classGold, "", &False, nil, nil, newVolumeError("Failed to create snapshot content with error failed to take snapshot of the volume, volume7-7: \"mock create snapshot error\"")),
|
||||
initialClaims: newClaimArray("claim7-7", "pvc-uid7-7", "1Gi", "volume7-7", v1.ClaimBound, &classEmpty),
|
||||
initialVolumes: newVolumeArray("volume7-7", "pv-uid7-7", "pv-handle7-7", "1Gi", "pvc-uid7-7", "claim7-7", v1.VolumeBound, v1.PersistentVolumeReclaimDelete, classEmpty),
|
||||
expectedCreateCalls: []createCall{
|
||||
{
|
||||
snapshotName: "snapshot-snapuid7-7",
|
||||
volume: newVolume("volume7-7", "pv-uid7-7", "pv-handle7-7", "1Gi", "pvc-uid7-7", "claim7-7", v1.VolumeBound, v1.PersistentVolumeReclaimDelete, classEmpty),
|
||||
parameters: map[string]string{"param1": "value1"},
|
||||
// information to return
|
||||
err: errors.New("mock create snapshot error"),
|
||||
},
|
||||
},
|
||||
errors: noerrors,
|
||||
expectSuccess: false,
|
||||
expectedEvents: []string{"Warning SnapshotContentCreationFailed"},
|
||||
test: testSyncSnapshot,
|
||||
},*/
|
||||
/*{
|
||||
name: "7-8 - fail create snapshot due to cannot update snapshot status",
|
||||
initialContents: nocontents,
|
||||
expectedContents: nocontents,
|
||||
initialSnapshots: newSnapshotArray("snap7-8", "snapuid7-8", "claim7-8", "", classGold, "", &False, nil, nil, nil),
|
||||
expectedSnapshots: newSnapshotArray("snap7-8", "snapuid7-8", "claim7-8", "", classGold, "", &False, nil, nil, newVolumeError("Failed to create snapshot: snapshot controller failed to update default/snap7-8 on API server: mock update error")),
|
||||
initialClaims: newClaimArray("claim7-8", "pvc-uid7-8", "1Gi", "volume7-8", v1.ClaimBound, &classEmpty),
|
||||
initialVolumes: newVolumeArray("volume7-8", "pv-uid7-8", "pv-handle7-8", "1Gi", "pvc-uid7-8", "claim7-8", v1.VolumeBound, v1.PersistentVolumeReclaimDelete, classEmpty),
|
||||
/*expectedCreateCalls: []createCall{
|
||||
{
|
||||
snapshotName: "snapshot-snapuid7-8",
|
||||
volume: newVolume("volume7-8", "pv-uid7-8", "pv-handle7-8", "1Gi", "pvc-uid7-8", "claim7-8", v1.VolumeBound, v1.PersistentVolumeReclaimDelete, classEmpty),
|
||||
parameters: map[string]string{"param1": "value1"},
|
||||
// information to return
|
||||
driverName: mockDriverName,
|
||||
size: defaultSize,
|
||||
snapshotId: "sid7-8",
|
||||
creationTime: timeNow,
|
||||
readyToUse: True,
|
||||
},
|
||||
},*/
|
||||
/*errors: []reactorError{
|
||||
// Inject error to the forth client.VolumesnapshotV1beta1().VolumeSnapshots().Update call.
|
||||
// All other calls will succeed.
|
||||
{"update", "volumesnapshots", errors.New("mock update error")},
|
||||
{"update", "volumesnapshots", errors.New("mock update error")},
|
||||
{"update", "volumesnapshots", errors.New("mock update error")},
|
||||
},
|
||||
expectedEvents: []string{"Warning SnapshotContentCreationFailed"},
|
||||
|
||||
expectSuccess: false,
|
||||
test: testSyncSnapshot,
|
||||
},*/
|
||||
/*{
|
||||
// TODO(xiangqian): this test case needs to be revisited the scenario
|
||||
// of VolumeSnapshotContent saving failure. Since there will be no content object
|
||||
// in API server, it could potentially cause leaking issue
|
||||
name: "7-9 - fail create snapshot due to cannot save snapshot content",
|
||||
initialContents: nocontents,
|
||||
expectedContents: nocontents,
|
||||
initialSnapshots: newSnapshotArray("snap7-9", "snapuid7-9", "claim7-9", "", classGold, "", &False, nil, nil, nil),
|
||||
expectedSnapshots: newSnapshotArray("snap7-9", "snapuid7-9", "claim7-9", "", classGold, "snapcontent-snapuid7-9", &True, metaTimeNowUnix, getSize(defaultSize), nil),
|
||||
initialClaims: newClaimArray("claim7-9", "pvc-uid7-9", "1Gi", "volume7-9", v1.ClaimBound, &classEmpty),
|
||||
initialVolumes: newVolumeArray("volume7-9", "pv-uid7-9", "pv-handle7-9", "1Gi", "pvc-uid7-9", "claim7-9", v1.VolumeBound, v1.PersistentVolumeReclaimDelete, classEmpty),
|
||||
expectedCreateCalls: []createCall{
|
||||
{
|
||||
snapshotName: "snapshot-snapuid7-9",
|
||||
volume: newVolume("volume7-9", "pv-uid7-9", "pv-handle7-9", "1Gi", "pvc-uid7-9", "claim7-9", v1.VolumeBound, v1.PersistentVolumeReclaimDelete, classEmpty),
|
||||
parameters: map[string]string{"param1": "value1"},
|
||||
// information to return
|
||||
driverName: mockDriverName,
|
||||
size: defaultSize,
|
||||
snapshotId: "sid7-9",
|
||||
creationTime: timeNow,
|
||||
readyToUse: True,
|
||||
},
|
||||
},
|
||||
errors: []reactorError{
|
||||
{"create", "volumesnapshotcontents", errors.New("mock create error")},
|
||||
{"create", "volumesnapshotcontents", errors.New("mock create error")},
|
||||
{"create", "volumesnapshotcontents", errors.New("mock create error")},
|
||||
},
|
||||
expectedEvents: []string{"Warning CreateSnapshotContentFailed"},
|
||||
test: testSyncSnapshot,
|
||||
},
|
||||
{
|
||||
name: "7-10 - fail create snapshot with secret not found",
|
||||
initialContents: nocontents,
|
||||
expectedContents: nocontents,
|
||||
initialSnapshots: newSnapshotArray("snap7-10", "snapuid7-10", "claim7-10", "", validSecretClass, "", &False, nil, nil, nil),
|
||||
expectedSnapshots: newSnapshotArray("snap7-10", "snapuid7-10", "claim7-10", "", validSecretClass, "", &False, nil, nil, newVolumeError("Failed to create snapshot: error getting secret secret in namespace default: cannot find secret secret")),
|
||||
initialClaims: newClaimArray("claim7-10", "pvc-uid7-10", "1Gi", "volume7-10", v1.ClaimBound, &classEmpty),
|
||||
initialVolumes: newVolumeArray("volume7-10", "pv-uid7-10", "pv-handle7-10", "1Gi", "pvc-uid7-10", "claim7-10", v1.VolumeBound, v1.PersistentVolumeReclaimDelete, classEmpty),
|
||||
initialSecrets: []*v1.Secret{}, // no initial secret created
|
||||
errors: noerrors,
|
||||
test: testSyncSnapshot,
|
||||
},*/
|
||||
}
|
||||
runSyncTests(t, tests, snapshotClasses)
|
||||
}
|
321
pkg/common-controller/snapshot_delete_test.go
Normal file
321
pkg/common-controller/snapshot_delete_test.go
Normal file
@@ -0,0 +1,321 @@
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
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 common_controller
|
||||
|
||||
import (
|
||||
//"errors"
|
||||
"testing"
|
||||
|
||||
crdv1 "github.com/kubernetes-csi/external-snapshotter/pkg/apis/volumesnapshot/v1beta1"
|
||||
"github.com/kubernetes-csi/external-snapshotter/pkg/utils"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
var class1Parameters = map[string]string{
|
||||
"param1": "value1",
|
||||
}
|
||||
|
||||
var class2Parameters = map[string]string{
|
||||
"param2": "value2",
|
||||
}
|
||||
|
||||
var class3Parameters = map[string]string{
|
||||
"param3": "value3",
|
||||
utils.SnapshotterSecretNameKey: "name",
|
||||
}
|
||||
|
||||
var class4Parameters = map[string]string{
|
||||
utils.SnapshotterSecretNameKey: "emptysecret",
|
||||
utils.SnapshotterSecretNamespaceKey: "default",
|
||||
}
|
||||
|
||||
var class5Parameters = map[string]string{
|
||||
utils.SnapshotterSecretNameKey: "secret",
|
||||
utils.SnapshotterSecretNamespaceKey: "default",
|
||||
}
|
||||
|
||||
var snapshotClasses = []*crdv1.VolumeSnapshotClass{
|
||||
{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "VolumeSnapshotClass",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: classGold,
|
||||
},
|
||||
Driver: mockDriverName,
|
||||
Parameters: class1Parameters,
|
||||
DeletionPolicy: crdv1.VolumeSnapshotContentDelete,
|
||||
},
|
||||
{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "VolumeSnapshotClass",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: classSilver,
|
||||
},
|
||||
Driver: mockDriverName,
|
||||
Parameters: class2Parameters,
|
||||
DeletionPolicy: crdv1.VolumeSnapshotContentDelete,
|
||||
},
|
||||
{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "VolumeSnapshotClass",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: emptySecretClass,
|
||||
},
|
||||
Driver: mockDriverName,
|
||||
Parameters: class4Parameters,
|
||||
DeletionPolicy: crdv1.VolumeSnapshotContentDelete,
|
||||
},
|
||||
{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "VolumeSnapshotClass",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: invalidSecretClass,
|
||||
},
|
||||
Driver: mockDriverName,
|
||||
Parameters: class3Parameters,
|
||||
DeletionPolicy: crdv1.VolumeSnapshotContentDelete,
|
||||
},
|
||||
{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "VolumeSnapshotClass",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: validSecretClass,
|
||||
},
|
||||
Driver: mockDriverName,
|
||||
Parameters: class5Parameters,
|
||||
DeletionPolicy: crdv1.VolumeSnapshotContentDelete,
|
||||
},
|
||||
{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "VolumeSnapshotClass",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: defaultClass,
|
||||
Annotations: map[string]string{utils.IsDefaultSnapshotClassAnnotation: "true"},
|
||||
},
|
||||
Driver: mockDriverName,
|
||||
DeletionPolicy: crdv1.VolumeSnapshotContentDelete,
|
||||
},
|
||||
}
|
||||
|
||||
// Test single call to syncContent, expecting deleting to happen.
|
||||
// 1. Fill in the controller with initial data
|
||||
// 2. Call the syncContent *once*.
|
||||
// 3. Compare resulting contents with expected contents.
|
||||
func TestDeleteSync(t *testing.T) {
|
||||
tests := []controllerTest{
|
||||
{
|
||||
name: "1-1 - content with empty snapshot class is deleted if it is bound to a non-exist snapshot and also has a snapshot uid specified",
|
||||
initialContents: newContentArray("content1-1", "snapuid1-1", "snap1-1", "sid1-1", classGold, "", "", deletionPolicy, nil, nil, true),
|
||||
expectedContents: newContentArray("content1-1", "snapuid1-1", "snap1-1", "sid1-1", classGold, "", "", deletionPolicy, nil, nil, true),
|
||||
initialSnapshots: nosnapshots,
|
||||
expectedSnapshots: nosnapshots,
|
||||
expectedEvents: noevents,
|
||||
errors: noerrors,
|
||||
//expectedDeleteCalls: []deleteCall{{"sid1-1", nil, nil}},
|
||||
test: testSyncContent,
|
||||
},
|
||||
{
|
||||
name: "2-1 - content with empty snapshot class will not be deleted if it is bound to a non-exist snapshot but it does not have a snapshot uid specified",
|
||||
initialContents: newContentArray("content2-1", "", "snap2-1", "sid2-1", "", "", "", deletionPolicy, nil, nil, true),
|
||||
expectedContents: newContentArray("content2-1", "", "snap2-1", "sid2-1", "", "", "", deletionPolicy, nil, nil, true),
|
||||
initialSnapshots: nosnapshots,
|
||||
expectedSnapshots: nosnapshots,
|
||||
expectedEvents: noevents,
|
||||
errors: noerrors,
|
||||
//expectedDeleteCalls: []deleteCall{{"sid2-1", nil, nil}},
|
||||
test: testSyncContent,
|
||||
},
|
||||
{
|
||||
name: "1-2 - successful delete with snapshot class that has empty secret parameter",
|
||||
initialContents: newContentArray("content1-2", "sid1-2", "snap1-2", "sid1-2", emptySecretClass, "", "", deletionPolicy, nil, nil, true),
|
||||
expectedContents: newContentArray("content1-2", "sid1-2", "snap1-2", "sid1-2", emptySecretClass, "", "", deletionPolicy, nil, nil, true),
|
||||
initialSnapshots: nosnapshots,
|
||||
expectedSnapshots: nosnapshots,
|
||||
initialSecrets: []*v1.Secret{emptySecret()},
|
||||
expectedEvents: noevents,
|
||||
errors: noerrors,
|
||||
//expectedDeleteCalls: []deleteCall{{"sid1-2", map[string]string{}, nil}},
|
||||
test: testSyncContent,
|
||||
},
|
||||
{
|
||||
name: "1-3 - successful delete with snapshot class that has valid secret parameter",
|
||||
initialContents: newContentArray("content1-3", "sid1-3", "snap1-3", "sid1-3", validSecretClass, "", "", deletionPolicy, nil, nil, true),
|
||||
expectedContents: newContentArray("content1-3", "sid1-3", "snap1-3", "sid1-3", validSecretClass, "", "", deletionPolicy, nil, nil, true),
|
||||
initialSnapshots: nosnapshots,
|
||||
expectedSnapshots: nosnapshots,
|
||||
expectedEvents: noevents,
|
||||
errors: noerrors,
|
||||
initialSecrets: []*v1.Secret{secret()},
|
||||
//expectedDeleteCalls: []deleteCall{{"sid1-3", map[string]string{"foo": "bar"}, nil}},
|
||||
test: testSyncContent,
|
||||
},
|
||||
/*{
|
||||
name: "1-4 - fail delete with snapshot class that has invalid secret parameter",
|
||||
initialContents: newContentArray("content1-4", "sid1-4", "snapuid1-4", "snap1-4", &deletePolicy, nil, nil, true),
|
||||
expectedContents: newContentArray("content1-4", "sid1-4", "snapuid1-4", "snap1-4", &deletePolicy, nil, nil, true),
|
||||
initialSnapshots: nosnapshots,
|
||||
expectedSnapshots: nosnapshots,
|
||||
expectedEvents: noevents,
|
||||
errors: noerrors,
|
||||
test: testSyncContent,
|
||||
},*/
|
||||
/*{
|
||||
name: "1-5 - csi driver delete snapshot returns error",
|
||||
initialContents: newContentArray("content1-5", "sid1-5", "snap1-5", "sid1-5", validSecretClass, "", "", deletionPolicy, nil, nil, true),
|
||||
expectedContents: newContentArray("content1-5", "sid1-5", "snap1-5", "sid1-5", validSecretClass, "", "", deletionPolicy, nil, nil, true),
|
||||
initialSnapshots: nosnapshots,
|
||||
expectedSnapshots: nosnapshots,
|
||||
initialSecrets: []*v1.Secret{secret()},
|
||||
expectedDeleteCalls: []deleteCall{{"sid1-5", map[string]string{"foo": "bar"}, errors.New("mock csi driver delete error")}},
|
||||
expectedEvents: []string{"Warning SnapshotDeleteError"},
|
||||
errors: noerrors,
|
||||
test: testSyncContent,
|
||||
},*/
|
||||
/*{
|
||||
name: "1-6 - api server delete content returns error",
|
||||
initialContents: newContentArray("content1-6", "sid1-6", "snap1-6", "sid1-6", validSecretClass, "", "", deletionPolicy, nil, nil, true),
|
||||
expectedContents: newContentArray("content1-6", "sid1-6", "snap1-6", "sid1-6", validSecretClass, "", "", deletionPolicy, nil, nil, true),
|
||||
initialSnapshots: nosnapshots,
|
||||
expectedSnapshots: nosnapshots,
|
||||
initialSecrets: []*v1.Secret{secret()},
|
||||
//expectedDeleteCalls: []deleteCall{{"sid1-6", map[string]string{"foo": "bar"}, nil}},
|
||||
expectedEvents: []string{"Warning SnapshotContentObjectDeleteError"},
|
||||
errors: []reactorError{
|
||||
// Inject error to the first client.VolumesnapshotV1beta1().VolumeSnapshotContents().Delete call.
|
||||
// All other calls will succeed.
|
||||
{"delete", "volumesnapshotcontents", errors.New("mock delete error")},
|
||||
},
|
||||
test: testSyncContent,
|
||||
},*/
|
||||
{
|
||||
// delete success - snapshot that the content was pointing to was deleted, and another
|
||||
// with the same name created.
|
||||
name: "1-7 - prebound content is deleted while the snapshot exists",
|
||||
initialContents: newContentArray("content1-7", "sid1-7", "snap1-7", "sid1-7", emptySecretClass, "", "", deletionPolicy, nil, nil, true),
|
||||
expectedContents: newContentArray("content1-7", "sid1-7", "snap1-7", "sid1-7", emptySecretClass, "", "", deletionPolicy, nil, nil, true),
|
||||
initialSnapshots: newSnapshotArray("snap1-7", "snapuid1-7-x", "claim1-7", "", validSecretClass, "", &False, nil, nil, nil, false),
|
||||
expectedSnapshots: newSnapshotArray("snap1-7", "snapuid1-7-x", "claim1-7", "", validSecretClass, "", &False, nil, nil, nil, false),
|
||||
initialSecrets: []*v1.Secret{secret()},
|
||||
//expectedDeleteCalls: []deleteCall{{"sid1-7", map[string]string{"foo": "bar"}, nil}},
|
||||
expectedEvents: noevents,
|
||||
errors: noerrors,
|
||||
test: testSyncContent,
|
||||
},
|
||||
{
|
||||
// delete success(?) - content is deleted before doDelete() starts
|
||||
name: "1-8 - content is deleted before deleting",
|
||||
initialContents: newContentArray("content1-8", "sid1-8", "snap1-8", "sid1-8", validSecretClass, "", "", deletionPolicy, nil, nil, true),
|
||||
expectedContents: nocontents,
|
||||
initialSnapshots: nosnapshots,
|
||||
expectedSnapshots: nosnapshots,
|
||||
initialSecrets: []*v1.Secret{secret()},
|
||||
//expectedDeleteCalls: []deleteCall{{"sid1-8", map[string]string{"foo": "bar"}, nil}},
|
||||
expectedEvents: noevents,
|
||||
errors: noerrors,
|
||||
test: wrapTestWithInjectedOperation(testSyncContent, func(ctrl *csiSnapshotCommonController, reactor *snapshotReactor) {
|
||||
// Delete the volume before delete operation starts
|
||||
reactor.lock.Lock()
|
||||
delete(reactor.contents, "content1-8")
|
||||
reactor.lock.Unlock()
|
||||
}),
|
||||
},
|
||||
/*{
|
||||
name: "1-9 - content will not be deleted if it is bound to a snapshot correctly, snapshot uid is specified",
|
||||
initialContents: newContentArray("content1-9", "snapuid1-9", "snap1-9", "sid1-9", validSecretClass, "", "", deletionPolicy, nil, nil, true),
|
||||
expectedContents: newContentArray("content1-9", "snapuid1-9", "snap1-9", "sid1-9", validSecretClass, "", "", deletionPolicy, nil, nil, true),
|
||||
initialSnapshots: newSnapshotArray("snap1-9", "snapuid1-9", "claim1-9", "", validSecretClass, "content1-9", &False, nil, nil, nil),
|
||||
expectedSnapshots: newSnapshotArray("snap1-9", "snapuid1-9", "claim1-9", "", validSecretClass, "content1-9", &True, nil, nil, nil),
|
||||
expectedEvents: noevents,
|
||||
initialSecrets: []*v1.Secret{secret()},
|
||||
errors: noerrors,
|
||||
test: testSyncContent,
|
||||
},*/
|
||||
{
|
||||
name: "1-10 - will not delete content with retain policy set which is bound to a snapshot incorrectly",
|
||||
initialContents: newContentArray("content1-10", "snapuid1-10-x", "snap1-10", "sid1-10", validSecretClass, "", "", retainPolicy, nil, nil, true),
|
||||
expectedContents: newContentArray("content1-10", "snapuid1-10-x", "snap1-10", "sid1-10", validSecretClass, "", "", retainPolicy, nil, nil, true),
|
||||
initialSnapshots: newSnapshotArray("snap1-10", "snapuid1-10", "claim1-10", "", validSecretClass, "content1-10", &False, nil, nil, nil, false),
|
||||
expectedSnapshots: newSnapshotArray("snap1-10", "snapuid1-10", "claim1-10", "", validSecretClass, "content1-10", &False, nil, nil, nil, false),
|
||||
expectedEvents: noevents,
|
||||
initialSecrets: []*v1.Secret{secret()},
|
||||
errors: noerrors,
|
||||
test: testSyncContent,
|
||||
},
|
||||
{
|
||||
name: "1-11 - content will not be deleted if it is bound to a snapshot correctly, snapsht uid is not specified",
|
||||
initialContents: newContentArray("content1-11", "", "snap1-11", "sid1-11", validSecretClass, "", "", deletePolicy, nil, nil, true),
|
||||
expectedContents: newContentArray("content1-11", "", "snap1-11", "sid1-11", validSecretClass, "", "", deletePolicy, nil, nil, true),
|
||||
initialSnapshots: newSnapshotArray("snap1-11", "snapuid1-11", "claim1-11", "", validSecretClass, "content1-11", &False, nil, nil, nil, false),
|
||||
expectedSnapshots: newSnapshotArray("snap1-11", "snapuid1-11", "claim1-11", "", validSecretClass, "content1-11", &False, nil, nil, nil, false),
|
||||
expectedEvents: noevents,
|
||||
initialSecrets: []*v1.Secret{secret()},
|
||||
errors: noerrors,
|
||||
test: testSyncContent,
|
||||
},
|
||||
{
|
||||
name: "1-12 - content with retain policy will not be deleted if it is bound to a non-exist snapshot and also has a snapshot uid specified",
|
||||
initialContents: newContentArray("content1-12", "sid1-12", "snap1-11", "sid1-11", validSecretClass, "", "", retainPolicy, nil, nil, true),
|
||||
expectedContents: newContentArray("content1-12", "sid1-12", "snap1-11", "sid1-11", validSecretClass, "", "", retainPolicy, nil, nil, true),
|
||||
initialSnapshots: nosnapshots,
|
||||
expectedSnapshots: nosnapshots,
|
||||
expectedEvents: noevents,
|
||||
errors: noerrors,
|
||||
test: testSyncContent,
|
||||
},
|
||||
{
|
||||
name: "1-13 - content with empty snapshot class is not deleted when Deletion policy is not set even if it is bound to a non-exist snapshot and also has a snapshot uid specified",
|
||||
initialContents: newContentArray("content1-13", "sid1-13", "snap1-13", "sid1-13", validSecretClass, "", "", retainPolicy, nil, nil, true),
|
||||
expectedContents: newContentArray("content1-13", "sid1-13", "snap1-13", "sid1-13", validSecretClass, "", "", retainPolicy, nil, nil, true),
|
||||
initialSnapshots: nosnapshots,
|
||||
expectedSnapshots: nosnapshots,
|
||||
expectedEvents: noevents,
|
||||
errors: noerrors,
|
||||
test: testSyncContent,
|
||||
},
|
||||
/*{
|
||||
name: "1-14 - content will not be deleted if it is bound to a snapshot correctly, snapshot uid is specified",
|
||||
initialContents: newContentArray("content1-14", "snapuid1-14", "snap1-14", "sid1-14", validSecretClass, "", "", retainPolicy, nil, nil, true),
|
||||
expectedContents: newContentArray("content1-14", "snapuid1-14", "snap1-14", "sid1-14", validSecretClass, "", "", retainPolicy, nil, nil, true),
|
||||
initialSnapshots: newSnapshotArray("snap1-14", "snapuid1-14", "claim1-14", "", validSecretClass, "content1-14", &False, nil, nil, nil),
|
||||
expectedSnapshots: newSnapshotArray("snap1-14", "snapuid1-14", "claim1-14", "", validSecretClass, "content1-14", &True, nil, nil, nil),
|
||||
expectedEvents: noevents,
|
||||
initialSecrets: []*v1.Secret{secret()},
|
||||
errors: noerrors,
|
||||
test: testSyncContent,
|
||||
},*/
|
||||
{
|
||||
name: "1-16 - continue delete with snapshot class that has nonexistent secret",
|
||||
initialContents: newContentArray("content1-16", "sid1-16", "snap1-16", "sid1-16", emptySecretClass, "", "", deletePolicy, nil, nil, true),
|
||||
expectedContents: newContentArray("content1-16", "sid1-16", "snap1-16", "sid1-16", emptySecretClass, "", "", deletePolicy, nil, nil, true),
|
||||
initialSnapshots: nosnapshots,
|
||||
expectedSnapshots: nosnapshots,
|
||||
expectedEvents: noevents,
|
||||
errors: noerrors,
|
||||
initialSecrets: []*v1.Secret{}, // secret does not exist
|
||||
//expectedDeleteCalls: []deleteCall{{"sid1-16", nil, nil}},
|
||||
test: testSyncContent,
|
||||
},
|
||||
}
|
||||
runSyncTests(t, tests, snapshotClasses)
|
||||
}
|
67
pkg/common-controller/snapshot_finalizer_test.go
Normal file
67
pkg/common-controller/snapshot_finalizer_test.go
Normal file
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
Copyright 2019 The Kubernetes Authors.
|
||||
|
||||
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 common_controller
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
v1 "k8s.io/api/core/v1"
|
||||
)
|
||||
|
||||
// Test single call to ensurePVCFinalizer and checkandRemovePVCFinalizer,
|
||||
// expecting PVCFinalizer to be added or removed
|
||||
func TestPVCFinalizer(t *testing.T) {
|
||||
|
||||
tests := []controllerTest{
|
||||
{
|
||||
name: "1-1 - successful add PVC finalizer",
|
||||
initialSnapshots: newSnapshotArray("snap6-2", "snapuid6-2", "claim6-2", "", classSilver, "", &False, nil, nil, nil, false),
|
||||
initialClaims: newClaimArray("claim6-2", "pvc-uid6-2", "1Gi", "volume6-2", v1.ClaimBound, &classEmpty),
|
||||
test: testAddPVCFinalizer,
|
||||
expectSuccess: true,
|
||||
},
|
||||
{
|
||||
name: "1-2 - won't add PVC finalizer; already added",
|
||||
initialSnapshots: newSnapshotArray("snap6-2", "snapuid6-2", "claim6-2", "", classSilver, "", &False, nil, nil, nil, false),
|
||||
initialClaims: newClaimArrayFinalizer("claim6-2", "pvc-uid6-2", "1Gi", "volume6-2", v1.ClaimBound, &classEmpty),
|
||||
test: testAddPVCFinalizer,
|
||||
expectSuccess: false,
|
||||
},
|
||||
{
|
||||
name: "1-3 - successful remove PVC finalizer",
|
||||
initialSnapshots: newSnapshotArray("snap6-2", "snapuid6-2", "claim6-2", "", classSilver, "", &False, nil, nil, nil, false),
|
||||
initialClaims: newClaimArrayFinalizer("claim6-2", "pvc-uid6-2", "1Gi", "volume6-2", v1.ClaimBound, &classEmpty),
|
||||
test: testRemovePVCFinalizer,
|
||||
expectSuccess: true,
|
||||
},
|
||||
{
|
||||
name: "1-4 - won't remove PVC finalizer; already removed",
|
||||
initialSnapshots: newSnapshotArray("snap6-2", "snapuid6-2", "claim6-2", "", classSilver, "", &False, nil, nil, nil, false),
|
||||
initialClaims: newClaimArray("claim6-2", "pvc-uid6-2", "1Gi", "volume6-2", v1.ClaimBound, &classEmpty),
|
||||
test: testRemovePVCFinalizer,
|
||||
expectSuccess: false,
|
||||
},
|
||||
{
|
||||
name: "1-5 - won't remove PVC finalizer; PVC in-use",
|
||||
initialSnapshots: newSnapshotArray("snap6-2", "snapuid6-2", "claim6-2", "", classSilver, "", &False, nil, nil, nil, false),
|
||||
initialClaims: newClaimArray("claim6-2", "pvc-uid6-2", "1Gi", "volume6-2", v1.ClaimBound, &classEmpty),
|
||||
test: testRemovePVCFinalizer,
|
||||
expectSuccess: false,
|
||||
},
|
||||
}
|
||||
runPVCFinalizerTests(t, tests, snapshotClasses)
|
||||
}
|
305
pkg/common-controller/snapshot_update_test.go
Normal file
305
pkg/common-controller/snapshot_update_test.go
Normal file
@@ -0,0 +1,305 @@
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
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 common_controller
|
||||
|
||||
import (
|
||||
//"errors"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
v1 "k8s.io/api/core/v1"
|
||||
storagev1beta1 "k8s.io/api/storage/v1beta1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
var metaTimeNow = &metav1.Time{
|
||||
Time: time.Now(),
|
||||
}
|
||||
|
||||
var volumeErr = &storagev1beta1.VolumeError{
|
||||
Time: *metaTimeNow,
|
||||
Message: "Failed to upload the snapshot",
|
||||
}
|
||||
|
||||
// Test single call to syncSnapshot and syncContent methods.
|
||||
// 1. Fill in the controller with initial data
|
||||
// 2. Call the tested function (syncSnapshot/syncContent) via
|
||||
// controllerTest.testCall *once*.
|
||||
// 3. Compare resulting contents and snapshots with expected contents and snapshots.
|
||||
func TestSync(t *testing.T) {
|
||||
size := int64(1)
|
||||
tests := []controllerTest{
|
||||
{
|
||||
// snapshot is bound to a non-existing content
|
||||
name: "2-1 - snapshot is bound to a non-existing content",
|
||||
initialContents: nocontents,
|
||||
expectedContents: nocontents,
|
||||
initialSnapshots: newSnapshotArray("snap2-1", "snapuid2-1", "claim2-1", "", validSecretClass, "content2-1", &True, nil, nil, nil, false),
|
||||
expectedSnapshots: newSnapshotArray("snap2-1", "snapuid2-1", "claim2-1", "", validSecretClass, "content2-1", &False, nil, nil, newVolumeError("VolumeSnapshotContent is missing"), false),
|
||||
expectedEvents: []string{"Warning SnapshotContentMissing"},
|
||||
errors: noerrors,
|
||||
test: testSyncSnapshot,
|
||||
},
|
||||
/*{
|
||||
name: "2-2 - snapshot points to a content but content does not point to snapshot(VolumeSnapshotRef does not match)",
|
||||
initialContents: newContentArray("content2-2", "snapuid2-2-x", "snap2-2", "sid2-2", validSecretClass, "", "", deletionPolicy, nil, nil, false),
|
||||
expectedContents: newContentArray("content2-2", "snapuid2-2-x", "snap2-2", "sid2-2", validSecretClass, "", "", deletionPolicy, nil, nil, false),
|
||||
initialSnapshots: newSnapshotArray("snap2-2", "snapuid2-2", "claim2-2", "", validSecretClass, "content2-2", &False, nil, nil, nil),
|
||||
expectedSnapshots: newSnapshotArray("snap2-2", "snapuid2-2", "claim2-2", "", validSecretClass, "content2-2", &False, nil, nil, newVolumeError("Snapshot is bound to a VolumeSnapshotContent which is bound to other Snapshot")),
|
||||
expectedEvents: []string{"Warning InvalidSnapshotBinding"},
|
||||
errors: noerrors,
|
||||
test: testSyncSnapshotError,
|
||||
},*/
|
||||
{
|
||||
name: "2-3 - success bind snapshot and content but not ready, no status changed",
|
||||
initialContents: newContentArray("content2-3", "snapuid2-3", "snap2-3", "sid2-3", validSecretClass, "", "", deletionPolicy, nil, nil, false),
|
||||
expectedContents: newContentArrayWithReadyToUse("content2-3", "snapuid2-3", "snap2-3", "sid2-3", validSecretClass, "", "", deletionPolicy, &timeNowStamp, nil, &True, false),
|
||||
initialSnapshots: newSnapshotArray("snap2-3", "snapuid2-3", "claim2-3", "", validSecretClass, "content2-3", &False, metaTimeNow, nil, nil, false),
|
||||
expectedSnapshots: newSnapshotArray("snap2-3", "snapuid2-3", "claim2-3", "", validSecretClass, "content2-3", &True, metaTimeNow, nil, nil, false),
|
||||
initialClaims: newClaimArray("claim2-3", "pvc-uid2-3", "1Gi", "volume2-3", v1.ClaimBound, &classEmpty),
|
||||
initialVolumes: newVolumeArray("volume2-3", "pv-uid2-3", "pv-handle2-3", "1Gi", "pvc-uid2-3", "claim2-3", v1.VolumeBound, v1.PersistentVolumeReclaimDelete, classEmpty),
|
||||
initialSecrets: []*v1.Secret{secret()},
|
||||
/*expectedCreateCalls: []createCall{
|
||||
{
|
||||
snapshotName: "snapshot-snapuid2-3",
|
||||
volume: newVolume("volume2-3", "pv-uid2-3", "pv-handle2-3", "1Gi", "pvc-uid2-3", "claim2-3", v1.VolumeBound, v1.PersistentVolumeReclaimDelete, classEmpty),
|
||||
parameters: class5Parameters,
|
||||
secrets: map[string]string{"foo": "bar"},
|
||||
// information to return
|
||||
driverName: mockDriverName,
|
||||
size: defaultSize,
|
||||
snapshotId: "sid2-3",
|
||||
creationTime: timeNow,
|
||||
readyToUse: False,
|
||||
},
|
||||
},*/
|
||||
errors: noerrors,
|
||||
test: testSyncSnapshot,
|
||||
},
|
||||
{
|
||||
// nothing changed
|
||||
name: "2-4 - noop",
|
||||
initialContents: newContentArray("content2-4", "snapuid2-4", "snap2-4", "sid2-4", validSecretClass, "", "", deletionPolicy, nil, nil, false),
|
||||
expectedContents: newContentArray("content2-4", "snapuid2-4", "snap2-4", "sid2-4", validSecretClass, "", "", deletionPolicy, nil, nil, false),
|
||||
initialSnapshots: newSnapshotArray("snap2-4", "snapuid2-4", "claim2-4", "", validSecretClass, "content2-4", &True, metaTimeNow, nil, nil, false),
|
||||
expectedSnapshots: newSnapshotArray("snap2-4", "snapuid2-4", "claim2-4", "", validSecretClass, "content2-4", &True, metaTimeNow, nil, nil, false),
|
||||
errors: noerrors,
|
||||
test: testSyncSnapshot,
|
||||
},
|
||||
{
|
||||
name: "2-5 - snapshot and content bound, status ready false -> true",
|
||||
initialContents: newContentArrayWithReadyToUse("content2-5", "snapuid2-5", "snap2-5", "sid2-5", validSecretClass, "", "", deletionPolicy, &timeNowStamp, nil, &False, false),
|
||||
expectedContents: newContentArrayWithReadyToUse("content2-5", "snapuid2-5", "snap2-5", "sid2-5", validSecretClass, "", "", deletionPolicy, &timeNowStamp, nil, &False, false),
|
||||
initialSnapshots: newSnapshotArray("snap2-5", "snapuid2-5", "claim2-5", "", validSecretClass, "content2-5", &False, metaTimeNow, nil, nil, false),
|
||||
expectedSnapshots: newSnapshotArray("snap2-5", "snapuid2-5", "claim2-5", "", validSecretClass, "content2-5", &False, metaTimeNow, nil, nil, false),
|
||||
initialClaims: newClaimArray("claim2-5", "pvc-uid2-5", "1Gi", "volume2-5", v1.ClaimBound, &classEmpty),
|
||||
initialVolumes: newVolumeArray("volume2-5", "pv-uid2-5", "pv-handle2-5", "1Gi", "pvc-uid2-5", "claim2-5", v1.VolumeBound, v1.PersistentVolumeReclaimDelete, classEmpty),
|
||||
initialSecrets: []*v1.Secret{secret()},
|
||||
/*expectedCreateCalls: []createCall{
|
||||
{
|
||||
snapshotName: "snapshot-snapuid2-5",
|
||||
volume: newVolume("volume2-5", "pv-uid2-5", "pv-handle2-5", "1Gi", "pvc-uid2-5", "claim2-5", v1.VolumeBound, v1.PersistentVolumeReclaimDelete, classEmpty),
|
||||
parameters: class5Parameters,
|
||||
secrets: map[string]string{"foo": "bar"},
|
||||
// information to return
|
||||
driverName: mockDriverName,
|
||||
size: defaultSize,
|
||||
snapshotId: "sid2-5",
|
||||
creationTime: timeNow,
|
||||
readyToUse: True,
|
||||
},
|
||||
},*/
|
||||
errors: noerrors,
|
||||
test: testSyncSnapshot,
|
||||
},
|
||||
{
|
||||
name: "2-6 - snapshot bound to prebound content correctly, status ready false -> true, ref.UID '' -> 'snapuid2-6'",
|
||||
initialContents: newContentArrayWithReadyToUse("content2-6", "snapuid2-6", "snap2-6", "sid2-6", validSecretClass, "", "", deletionPolicy, &timeNowStamp, nil, &False, false),
|
||||
expectedContents: newContentArrayWithReadyToUse("content2-6", "snapuid2-6", "snap2-6", "sid2-6", validSecretClass, "", "", deletionPolicy, &timeNowStamp, nil, &False, false),
|
||||
initialSnapshots: newSnapshotArray("snap2-6", "snapuid2-6", "", "content2-6", validSecretClass, "content2-6", &False, metaTimeNow, nil, nil, false),
|
||||
expectedSnapshots: newSnapshotArray("snap2-6", "snapuid2-6", "", "content2-6", validSecretClass, "content2-6", &False, metaTimeNow, nil, nil, false),
|
||||
expectedListCalls: []listCall{
|
||||
{
|
||||
size: defaultSize,
|
||||
snapshotID: "sid2-6",
|
||||
readyToUse: true,
|
||||
},
|
||||
},
|
||||
errors: noerrors,
|
||||
test: testSyncSnapshot,
|
||||
},
|
||||
/*{
|
||||
name: "2-7 - snapshot and content bound, csi driver get status error",
|
||||
initialContents: newContentArrayWithReadyToUse("content2-7", "snapuid2-7", "snap2-7", "sid2-7", validSecretClass, "", "", deletionPolicy, &timeNowStamp, nil, &False, false),
|
||||
expectedContents: newContentArrayWithReadyToUse("content2-7", "snapuid2-7", "snap2-7", "sid2-7", validSecretClass, "", "", deletionPolicy, &timeNowStamp, nil, &False, false),
|
||||
initialSnapshots: newSnapshotArray("snap2-7", "snapuid2-7", "claim2-7", "", validSecretClass, "content2-7", &False, metaTimeNow, nil, nil),
|
||||
expectedSnapshots: newSnapshotArray("snap2-7", "snapuid2-7", "claim2-7", "", validSecretClass, "content2-7", &False, metaTimeNow, nil, newVolumeError("Failed to check and update snapshot: mock create snapshot error")),
|
||||
expectedEvents: []string{"Warning SnapshotCheckandUpdateFailed"},
|
||||
initialClaims: newClaimArray("claim2-7", "pvc-uid2-7", "1Gi", "volume2-7", v1.ClaimBound, &classEmpty),
|
||||
initialVolumes: newVolumeArray("volume2-7", "pv-uid2-7", "pv-handle2-7", "1Gi", "pvc-uid2-7", "claim2-7", v1.VolumeBound, v1.PersistentVolumeReclaimDelete, classEmpty),
|
||||
initialSecrets: []*v1.Secret{secret()},
|
||||
expectedCreateCalls: []createCall{
|
||||
{
|
||||
snapshotName: "snapshot-snapuid2-7",
|
||||
volume: newVolume("volume2-7", "pv-uid2-7", "pv-handle2-7", "1Gi", "pvc-uid2-7", "claim2-7", v1.VolumeBound, v1.PersistentVolumeReclaimDelete, classEmpty),
|
||||
parameters: class5Parameters,
|
||||
secrets: map[string]string{"foo": "bar"},
|
||||
// information to return
|
||||
err: errors.New("mock create snapshot error"),
|
||||
},
|
||||
},
|
||||
errors: noerrors,
|
||||
test: testSyncSnapshot,
|
||||
},*/
|
||||
/*{
|
||||
name: "2-8 - snapshot and content bound, apiserver update status error",
|
||||
initialContents: newContentArrayWithReadyToUse("content2-8", "snapuid2-8", "snap2-8", "sid2-8", validSecretClass, "", "", deletionPolicy, &timeNowStamp, nil, &False, false),
|
||||
expectedContents: newContentArrayWithReadyToUse("content2-8", "snapuid2-8", "snap2-8", "sid2-8", validSecretClass, "", "", deletionPolicy, &timeNowStamp, nil, &False, false),
|
||||
initialSnapshots: newSnapshotArray("snap2-8", "snapuid2-8", "claim2-8", "", validSecretClass, "content2-8", &False, metaTimeNow, nil, nil),
|
||||
expectedSnapshots: newSnapshotArray("snap2-8", "snapuid2-8", "claim2-8", "", validSecretClass, "content2-8", &False, metaTimeNow, nil, newVolumeError("Failed to check and update snapshot: snapshot controller failed to update default/snap2-8 on API server: mock update error")),
|
||||
expectedEvents: []string{"Warning SnapshotCheckandUpdateFailed"},
|
||||
initialClaims: newClaimArray("claim2-8", "pvc-uid2-8", "1Gi", "volume2-8", v1.ClaimBound, &classEmpty),
|
||||
initialVolumes: newVolumeArray("volume2-8", "pv-uid2-8", "pv-handle2-8", "1Gi", "pvc-uid2-8", "claim2-8", v1.VolumeBound, v1.PersistentVolumeReclaimDelete, classEmpty),
|
||||
initialSecrets: []*v1.Secret{secret()},
|
||||
/*expectedCreateCalls: []createCall{
|
||||
{
|
||||
snapshotName: "snapshot-snapuid2-8",
|
||||
volume: newVolume("volume2-8", "pv-uid2-8", "pv-handle2-8", "1Gi", "pvc-uid2-8", "claim2-8", v1.VolumeBound, v1.PersistentVolumeReclaimDelete, classEmpty),
|
||||
parameters: class5Parameters,
|
||||
secrets: map[string]string{"foo": "bar"},
|
||||
// information to return
|
||||
driverName: mockDriverName,
|
||||
size: defaultSize,
|
||||
snapshotId: "sid2-8",
|
||||
creationTime: timeNow,
|
||||
readyToUse: true,
|
||||
},
|
||||
},*/ /*
|
||||
errors: []reactorError{
|
||||
// Inject error to the first client.VolumesnapshotV1beta1().VolumeSnapshots().Update call.
|
||||
// All other calls will succeed.
|
||||
{"update", "volumesnapshots", errors.New("mock update error")},
|
||||
},
|
||||
test: testSyncSnapshot,
|
||||
},*/
|
||||
{
|
||||
name: "2-9 - fail on status update as there is not pvc provided",
|
||||
initialContents: newContentArray("content2-9", "snapuid2-9", "snap2-9", "sid2-9", validSecretClass, "", "", deletionPolicy, nil, nil, false),
|
||||
expectedContents: newContentArray("content2-9", "snapuid2-9", "snap2-9", "sid2-9", validSecretClass, "", "", deletionPolicy, nil, nil, false),
|
||||
initialSnapshots: newSnapshotArray("snap2-9", "snapuid2-9", "claim2-9", "", validSecretClass, "", &False, nil, nil, nil, false),
|
||||
expectedSnapshots: newSnapshotArray("snap2-9", "snapuid2-9", "claim2-9", "", validSecretClass, "content2-9", &True, nil, nil, nil, false),
|
||||
//expectedSnapshots: newSnapshotArray("snap2-9", "snapuid2-9", "claim2-9", "", validSecretClass, "content2-9", &False, nil, nil, newVolumeError("Failed to check and update snapshot: failed to get input parameters to create snapshot snap2-9: \"failed to retrieve PVC claim2-9 from the lister: \\\"persistentvolumeclaim \\\\\\\"claim2-9\\\\\\\" not found\\\"\"")),
|
||||
errors: noerrors,
|
||||
test: testSyncSnapshot,
|
||||
},
|
||||
{
|
||||
name: "2-10 - do not bind when snapshot and content not match",
|
||||
initialContents: newContentArray("content2-10", "snapuid2-10-x", "snap2-10", "sid2-10", validSecretClass, "", "", deletionPolicy, nil, nil, false),
|
||||
expectedContents: newContentArray("content2-10", "snapuid2-10-x", "snap2-10", "sid2-10", validSecretClass, "", "", deletionPolicy, nil, nil, false),
|
||||
initialSnapshots: newSnapshotArray("snap2-10", "snapuid2-10", "claim2-10", "", validSecretClass, "", &False, nil, nil, newVolumeError("mock driver error"), false),
|
||||
expectedSnapshots: newSnapshotArray("snap2-10", "snapuid2-10", "claim2-10", "", validSecretClass, "", &False, nil, nil, newVolumeError("mock driver error"), false),
|
||||
errors: noerrors,
|
||||
test: testSyncSnapshot,
|
||||
},
|
||||
{
|
||||
name: "3-1 - ready snapshot lost reference to VolumeSnapshotContent",
|
||||
initialContents: nocontents,
|
||||
expectedContents: nocontents,
|
||||
initialSnapshots: newSnapshotArray("snap3-1", "snapuid3-1", "claim3-1", "", validSecretClass, "content3-1", &True, metaTimeNow, nil, nil, false),
|
||||
expectedSnapshots: newSnapshotArray("snap3-1", "snapuid3-1", "claim3-1", "", validSecretClass, "content3-1", &False, metaTimeNow, nil, newVolumeError("VolumeSnapshotContent is missing"), false),
|
||||
errors: noerrors,
|
||||
expectedEvents: []string{"Warning SnapshotContentMissing"},
|
||||
test: testSyncSnapshot,
|
||||
},
|
||||
{
|
||||
name: "3-2 - ready snapshot bound to none-exist content",
|
||||
initialContents: nocontents,
|
||||
expectedContents: nocontents,
|
||||
initialSnapshots: newSnapshotArray("snap3-2", "snapuid3-2", "claim3-2", "", validSecretClass, "content3-2", &True, metaTimeNow, nil, nil, false),
|
||||
expectedSnapshots: newSnapshotArray("snap3-2", "snapuid3-2", "claim3-2", "", validSecretClass, "content3-2", &False, metaTimeNow, nil, newVolumeError("VolumeSnapshotContent is missing"), false),
|
||||
errors: noerrors,
|
||||
expectedEvents: []string{"Warning SnapshotContentMissing"},
|
||||
test: testSyncSnapshot,
|
||||
},
|
||||
{
|
||||
name: "3-3 - ready snapshot(everything is well, do nothing)",
|
||||
initialContents: newContentArray("content3-3", "snapuid3-3", "snap3-3", "sid3-3", validSecretClass, "", "", deletionPolicy, nil, nil, false),
|
||||
expectedContents: newContentArray("content3-3", "snapuid3-3", "snap3-3", "sid3-3", validSecretClass, "", "", deletionPolicy, nil, nil, false),
|
||||
initialSnapshots: newSnapshotArray("snap3-3", "snapuid3-3", "claim3-3", "", validSecretClass, "content3-3", &True, metaTimeNow, nil, nil, false),
|
||||
expectedSnapshots: newSnapshotArray("snap3-3", "snapuid3-3", "claim3-3", "", validSecretClass, "content3-3", &True, metaTimeNow, nil, nil, false),
|
||||
errors: noerrors,
|
||||
test: testSyncSnapshot,
|
||||
},
|
||||
{
|
||||
name: "3-4 - ready snapshot misbound to VolumeSnapshotContent",
|
||||
initialContents: newContentArray("content3-4", "snapuid3-4-x", "snap3-4", "sid3-4", validSecretClass, "", "", deletionPolicy, nil, nil, false),
|
||||
expectedContents: newContentArray("content3-4", "snapuid3-4-x", "snap3-4", "sid3-4", validSecretClass, "", "", deletionPolicy, nil, nil, false),
|
||||
initialSnapshots: newSnapshotArray("snap3-4", "snapuid3-4", "claim3-4", "", validSecretClass, "content3-4", &True, metaTimeNow, nil, nil, false),
|
||||
expectedSnapshots: newSnapshotArray("snap3-4", "snapuid3-4", "claim3-4", "", validSecretClass, "content3-4", &False, metaTimeNow, nil, newVolumeError("VolumeSnapshotContent is not bound to the VolumeSnapshot correctly"), false),
|
||||
errors: noerrors,
|
||||
test: testSyncSnapshot,
|
||||
},
|
||||
/*{
|
||||
name: "3-5 - snapshot bound to content in which the driver does not match",
|
||||
initialContents: newContentWithUnmatchDriverArray("content3-5", "snapuid3-5", "snap3-5", "sid3-5", validSecretClass, "", "", deletionPolicy, nil, nil, false),
|
||||
expectedContents: nocontents,
|
||||
initialSnapshots: newSnapshotArray("snap3-5", "snapuid3-5", "claim3-5", "", validSecretClass, "content3-5", &False, metaTimeNow, nil, nil),
|
||||
expectedSnapshots: newSnapshotArray("snap3-5", "snapuid3-5", "claim3-5", "", validSecretClass, "content3-5", &False, metaTimeNow, nil, newVolumeError("VolumeSnapshotContent is missing")),
|
||||
expectedEvents: []string{"Warning SnapshotContentMissing"},
|
||||
errors: noerrors,
|
||||
test: testSyncSnapshotError,
|
||||
},*/
|
||||
{
|
||||
name: "4-1 - content bound to snapshot, snapshot status missing and rebuilt",
|
||||
initialContents: newContentArrayWithReadyToUse("content2-5", "snapuid2-5", "snap2-5", "sid2-5", validSecretClass, "", "", deletionPolicy, nil, &size, &True, false),
|
||||
expectedContents: newContentArrayWithReadyToUse("content2-5", "snapuid2-5", "snap2-5", "sid2-5", validSecretClass, "", "", deletionPolicy, nil, &size, &True, false),
|
||||
initialSnapshots: newSnapshotArray("snap2-5", "snapuid2-5", "claim2-5", "", validSecretClass, "", &False, nil, nil, nil, true),
|
||||
expectedSnapshots: newSnapshotArray("snap2-5", "snapuid2-5", "claim2-5", "", validSecretClass, "content2-5", &True, nil, getSize(1), nil, false),
|
||||
initialClaims: newClaimArray("claim2-5", "pvc-uid2-5", "1Gi", "volume2-5", v1.ClaimBound, &classEmpty),
|
||||
initialVolumes: newVolumeArray("volume2-5", "pv-uid2-5", "pv-handle2-5", "1Gi", "pvc-uid2-5", "claim2-5", v1.VolumeBound, v1.PersistentVolumeReclaimDelete, classEmpty),
|
||||
initialSecrets: []*v1.Secret{secret()},
|
||||
errors: noerrors,
|
||||
test: testSyncSnapshot,
|
||||
},
|
||||
{
|
||||
name: "4-2 - snapshot and content bound, ReadyToUse in snapshot status missing and rebuilt",
|
||||
initialContents: newContentArrayWithReadyToUse("content2-5", "snapuid2-5", "snap2-5", "sid2-5", validSecretClass, "", "", deletionPolicy, nil, nil, &True, false),
|
||||
expectedContents: newContentArrayWithReadyToUse("content2-5", "snapuid2-5", "snap2-5", "sid2-5", validSecretClass, "", "", deletionPolicy, nil, nil, &True, false),
|
||||
initialSnapshots: newSnapshotArray("snap2-5", "snapuid2-5", "claim2-5", "", validSecretClass, "content2-5", &False, nil, nil, nil, false),
|
||||
expectedSnapshots: newSnapshotArray("snap2-5", "snapuid2-5", "claim2-5", "", validSecretClass, "content2-5", &True, nil, nil, nil, false),
|
||||
initialClaims: newClaimArray("claim2-5", "pvc-uid2-5", "1Gi", "volume2-5", v1.ClaimBound, &classEmpty),
|
||||
initialVolumes: newVolumeArray("volume2-5", "pv-uid2-5", "pv-handle2-5", "1Gi", "pvc-uid2-5", "claim2-5", v1.VolumeBound, v1.PersistentVolumeReclaimDelete, classEmpty),
|
||||
initialSecrets: []*v1.Secret{secret()},
|
||||
errors: noerrors,
|
||||
test: testSyncSnapshot,
|
||||
},
|
||||
{
|
||||
name: "4-3 - content bound to snapshot, fields in snapshot status missing and rebuilt",
|
||||
initialContents: newContentArrayWithReadyToUse("content2-5", "snapuid2-5", "snap2-5", "sid2-5", validSecretClass, "", "", deletionPolicy, nil, &size, &True, false),
|
||||
expectedContents: newContentArrayWithReadyToUse("content2-5", "snapuid2-5", "snap2-5", "sid2-5", validSecretClass, "", "", deletionPolicy, nil, &size, &True, false),
|
||||
initialSnapshots: newSnapshotArray("snap2-5", "snapuid2-5", "claim2-5", "", validSecretClass, "", &False, nil, nil, nil, false),
|
||||
expectedSnapshots: newSnapshotArray("snap2-5", "snapuid2-5", "claim2-5", "", validSecretClass, "content2-5", &True, nil, getSize(1), nil, false),
|
||||
initialClaims: newClaimArray("claim2-5", "pvc-uid2-5", "1Gi", "volume2-5", v1.ClaimBound, &classEmpty),
|
||||
initialVolumes: newVolumeArray("volume2-5", "pv-uid2-5", "pv-handle2-5", "1Gi", "pvc-uid2-5", "claim2-5", v1.VolumeBound, v1.PersistentVolumeReclaimDelete, classEmpty),
|
||||
initialSecrets: []*v1.Secret{secret()},
|
||||
errors: noerrors,
|
||||
test: testSyncSnapshot,
|
||||
},
|
||||
}
|
||||
|
||||
runSyncTests(t, tests, snapshotClasses)
|
||||
}
|
Reference in New Issue
Block a user