Skip to content

Commit ffc3047

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

File tree

4 files changed

+46
-8
lines changed

4 files changed

+46
-8
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-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/internal.go

+4
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,10 @@ func (cm *controllerManager) GetRecorder(name string) record.EventRecorder {
139139
return cm.recorderProvider.GetEventRecorderFor(name)
140140
}
141141

142+
func (cm *controllerManager) GetResourceLock() resourcelock.Interface {
143+
return cm.resourceLock
144+
}
145+
142146
func (cm *controllerManager) Start(stop <-chan struct{}) error {
143147
if cm.resourceLock == nil {
144148
go cm.start(stop)

pkg/manager/manager.go

+3
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,9 @@ type Manager interface {
6767

6868
// GetRecorder returns a new EventRecorder for the provided name
6969
GetRecorder(name string) record.EventRecorder
70+
71+
// GetResourceLock returns an initialized ResourceLock
72+
GetResourceLock() resourcelock.Interface
7073
}
7174

7275
// Options are the arguments for creating a new Manager

pkg/manager/manager_test.go

+6-6
Original file line numberDiff line numberDiff line change
@@ -97,18 +97,18 @@ var _ = Describe("manger.Manager", func() {
9797
close(done)
9898
})
9999
Context("with leader election enabled", func() {
100-
It("should return an error if ID not set", func() {
100+
It("should default ID to controller-runtime if ID is not set", func() {
101101
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+
Expect(m).ToNot(BeNil())
103+
Expect(err).ToNot(HaveOccurred())
104+
Expect(m.GetResourceLock().Describe()).To(Equal("default/controller-runtime"))
105105
})
106106

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

0 commit comments

Comments
 (0)