Skip to content

Commit f22e071

Browse files
committed
Add defaulting to leader election
1 parent e439a4f commit f22e071

File tree

2 files changed

+51
-9
lines changed

2 files changed

+51
-9
lines changed

pkg/leaderelection/leader_election.go

Lines changed: 33 additions & 2 deletions
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-runtime"
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

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

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

0 commit comments

Comments
 (0)