Skip to content

Commit da7dd5d

Browse files
committed
⚠️ Allow configuring RecoverPanic for controllers globally
This change allows configuring the RecoverPanic setting for controllers globally. It is a breaking change as it requires changing the field type of the setting to *bool from bool in order to be able to check if it has been set already.
1 parent 222fb66 commit da7dd5d

File tree

5 files changed

+50
-4
lines changed

5 files changed

+50
-4
lines changed

pkg/config/v1alpha1/types.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,10 @@ type ControllerConfigurationSpec struct {
9494
// Defaults to 2 minutes if not set.
9595
// +optional
9696
CacheSyncTimeout *time.Duration `json:"cacheSyncTimeout,omitempty"`
97+
98+
// RecoverPanic indicates if panics should be recovered.
99+
// +optional
100+
RecoverPanic *bool `json:"recoverPanic,omitempty"`
97101
}
98102

99103
// ControllerMetrics defines the metrics configs.

pkg/controller/controller.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,8 @@ type Options struct {
5656
CacheSyncTimeout time.Duration
5757

5858
// RecoverPanic indicates whether the panic caused by reconcile should be recovered.
59-
RecoverPanic bool
59+
// Defaults to the Controller.RecoverPanic setting from the Manager if unset.
60+
RecoverPanic *bool
6061
}
6162

6263
// Controller implements a Kubernetes API. A Controller manages a work queue fed reconcile.Requests
@@ -139,6 +140,10 @@ func NewUnmanaged(name string, mgr manager.Manager, options Options) (Controller
139140
return nil, err
140141
}
141142

143+
if options.RecoverPanic == nil {
144+
options.RecoverPanic = mgr.GetControllerOptions().RecoverPanic
145+
}
146+
142147
// Create controller with dependencies set
143148
return &controller.Controller{
144149
Do: options.Reconciler,

pkg/controller/controller_test.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,14 @@ import (
2525
. "github.com/onsi/gomega"
2626
"go.uber.org/goleak"
2727
corev1 "k8s.io/api/core/v1"
28+
"k8s.io/utils/pointer"
2829

2930
"sigs.k8s.io/controller-runtime/pkg/client"
31+
"sigs.k8s.io/controller-runtime/pkg/config/v1alpha1"
3032
"sigs.k8s.io/controller-runtime/pkg/controller"
3133
"sigs.k8s.io/controller-runtime/pkg/event"
3234
"sigs.k8s.io/controller-runtime/pkg/handler"
35+
internalcontroller "sigs.k8s.io/controller-runtime/pkg/internal/controller"
3336
"sigs.k8s.io/controller-runtime/pkg/manager"
3437
"sigs.k8s.io/controller-runtime/pkg/reconcile"
3538
"sigs.k8s.io/controller-runtime/pkg/runtime/inject"
@@ -142,6 +145,39 @@ var _ = Describe("controller.Controller", func() {
142145
clientTransport.CloseIdleConnections()
143146
Eventually(func() error { return goleak.Find(currentGRs) }).Should(Succeed())
144147
})
148+
149+
It("should default RecoverPanic from the manager", func() {
150+
m, err := manager.New(cfg, manager.Options{Controller: v1alpha1.ControllerConfigurationSpec{RecoverPanic: pointer.Bool(true)}})
151+
Expect(err).NotTo(HaveOccurred())
152+
153+
c, err := controller.New("new-controller", m, controller.Options{
154+
Reconciler: reconcile.Func(nil),
155+
})
156+
Expect(err).NotTo(HaveOccurred())
157+
158+
ctrl, ok := c.(*internalcontroller.Controller)
159+
Expect(ok).To(BeTrue())
160+
161+
Expect(ctrl.RecoverPanic).NotTo(BeNil())
162+
Expect(*ctrl.RecoverPanic).To(BeTrue())
163+
})
164+
165+
It("should not override RecoverPanic on the controller", func() {
166+
m, err := manager.New(cfg, manager.Options{Controller: v1alpha1.ControllerConfigurationSpec{RecoverPanic: pointer.Bool(true)}})
167+
Expect(err).NotTo(HaveOccurred())
168+
169+
c, err := controller.New("new-controller", m, controller.Options{
170+
Reconciler: reconcile.Func(nil),
171+
RecoverPanic: pointer.Bool(false),
172+
})
173+
Expect(err).NotTo(HaveOccurred())
174+
175+
ctrl, ok := c.(*internalcontroller.Controller)
176+
Expect(ok).To(BeTrue())
177+
178+
Expect(ctrl.RecoverPanic).NotTo(BeNil())
179+
Expect(*ctrl.RecoverPanic).To(BeFalse())
180+
})
145181
})
146182
})
147183

pkg/internal/controller/controller.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ type Controller struct {
9292
LogConstructor func(request *reconcile.Request) logr.Logger
9393

9494
// RecoverPanic indicates whether the panic caused by reconcile should be recovered.
95-
RecoverPanic bool
95+
RecoverPanic *bool
9696
}
9797

9898
// watchDescription contains all the information necessary to start a watch.
@@ -106,7 +106,7 @@ type watchDescription struct {
106106
func (c *Controller) Reconcile(ctx context.Context, req reconcile.Request) (_ reconcile.Result, err error) {
107107
defer func() {
108108
if r := recover(); r != nil {
109-
if c.RecoverPanic {
109+
if c.RecoverPanic != nil && *c.RecoverPanic {
110110
for _, fn := range utilruntime.PanicHandlers {
111111
fn(r)
112112
}

pkg/internal/controller/controller_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import (
3333
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
3434
"k8s.io/apimachinery/pkg/types"
3535
"k8s.io/client-go/util/workqueue"
36+
"k8s.io/utils/pointer"
3637
"sigs.k8s.io/controller-runtime/pkg/cache"
3738
"sigs.k8s.io/controller-runtime/pkg/cache/informertest"
3839
"sigs.k8s.io/controller-runtime/pkg/client"
@@ -114,7 +115,7 @@ var _ = Describe("controller", func() {
114115
defer func() {
115116
Expect(recover()).To(BeNil())
116117
}()
117-
ctrl.RecoverPanic = true
118+
ctrl.RecoverPanic = pointer.Bool(true)
118119
ctrl.Do = reconcile.Func(func(context.Context, reconcile.Request) (reconcile.Result, error) {
119120
var res *reconcile.Result
120121
return *res, nil

0 commit comments

Comments
 (0)