Skip to content

Commit 50b6bdd

Browse files
committed
Add defaulting to leader election
1 parent 747d4f3 commit 50b6bdd

File tree

2 files changed

+51
-9
lines changed

2 files changed

+51
-9
lines changed

pkg/leaderelection/leader_election.go

+33-2
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package leaderelection
1818

1919
import (
2020
"fmt"
21+
"io/ioutil"
2122
"os"
2223

2324
"k8s.io/apimachinery/pkg/util/uuid"
@@ -27,6 +28,8 @@ import (
2728
"sigs.k8s.io/controller-runtime/pkg/recorder"
2829
)
2930

31+
const inClusterNamespacePath = "/var/run/secrets/kubernetes.io/serviceaccount/namespace"
32+
3033
// Options provides the required configuration to create a new resource lock
3134
type Options struct {
3235
// LeaderElection determines whether or not to use leader election when
@@ -49,8 +52,18 @@ func NewResourceLock(config *rest.Config, recorderProvider recorder.Provider, op
4952
return nil, nil
5053
}
5154

52-
if options.LeaderElectionID == "" || options.LeaderElectionNamespace == "" {
53-
return nil, fmt.Errorf("if leader election is enabled, both LeaderElectionID and LeaderElectionNamespace must be set")
55+
// Default the LeaderElectionID
56+
if options.LeaderElectionID == "" {
57+
options.LeaderElectionID = "controller-leader-election-helper"
58+
}
59+
60+
// Default the namespace (if running in cluster)
61+
if options.LeaderElectionNamespace == "" {
62+
var err error
63+
options.LeaderElectionNamespace, err = getInClusterNamespace()
64+
if err != nil {
65+
return nil, fmt.Errorf("unable to find leader election namespace: %v", err)
66+
}
5467
}
5568

5669
// Leader id, needs to be unique
@@ -76,3 +89,21 @@ func NewResourceLock(config *rest.Config, recorderProvider recorder.Provider, op
7689
EventRecorder: recorderProvider.GetEventRecorderFor(id),
7790
})
7891
}
92+
93+
func getInClusterNamespace() (string, error) {
94+
// Check whether the namespace file exists.
95+
// If not, we are not running in cluster so can't guess the namespace.
96+
_, err := os.Stat(inClusterNamespacePath)
97+
if os.IsNotExist(err) {
98+
return "", fmt.Errorf("not running in-cluster, please specify LeaderElectionNamespace")
99+
} else if err != nil {
100+
return "", fmt.Errorf("error checking namespace file: %v", err)
101+
}
102+
103+
// Load the namespace file and return itss content
104+
namespace, err := ioutil.ReadFile(inClusterNamespacePath)
105+
if err != nil {
106+
return "", fmt.Errorf("error reading namespace file: %v", err)
107+
}
108+
return string(namespace), nil
109+
}

pkg/manager/manager_test.go

+18-7
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,11 @@ import (
2525
"k8s.io/apimachinery/pkg/api/meta"
2626
"k8s.io/apimachinery/pkg/runtime"
2727
"k8s.io/client-go/rest"
28+
"k8s.io/client-go/tools/leaderelection/resourcelock"
2829
"sigs.k8s.io/controller-runtime/pkg/cache"
2930
"sigs.k8s.io/controller-runtime/pkg/cache/informertest"
3031
"sigs.k8s.io/controller-runtime/pkg/client"
32+
"sigs.k8s.io/controller-runtime/pkg/leaderelection"
3133
fakeleaderelection "sigs.k8s.io/controller-runtime/pkg/leaderelection/fake"
3234
"sigs.k8s.io/controller-runtime/pkg/reconcile"
3335
"sigs.k8s.io/controller-runtime/pkg/recorder"
@@ -98,18 +100,27 @@ var _ = Describe("manger.Manager", func() {
98100
close(done)
99101
})
100102
Context("with leader election enabled", func() {
101-
It("should return an error if ID not set", func() {
102-
m, err := New(cfg, Options{LeaderElection: true, LeaderElectionNamespace: "default"})
103-
Expect(m).To(BeNil())
104-
Expect(err).To(HaveOccurred())
105-
Expect(err.Error()).To(ContainSubstring("if leader election is enabled, both LeaderElectionID and LeaderElectionNamespace must be set"))
103+
It("should default ID to controller-runtime if ID is not set", func() {
104+
var rl resourcelock.Interface
105+
m, err := New(cfg, Options{
106+
LeaderElection: true,
107+
LeaderElectionNamespace: "default",
108+
newResourceLock: func(config *rest.Config, recorderProvider recorder.Provider, options leaderelection.Options) (resourcelock.Interface, error) {
109+
var err error
110+
rl, err = leaderelection.NewResourceLock(config, recorderProvider, options)
111+
return rl, err
112+
},
113+
})
114+
Expect(m).ToNot(BeNil())
115+
Expect(err).ToNot(HaveOccurred())
116+
Expect(rl.Describe()).To(Equal("default/controller-leader-election-helper"))
106117
})
107118

108-
It("should return an error if namespace not set", func() {
119+
It("should return an error if namespace not set and not running in cluster", func() {
109120
m, err := New(cfg, Options{LeaderElection: true, LeaderElectionID: "controller-runtime"})
110121
Expect(m).To(BeNil())
111122
Expect(err).To(HaveOccurred())
112-
Expect(err.Error()).To(ContainSubstring("if leader election is enabled, both LeaderElectionID and LeaderElectionNamespace must be set"))
123+
Expect(err.Error()).To(ContainSubstring("unable to find leader election namespace: not running in-cluster, please specify LeaderElectionNamespace"))
113124
})
114125
})
115126
})

0 commit comments

Comments
 (0)