Skip to content

Commit 4994e9e

Browse files
vincepriRainbowMango
authored andcommitted
⚠️ Support global controller options in component config
This change adds support for our v1alpha1 ComponentConfig types to expose configuration options for controllers. The only two current exposed options are concurrency (done via a GroupKind map) and the cache sync timeout option. This is a breaking change, given that we're adding a new required method to the Manager's interface. Signed-off-by: Vince Prignano <[email protected]>
1 parent 76bae12 commit 4994e9e

File tree

6 files changed

+136
-1
lines changed

6 files changed

+136
-1
lines changed

pkg/builder/controller.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,8 @@ func (blder *Builder) getControllerName(gvk schema.GroupVersionKind) string {
287287
}
288288

289289
func (blder *Builder) doController(r reconcile.Reconciler) error {
290+
globalOpts := blder.mgr.GetControllerOptions()
291+
290292
ctrlOptions := blder.ctrlOptions
291293
if ctrlOptions.Reconciler == nil {
292294
ctrlOptions.Reconciler = r
@@ -299,6 +301,20 @@ func (blder *Builder) doController(r reconcile.Reconciler) error {
299301
return err
300302
}
301303

304+
// Setup concurrency.
305+
if ctrlOptions.MaxConcurrentReconciles == 0 {
306+
groupKind := gvk.GroupKind().String()
307+
308+
if concurrency, ok := globalOpts.GroupKindConcurrency[groupKind]; ok && concurrency > 0 {
309+
ctrlOptions.MaxConcurrentReconciles = concurrency
310+
}
311+
}
312+
313+
// Setup cache sync timeout.
314+
if ctrlOptions.CacheSyncTimeout == 0 && globalOpts.CacheSyncTimeout != nil {
315+
ctrlOptions.CacheSyncTimeout = *globalOpts.CacheSyncTimeout
316+
}
317+
302318
// Setup the logger.
303319
if ctrlOptions.Log == nil {
304320
ctrlOptions.Log = blder.mgr.GetLogger()

pkg/builder/controller_test.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import (
3636

3737
"sigs.k8s.io/controller-runtime/pkg/cache"
3838
"sigs.k8s.io/controller-runtime/pkg/client"
39+
"sigs.k8s.io/controller-runtime/pkg/config/v1alpha1"
3940
"sigs.k8s.io/controller-runtime/pkg/controller"
4041
"sigs.k8s.io/controller-runtime/pkg/event"
4142
"sigs.k8s.io/controller-runtime/pkg/handler"
@@ -172,6 +173,34 @@ var _ = Describe("application", func() {
172173
Expect(instance).NotTo(BeNil())
173174
})
174175

176+
It("should override max concurrent reconcilers during creation of controller, when using", func() {
177+
const maxConcurrentReconciles = 10
178+
newController = func(name string, mgr manager.Manager, options controller.Options) (
179+
controller.Controller, error) {
180+
if options.MaxConcurrentReconciles == maxConcurrentReconciles {
181+
return controller.New(name, mgr, options)
182+
}
183+
return nil, fmt.Errorf("max concurrent reconcilers expected %d but found %d", maxConcurrentReconciles, options.MaxConcurrentReconciles)
184+
}
185+
186+
By("creating a controller manager")
187+
m, err := manager.New(cfg, manager.Options{
188+
Controller: v1alpha1.ControllerConfigurationSpec{
189+
GroupKindConcurrency: map[string]int{
190+
"ReplicaSet.apps": maxConcurrentReconciles,
191+
},
192+
},
193+
})
194+
Expect(err).NotTo(HaveOccurred())
195+
196+
instance, err := ControllerManagedBy(m).
197+
For(&appsv1.ReplicaSet{}).
198+
Owns(&appsv1.ReplicaSet{}).
199+
Build(noop)
200+
Expect(err).NotTo(HaveOccurred())
201+
Expect(instance).NotTo(BeNil())
202+
})
203+
175204
It("should override rate limiter during creation of controller", func() {
176205
rateLimiter := workqueue.DefaultItemBasedRateLimiter()
177206
newController = func(name string, mgr manager.Manager, options controller.Options) (controller.Controller, error) {

pkg/config/v1alpha1/types.go

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ limitations under the License.
1717
package v1alpha1
1818

1919
import (
20+
"time"
21+
2022
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2123

2224
configv1alpha1 "k8s.io/component-base/config/v1alpha1"
@@ -50,9 +52,14 @@ type ControllerManagerConfigurationSpec struct {
5052
// GracefulShutdownTimeout is the duration given to runnable to stop before the manager actually returns on stop.
5153
// To disable graceful shutdown, set to time.Duration(0)
5254
// To use graceful shutdown without timeout, set to a negative duration, e.G. time.Duration(-1)
53-
// The graceful shutdown is skipped for safety reasons in case the leadere election lease is lost.
55+
// The graceful shutdown is skipped for safety reasons in case the leader election lease is lost.
5456
GracefulShutdownTimeout *metav1.Duration `json:"gracefulShutDown,omitempty"`
5557

58+
// Controller contains global configuration options for controllers
59+
// registered within this manager.
60+
// +optional
61+
Controller *ControllerConfigurationSpec `json:"controller,omitempty"`
62+
5663
// Metrics contains thw controller metrics configuration
5764
// +optional
5865
Metrics ControllerMetrics `json:"metrics,omitempty"`
@@ -66,6 +73,29 @@ type ControllerManagerConfigurationSpec struct {
6673
Webhook ControllerWebhook `json:"webhook,omitempty"`
6774
}
6875

76+
// ControllerConfigurationSpec defines the global configuration for
77+
// controllers registered with the manager.
78+
type ControllerConfigurationSpec struct {
79+
// GroupKindConcurrency is a map from a Kind to the number of concurrent reconciliation
80+
// allowed for that controller.
81+
//
82+
// When a controller is registered within this manager using the builder utilities,
83+
// users have to specify the type the controller reconciles in the For(...) call.
84+
// If the object's kind passed matches one of the keys in this map, the concurrency
85+
// for that controller is set to the number specified.
86+
//
87+
// The key is expected to be consistent in form with GroupKind.String(),
88+
// e.g. ReplicaSet in apps group (regardless of version) would be `ReplicaSet.apps`.
89+
//
90+
// +optional
91+
GroupKindConcurrency map[string]int `json:"groupKindConcurrency,omitempty"`
92+
93+
// CacheSyncTimeout refers to the time limit set to wait for syncing caches.
94+
// Defaults to 2 minutes if not set.
95+
// +optional
96+
CacheSyncTimeout *time.Duration `json:"cacheSyncTimeout,omitempty"`
97+
}
98+
6999
// ControllerMetrics defines the metrics configs
70100
type ControllerMetrics struct {
71101
// BindAddress is the TCP address that the controller should bind to

pkg/config/v1alpha1/zz_generated.deepcopy.go

Lines changed: 33 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/manager/internal.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ import (
3838
"sigs.k8s.io/controller-runtime/pkg/cache"
3939
"sigs.k8s.io/controller-runtime/pkg/client"
4040
"sigs.k8s.io/controller-runtime/pkg/cluster"
41+
"sigs.k8s.io/controller-runtime/pkg/config/v1alpha1"
4142
"sigs.k8s.io/controller-runtime/pkg/healthz"
4243
intrec "sigs.k8s.io/controller-runtime/pkg/internal/recorder"
4344
"sigs.k8s.io/controller-runtime/pkg/metrics"
@@ -108,6 +109,9 @@ type controllerManager struct {
108109
healthzStarted bool
109110
errChan chan error
110111

112+
// controllerOptions are the global controller options.
113+
controllerOptions v1alpha1.ControllerConfigurationSpec
114+
111115
// Logger is the logger that should be used by this manager.
112116
// If none is set, it defaults to log.Log global logger.
113117
logger logr.Logger
@@ -355,6 +359,10 @@ func (cm *controllerManager) GetLogger() logr.Logger {
355359
return cm.logger
356360
}
357361

362+
func (cm *controllerManager) GetControllerOptions() v1alpha1.ControllerConfigurationSpec {
363+
return cm.controllerOptions
364+
}
365+
358366
func (cm *controllerManager) serveMetrics() {
359367
handler := promhttp.HandlerFor(metrics.Registry, promhttp.HandlerOpts{
360368
ErrorHandling: promhttp.HTTPErrorOnError,

pkg/manager/manager.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,9 @@ type Manager interface {
9090

9191
// GetLogger returns this manager's logger.
9292
GetLogger() logr.Logger
93+
94+
// GetControllerOptions returns controller global configuration options.
95+
GetControllerOptions() v1alpha1.ControllerConfigurationSpec
9396
}
9497

9598
// Options are the arguments for creating a new Manager
@@ -230,6 +233,11 @@ type Options struct {
230233
// The graceful shutdown is skipped for safety reasons in case the leader election lease is lost.
231234
GracefulShutdownTimeout *time.Duration
232235

236+
// Controller contains global configuration options for controllers
237+
// registered within this manager.
238+
// +optional
239+
Controller v1alpha1.ControllerConfigurationSpec
240+
233241
// makeBroadcaster allows deferring the creation of the broadcaster to
234242
// avoid leaking goroutines if we never call Start on this manager. It also
235243
// returns whether or not this is a "owned" broadcaster, and as such should be
@@ -337,6 +345,7 @@ func New(config *rest.Config, options Options) (Manager, error) {
337345
resourceLock: resourceLock,
338346
metricsListener: metricsListener,
339347
metricsExtraHandlers: metricsExtraHandlers,
348+
controllerOptions: options.Controller,
340349
logger: options.Logger,
341350
elected: make(chan struct{}),
342351
port: options.Port,
@@ -407,6 +416,16 @@ func (o Options) AndFrom(loader config.ControllerManagerConfiguration) (Options,
407416
o.CertDir = newObj.Webhook.CertDir
408417
}
409418

419+
if newObj.Controller != nil {
420+
if o.Controller.CacheSyncTimeout == nil && newObj.Controller.CacheSyncTimeout != nil {
421+
o.Controller.CacheSyncTimeout = newObj.Controller.CacheSyncTimeout
422+
}
423+
424+
if len(o.Controller.GroupKindConcurrency) == 0 && len(newObj.Controller.GroupKindConcurrency) > 0 {
425+
o.Controller.GroupKindConcurrency = newObj.Controller.GroupKindConcurrency
426+
}
427+
}
428+
410429
return o, nil
411430
}
412431

0 commit comments

Comments
 (0)