From d125c02a56a8ac43024eac814d6f9f5398ce5603 Mon Sep 17 00:00:00 2001 From: Saikat Roychowdhury Date: Wed, 24 Jun 2020 22:27:13 +0000 Subject: [PATCH] Make Pod informer registration optional --- cmd/csi-resizer/main.go | 7 +++- pkg/controller/controller.go | 58 ++++++++++++++++------------ pkg/controller/controller_test.go | 64 ++++++++++++++++++++++++++++++- 3 files changed, 100 insertions(+), 29 deletions(-) diff --git a/cmd/csi-resizer/main.go b/cmd/csi-resizer/main.go index 76ad9ff0..a655a11c 100644 --- a/cmd/csi-resizer/main.go +++ b/cmd/csi-resizer/main.go @@ -20,10 +20,11 @@ import ( "context" "flag" "fmt" - "k8s.io/client-go/util/workqueue" "os" "time" + "k8s.io/client-go/util/workqueue" + "github.com/kubernetes-csi/csi-lib-utils/leaderelection" "github.com/kubernetes-csi/external-resizer/pkg/controller" "github.com/kubernetes-csi/external-resizer/pkg/resizer" @@ -53,6 +54,8 @@ var ( metricsAddress = flag.String("metrics-address", "", "The TCP network address where the prometheus metrics endpoint will listen (example: `:8080`). The default is empty string, which means metrics endpoint is disabled.") metricsPath = flag.String("metrics-path", "/metrics", "The HTTP path where prometheus metrics will be exposed. Default is `/metrics`.") + handleVolumeInUseError = flag.Bool("handle-volume-inuse-error", true, "Flag to turn on/off capability to handle volume in use error in resizer controller. Defaults to true if not set.") + version = "unknown" ) @@ -88,7 +91,7 @@ func main() { resizerName := csiResizer.Name() rc := controller.NewResizeController(resizerName, csiResizer, kubeClient, *resyncPeriod, informerFactory, workqueue.NewItemExponentialFailureRateLimiter(*retryIntervalStart, *retryIntervalMax), - ) + *handleVolumeInUseError) run := func(ctx context.Context) { informerFactory.Start(wait.NeverStop) rc.Run(*workers, ctx) diff --git a/pkg/controller/controller.go b/pkg/controller/controller.go index 2d155df7..bd715be0 100644 --- a/pkg/controller/controller.go +++ b/pkg/controller/controller.go @@ -62,8 +62,9 @@ type resizeController struct { usedPVCs *inUsePVCStore - podLister corelisters.PodLister - podListerSynced cache.InformerSynced + podLister corelisters.PodLister + podListerSynced cache.InformerSynced + handleVolumeInUseError bool } // NewResizeController returns a ResizeController. @@ -73,13 +74,10 @@ func NewResizeController( kubeClient kubernetes.Interface, resyncPeriod time.Duration, informerFactory informers.SharedInformerFactory, - pvcRateLimiter workqueue.RateLimiter) ResizeController { + pvcRateLimiter workqueue.RateLimiter, + handleVolumeInUseError bool) ResizeController { pvInformer := informerFactory.Core().V1().PersistentVolumes() pvcInformer := informerFactory.Core().V1().PersistentVolumeClaims() - - // list pods so as we can identify PVC that are in-use - podInformer := informerFactory.Core().V1().Pods() - eventBroadcaster := record.NewBroadcaster() eventBroadcaster.StartLogging(klog.Infof) eventBroadcaster.StartRecordingToSink(&corev1.EventSinkImpl{Interface: kubeClient.CoreV1().Events(v1.NamespaceAll)}) @@ -90,18 +88,17 @@ func NewResizeController( pvcRateLimiter, fmt.Sprintf("%s-pvc", name)) ctrl := &resizeController{ - name: name, - resizer: resizer, - kubeClient: kubeClient, - pvLister: pvInformer.Lister(), - pvSynced: pvInformer.Informer().HasSynced, - pvcLister: pvcInformer.Lister(), - pvcSynced: pvcInformer.Informer().HasSynced, - podLister: podInformer.Lister(), - podListerSynced: podInformer.Informer().HasSynced, - claimQueue: claimQueue, - eventRecorder: eventRecorder, - usedPVCs: newUsedPVCStore(), + name: name, + resizer: resizer, + kubeClient: kubeClient, + pvLister: pvInformer.Lister(), + pvSynced: pvInformer.Informer().HasSynced, + pvcLister: pvcInformer.Lister(), + pvcSynced: pvcInformer.Informer().HasSynced, + claimQueue: claimQueue, + eventRecorder: eventRecorder, + usedPVCs: newUsedPVCStore(), + handleVolumeInUseError: handleVolumeInUseError, } // Add a resync period as the PVC's request size can be resized again when we handling @@ -112,11 +109,18 @@ func NewResizeController( DeleteFunc: ctrl.deletePVC, }, resyncPeriod) - podInformer.Informer().AddEventHandlerWithResyncPeriod(cache.ResourceEventHandlerFuncs{ - AddFunc: ctrl.addPod, - DeleteFunc: ctrl.deletePod, - UpdateFunc: ctrl.updatePod, - }, resyncPeriod) + if handleVolumeInUseError { + // list pods so as we can identify PVC that are in-use + klog.Infof("Register Pod informer for resizer %s", ctrl.name) + podInformer := informerFactory.Core().V1().Pods() + ctrl.podLister = podInformer.Lister() + ctrl.podListerSynced = podInformer.Informer().HasSynced + podInformer.Informer().AddEventHandlerWithResyncPeriod(cache.ResourceEventHandlerFuncs{ + AddFunc: ctrl.addPod, + DeleteFunc: ctrl.deletePod, + UpdateFunc: ctrl.updatePod, + }, resyncPeriod) + } return ctrl } @@ -235,8 +239,12 @@ func (ctrl *resizeController) Run( defer klog.Infof("Shutting down external resizer %s", ctrl.name) stopCh := ctx.Done() + informersSyncd := []cache.InformerSynced{ctrl.pvSynced, ctrl.pvcSynced} + if ctrl.handleVolumeInUseError { + informersSyncd = append(informersSyncd, ctrl.podListerSynced) + } - if !cache.WaitForCacheSync(stopCh, ctrl.pvSynced, ctrl.pvcSynced, ctrl.podListerSynced) { + if !cache.WaitForCacheSync(stopCh, informersSyncd...) { klog.Errorf("Cannot sync pod, pv or pvc caches") return } diff --git a/pkg/controller/controller_test.go b/pkg/controller/controller_test.go index 7bd57f49..fc67846c 100644 --- a/pkg/controller/controller_test.go +++ b/pkg/controller/controller_test.go @@ -24,6 +24,7 @@ import ( func TestController(t *testing.T) { blockVolumeMode := v1.PersistentVolumeBlock fsVolumeMode := v1.PersistentVolumeFilesystem + for _, test := range []struct { Name string PVC *v1.PersistentVolumeClaim @@ -37,7 +38,8 @@ func TestController(t *testing.T) { // is PVC being expanded in-use pvcInUse bool // does PVC being expanded has Failed Precondition errors - pvcHasInUseErrors bool + pvcHasInUseErrors bool + disableVolumeInUseErrorHandler bool }{ { Name: "Invalid key", @@ -130,6 +132,64 @@ func TestController(t *testing.T) { pvcHasInUseErrors: true, pvcInUse: false, }, + // test cases with volume in use error handling disabled. + { + Name: "With volume-in-use error handler disabled, Resize PVC, no FS resize, pvc-inuse with failedprecondition", + PVC: createPVC(2, 1), + PV: createPV(1, "testPVC", defaultNS, "foobar", &fsVolumeMode), + CreateObjects: true, + CallCSIExpand: true, + pvcHasInUseErrors: true, + pvcInUse: true, + disableVolumeInUseErrorHandler: true, + }, + { + Name: "With volume-in-use error handler disabled, Resize PVC, no FS resize, pvc-inuse but no failedprecondition error", + PVC: createPVC(2, 1), + PV: createPV(1, "testPVC", defaultNS, "foobar", &fsVolumeMode), + CreateObjects: true, + CallCSIExpand: true, + pvcHasInUseErrors: false, + pvcInUse: true, + disableVolumeInUseErrorHandler: true, + }, + { + Name: "With volume-in-use error handler disabled, Resize PVC, no FS resize, pvc not in-use but has failedprecondition error", + PVC: createPVC(2, 1), + PV: createPV(1, "testPVC", defaultNS, "foobar", &fsVolumeMode), + CreateObjects: true, + CallCSIExpand: true, + pvcHasInUseErrors: true, + pvcInUse: false, + disableVolumeInUseErrorHandler: true, + }, + { + Name: "With volume-in-use error handler disabled, Block Resize PVC with FS resize", + PVC: createPVC(2, 1), + PV: createPV(1, "testPVC", defaultNS, "foobar", &blockVolumeMode), + CreateObjects: true, + NodeResize: true, + CallCSIExpand: true, + expectBlockVolume: true, + disableVolumeInUseErrorHandler: true, + }, + { + Name: "With volume-in-use error handler disabled, Resize PVC with FS resize", + PVC: createPVC(2, 1), + PV: createPV(1, "testPVC", defaultNS, "foobar", &fsVolumeMode), + CreateObjects: true, + NodeResize: true, + CallCSIExpand: true, + disableVolumeInUseErrorHandler: true, + }, + { + Name: "With volume-in-use error handler disabled, Resize PVC, no FS resize", + PVC: createPVC(2, 1), + PV: createPV(1, "testPVC", defaultNS, "foobar", &fsVolumeMode), + CreateObjects: true, + CallCSIExpand: true, + disableVolumeInUseErrorHandler: true, + }, } { client := csi.NewMockClient("mock", test.NodeResize, true, true) driverName, _ := client.GetDriverName(context.TODO()) @@ -163,7 +223,7 @@ func TestController(t *testing.T) { t.Fatalf("Test %s: Unable to create resizer: %v", test.Name, err) } - controller := NewResizeController(driverName, csiResizer, kubeClient, time.Second, informerFactory, workqueue.DefaultControllerRateLimiter()) + controller := NewResizeController(driverName, csiResizer, kubeClient, time.Second, informerFactory, workqueue.DefaultControllerRateLimiter(), !test.disableVolumeInUseErrorHandler) ctrlInstance, _ := controller.(*resizeController)