Skip to content

Commit b2a1572

Browse files
added leader election for runnables
1 parent 47744b5 commit b2a1572

File tree

11 files changed

+367
-131
lines changed

11 files changed

+367
-131
lines changed

pkg/builder/controller_test.go

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,11 @@ var _ = Describe("application", func() {
6161
instance, err := ControllerManagedBy(m).
6262
For(&appsv1.ReplicaSet{}).
6363
Owns(&appsv1.ReplicaSet{}).
64+
WithOptions(controller.Options{
65+
LeaderElection: &controller.LeaderElectionOptions{
66+
NeedLeaderElection: false,
67+
},
68+
}).
6469
Build(noop)
6570
Expect(err).NotTo(HaveOccurred())
6671
Expect(instance).NotTo(BeNil())
@@ -75,6 +80,11 @@ var _ = Describe("application", func() {
7580
instance, err := ControllerManagedBy(m).
7681
For(&fakeType{}).
7782
Owns(&appsv1.ReplicaSet{}).
83+
WithOptions(controller.Options{
84+
LeaderElection: &controller.LeaderElectionOptions{
85+
NeedLeaderElection: false,
86+
},
87+
}).
7888
Build(noop)
7989
Expect(err).To(MatchError(ContainSubstring("no kind is registered for the type builder.fakeType")))
8090
Expect(instance).To(BeNil())
@@ -97,6 +107,11 @@ var _ = Describe("application", func() {
97107
instance, err := ControllerManagedBy(m).
98108
For(&appsv1.ReplicaSet{}).
99109
Owns(&appsv1.ReplicaSet{}).
110+
WithOptions(controller.Options{
111+
LeaderElection: &controller.LeaderElectionOptions{
112+
NeedLeaderElection: false,
113+
},
114+
}).
100115
Build(noop)
101116
Expect(err).To(HaveOccurred())
102117
Expect(err.Error()).To(ContainSubstring("expected error"))
@@ -120,7 +135,12 @@ var _ = Describe("application", func() {
120135
instance, err := ControllerManagedBy(m).
121136
For(&appsv1.ReplicaSet{}).
122137
Owns(&appsv1.ReplicaSet{}).
123-
WithOptions(controller.Options{MaxConcurrentReconciles: maxConcurrentReconciles}).
138+
WithOptions(controller.Options{
139+
MaxConcurrentReconciles: maxConcurrentReconciles,
140+
LeaderElection: &controller.LeaderElectionOptions{
141+
NeedLeaderElection: false,
142+
},
143+
}).
124144
Build(noop)
125145
Expect(err).NotTo(HaveOccurred())
126146
Expect(instance).NotTo(BeNil())
@@ -141,6 +161,11 @@ var _ = Describe("application", func() {
141161
ctrl1, err := ControllerManagedBy(m).
142162
For(&TestDefaultValidator{}).
143163
Owns(&appsv1.ReplicaSet{}).
164+
WithOptions(controller.Options{
165+
LeaderElection: &controller.LeaderElectionOptions{
166+
NeedLeaderElection: false,
167+
},
168+
}).
144169
Build(noop)
145170
Expect(err).NotTo(HaveOccurred())
146171
Expect(ctrl1).NotTo(BeNil())
@@ -149,6 +174,11 @@ var _ = Describe("application", func() {
149174
ctrl2, err := ControllerManagedBy(m).
150175
For(&TestDefaultValidator{}).
151176
Owns(&appsv1.ReplicaSet{}).
177+
WithOptions(controller.Options{
178+
LeaderElection: &controller.LeaderElectionOptions{
179+
NeedLeaderElection: false,
180+
},
181+
}).
152182
Build(noop)
153183
Expect(err).NotTo(HaveOccurred())
154184
Expect(ctrl2).NotTo(BeNil())
@@ -162,7 +192,12 @@ var _ = Describe("application", func() {
162192

163193
bldr := ControllerManagedBy(m).
164194
For(&appsv1.Deployment{}).
165-
Owns(&appsv1.ReplicaSet{})
195+
Owns(&appsv1.ReplicaSet{}).
196+
WithOptions(controller.Options{
197+
LeaderElection: &controller.LeaderElectionOptions{
198+
NeedLeaderElection: false,
199+
},
200+
})
166201
doReconcileTest("3", stop, bldr, m, false)
167202
close(done)
168203
}, 10)
@@ -173,6 +208,11 @@ var _ = Describe("application", func() {
173208

174209
bldr := ControllerManagedBy(m).
175210
For(&appsv1.Deployment{}).
211+
WithOptions(controller.Options{
212+
LeaderElection: &controller.LeaderElectionOptions{
213+
NeedLeaderElection: false,
214+
},
215+
}).
176216
Watches( // Equivalent of Owns
177217
&source.Kind{Type: &appsv1.ReplicaSet{}},
178218
&handler.EnqueueRequestForOwner{OwnerType: &appsv1.Deployment{}, IsController: true})

pkg/controller/controller.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,18 @@ type Options struct {
3535

3636
// Reconciler reconciles an object
3737
Reconciler reconcile.Reconciler
38+
39+
// Leader election is by default
40+
LeaderElection *LeaderElectionOptions
41+
}
42+
43+
// Leader Election options
44+
type LeaderElectionOptions struct {
45+
// NeedLeaderElection determines whether or not to use leader election when starting the controller.
46+
NeedLeaderElection bool
47+
48+
// LeaderElectionID determines the name of the configmap that leader election will use for holding the leader lock.
49+
LeaderElectionID string
3850
}
3951

4052
// Controller implements a Kubernetes API. A Controller manages a work queue fed reconcile.Requests
@@ -73,6 +85,13 @@ func New(name string, mgr manager.Manager, options Options) (Controller, error)
7385
options.MaxConcurrentReconciles = 1
7486
}
7587

88+
if options.LeaderElection == nil {
89+
options.LeaderElection = &LeaderElectionOptions{
90+
NeedLeaderElection: true,
91+
LeaderElectionID: name,
92+
}
93+
}
94+
7695
// Inject dependencies into Reconciler
7796
if err := mgr.SetFields(options.Reconciler); err != nil {
7897
return nil, err
@@ -91,6 +110,8 @@ func New(name string, mgr manager.Manager, options Options) (Controller, error)
91110
},
92111
MaxConcurrentReconciles: options.MaxConcurrentReconciles,
93112
Name: name,
113+
LeaderElection: options.LeaderElection.NeedLeaderElection,
114+
LeaderElectionID: options.LeaderElection.LeaderElectionID,
94115
}
95116

96117
// Add the controller as a Manager components

pkg/controller/controller_integration_test.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,9 @@ var _ = Describe("controller", func() {
6464
reconciled <- request
6565
return reconcile.Result{}, nil
6666
}),
67+
LeaderElection: &controller.LeaderElectionOptions{
68+
NeedLeaderElection: false,
69+
},
6770
})
6871
Expect(err).NotTo(HaveOccurred())
6972

pkg/controller/controller_test.go

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,12 @@ var _ = Describe("controller.Controller", func() {
4646
It("should return an error if Name is not Specified", func(done Done) {
4747
m, err := manager.New(cfg, manager.Options{})
4848
Expect(err).NotTo(HaveOccurred())
49-
c, err := controller.New("", m, controller.Options{Reconciler: rec})
49+
c, err := controller.New("", m, controller.Options{
50+
Reconciler: rec,
51+
LeaderElection: &controller.LeaderElectionOptions{
52+
NeedLeaderElection: false,
53+
},
54+
})
5055
Expect(c).To(BeNil())
5156
Expect(err.Error()).To(ContainSubstring("must specify Name for Controller"))
5257

@@ -68,7 +73,12 @@ var _ = Describe("controller.Controller", func() {
6873
m, err := manager.New(cfg, manager.Options{})
6974
Expect(err).NotTo(HaveOccurred())
7075

71-
c, err := controller.New("foo", m, controller.Options{Reconciler: &failRec{}})
76+
c, err := controller.New("foo", m, controller.Options{
77+
Reconciler: &failRec{},
78+
LeaderElection: &controller.LeaderElectionOptions{
79+
NeedLeaderElection: false,
80+
},
81+
})
7282
Expect(c).To(BeNil())
7383
Expect(err).To(HaveOccurred())
7484
Expect(err.Error()).To(ContainSubstring("expected error"))
@@ -80,11 +90,21 @@ var _ = Describe("controller.Controller", func() {
8090
m, err := manager.New(cfg, manager.Options{})
8191
Expect(err).NotTo(HaveOccurred())
8292

83-
c1, err := controller.New("c1", m, controller.Options{Reconciler: rec})
93+
c1, err := controller.New("c1", m, controller.Options{
94+
Reconciler: rec,
95+
LeaderElection: &controller.LeaderElectionOptions{
96+
NeedLeaderElection: false,
97+
},
98+
})
8499
Expect(err).NotTo(HaveOccurred())
85100
Expect(c1).ToNot(BeNil())
86101

87-
c2, err := controller.New("c2", m, controller.Options{Reconciler: rec})
102+
c2, err := controller.New("c2", m, controller.Options{
103+
Reconciler: rec,
104+
LeaderElection: &controller.LeaderElectionOptions{
105+
NeedLeaderElection: false,
106+
},
107+
})
88108
Expect(err).NotTo(HaveOccurred())
89109
Expect(c2).ToNot(BeNil())
90110

pkg/internal/controller/controller.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,14 @@ type Controller struct {
5050
// MaxConcurrentReconciles is the maximum number of concurrent Reconciles which can be run. Defaults to 1.
5151
MaxConcurrentReconciles int
5252

53+
// LeaderElection determines whether or not to use leader election when
54+
// starting the controller.
55+
LeaderElection bool
56+
57+
// LeaderElectionID determines the name of the configmap that leader election
58+
// will use for holding the leader lock.
59+
LeaderElectionID string
60+
5361
// Reconciler is a function that can be called at any time with the Name / Namespace of an object and
5462
// ensures that the state of the system matches the state specified in the object.
5563
// Defaults to the DefaultReconcileFunc.
@@ -296,3 +304,11 @@ func (c *Controller) InjectFunc(f inject.Func) error {
296304
func (c *Controller) updateMetrics(reconcileTime time.Duration) {
297305
ctrlmetrics.ReconcileTime.WithLabelValues(c.Name).Observe(reconcileTime.Seconds())
298306
}
307+
308+
func (c *Controller) NeedLeaderElection() bool {
309+
return c.LeaderElection
310+
}
311+
312+
func (c *Controller) GetID() string {
313+
return c.LeaderElectionID
314+
}

pkg/internal/recorder/recorder_integration_test.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,9 @@ var _ = Describe("recorder", func() {
6161
recorder.Event(dp, corev1.EventTypeNormal, "test-reason", "test-msg")
6262
return reconcile.Result{}, nil
6363
}),
64+
LeaderElection: &controller.LeaderElectionOptions{
65+
NeedLeaderElection: false,
66+
},
6467
})
6568
Expect(err).NotTo(HaveOccurred())
6669

pkg/leaderelection/leader_election.go

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -52,11 +52,6 @@ func NewResourceLock(config *rest.Config, recorderProvider recorder.Provider, op
5252
return nil, nil
5353
}
5454

55-
// Default the LeaderElectionID
56-
if options.LeaderElectionID == "" {
57-
options.LeaderElectionID = "controller-leader-election-helper"
58-
}
59-
6055
// Default the namespace (if running in cluster)
6156
if options.LeaderElectionNamespace == "" {
6257
var err error

0 commit comments

Comments
 (0)