Skip to content

Commit b9a9ca0

Browse files
authored
Merge pull request #3237 from DerekFrank/leader-election-labels
✨ feat: add support for custom labels on leader election leases ✨
2 parents 15c5d61 + 9db63b4 commit b9a9ca0

File tree

3 files changed

+45
-16
lines changed

3 files changed

+45
-16
lines changed

pkg/leaderelection/leader_election.go

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -56,14 +56,17 @@ type Options struct {
5656
// Without that, a single slow response from the API server can result
5757
// in losing leadership.
5858
RenewDeadline time.Duration
59+
60+
// LeaderLabels are an optional set of labels that will be set on the lease object
61+
// when this replica becomes leader
62+
LeaderLabels map[string]string
5963
}
6064

6165
// NewResourceLock creates a new resource lock for use in a leader election loop.
6266
func NewResourceLock(config *rest.Config, recorderProvider recorder.Provider, options Options) (resourcelock.Interface, error) {
6367
if !options.LeaderElection {
6468
return nil, nil
6569
}
66-
6770
// Default resource lock to "leases". The previous default (from v0.7.0 to v0.11.x) was configmapsleases, which was
6871
// used to migrate from configmaps to leases. Since the default was "configmapsleases" for over a year, spanning
6972
// five minor releases, any actively maintained operators are very likely to have a released version that uses
@@ -93,22 +96,21 @@ func NewResourceLock(config *rest.Config, recorderProvider recorder.Provider, op
9396
}
9497
id = id + "_" + string(uuid.NewUUID())
9598

96-
// Construct clients for leader election
97-
rest.AddUserAgent(config, "leader-election")
99+
// Construct config for leader election
100+
config = rest.AddUserAgent(config, "leader-election")
98101

102+
// Timeout set for a client used to contact to Kubernetes should be lower than
103+
// RenewDeadline to keep a single hung request from forcing a leader loss.
104+
// Setting it to max(time.Second, RenewDeadline/2) as a reasonable heuristic.
99105
if options.RenewDeadline != 0 {
100-
return resourcelock.NewFromKubeconfig(options.LeaderElectionResourceLock,
101-
options.LeaderElectionNamespace,
102-
options.LeaderElectionID,
103-
resourcelock.ResourceLockConfig{
104-
Identity: id,
105-
EventRecorder: recorderProvider.GetEventRecorderFor(id),
106-
},
107-
config,
108-
options.RenewDeadline,
109-
)
106+
timeout := options.RenewDeadline / 2
107+
if timeout < time.Second {
108+
timeout = time.Second
109+
}
110+
config.Timeout = timeout
110111
}
111112

113+
// Construct clients for leader election
112114
corev1Client, err := corev1client.NewForConfig(config)
113115
if err != nil {
114116
return nil, err
@@ -118,7 +120,8 @@ func NewResourceLock(config *rest.Config, recorderProvider recorder.Provider, op
118120
if err != nil {
119121
return nil, err
120122
}
121-
return resourcelock.New(options.LeaderElectionResourceLock,
123+
124+
return resourcelock.NewWithLabels(options.LeaderElectionResourceLock,
122125
options.LeaderElectionNamespace,
123126
options.LeaderElectionID,
124127
corev1Client,
@@ -127,6 +130,7 @@ func NewResourceLock(config *rest.Config, recorderProvider recorder.Provider, op
127130
Identity: id,
128131
EventRecorder: recorderProvider.GetEventRecorderFor(id),
129132
},
133+
options.LeaderLabels,
130134
)
131135
}
132136

pkg/manager/manager.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -201,10 +201,15 @@ type Options struct {
201201
// LeaseDuration time first.
202202
LeaderElectionReleaseOnCancel bool
203203

204+
// LeaderElectionLabels allows a controller to supplement all leader election api calls with a set of custom labels based on
205+
// the replica attempting to acquire leader status.
206+
LeaderElectionLabels map[string]string
207+
204208
// LeaderElectionResourceLockInterface allows to provide a custom resourcelock.Interface that was created outside
205209
// of the controller-runtime. If this value is set the options LeaderElectionID, LeaderElectionNamespace,
206-
// LeaderElectionResourceLock, LeaseDuration, RenewDeadline and RetryPeriod will be ignored. This can be useful if you
207-
// want to use a locking mechanism that is currently not supported, like a MultiLock across two Kubernetes clusters.
210+
// LeaderElectionResourceLock, LeaseDuration, RenewDeadline, RetryPeriod and LeaderElectionLeases will be ignored.
211+
// This can be useful if you want to use a locking mechanism that is currently not supported, like a MultiLock across
212+
// two Kubernetes clusters.
208213
LeaderElectionResourceLockInterface resourcelock.Interface
209214

210215
// LeaseDuration is the duration that non-leader candidates will
@@ -390,6 +395,7 @@ func New(config *rest.Config, options Options) (Manager, error) {
390395
LeaderElectionID: options.LeaderElectionID,
391396
LeaderElectionNamespace: options.LeaderElectionNamespace,
392397
RenewDeadline: *options.RenewDeadline,
398+
LeaderLabels: options.LeaderElectionLabels,
393399
})
394400
if err != nil {
395401
return nil, err

pkg/manager/manager_test.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -498,6 +498,25 @@ var _ = Describe("manger.Manager", func() {
498498
Expect(err).ToNot(HaveOccurred())
499499
Expect(record.HolderIdentity).To(BeEmpty())
500500
})
501+
It("should set the leaselocks's label field when LeaderElectionLabels is set", func() {
502+
labels := map[string]string{"my-key": "my-val"}
503+
m, err := New(cfg, Options{
504+
LeaderElection: true,
505+
LeaderElectionResourceLock: resourcelock.LeasesResourceLock,
506+
LeaderElectionID: "controller-runtime",
507+
LeaderElectionNamespace: "default",
508+
LeaderElectionLabels: labels,
509+
})
510+
Expect(err).ToNot(HaveOccurred())
511+
Expect(m).ToNot(BeNil())
512+
cm, ok := m.(*controllerManager)
513+
Expect(ok).To(BeTrue())
514+
ll, isLeaseLock := cm.resourceLock.(*resourcelock.LeaseLock)
515+
Expect(isLeaseLock).To(BeTrue())
516+
val, exists := ll.Labels["my-key"]
517+
Expect(exists).To(BeTrue())
518+
Expect(val).To(Equal("my-val"))
519+
})
501520
When("using a custom LeaderElectionResourceLockInterface", func() {
502521
It("should use the custom LeaderElectionResourceLockInterface", func() {
503522
rl, err := fakeleaderelection.NewResourceLock(nil, nil, leaderelection.Options{})

0 commit comments

Comments
 (0)