2 Copyright 2018 The Kubernetes Authors.
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
8 http://www.apache.org/licenses/LICENSE-2.0
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
17 package leaderelection
24 "k8s.io/apimachinery/pkg/util/uuid"
25 "k8s.io/client-go/kubernetes"
26 "k8s.io/client-go/rest"
27 "k8s.io/client-go/tools/leaderelection/resourcelock"
28 "sigs.k8s.io/controller-runtime/pkg/recorder"
31 const inClusterNamespacePath = "/var/run/secrets/kubernetes.io/serviceaccount/namespace"
33 // Options provides the required configuration to create a new resource lock
35 // LeaderElection determines whether or not to use leader election when
36 // starting the manager.
39 // LeaderElectionNamespace determines the namespace in which the leader
40 // election configmap will be created.
41 LeaderElectionNamespace string
43 // LeaderElectionID determines the name of the configmap that leader election
44 // will use for holding the leader lock.
45 LeaderElectionID string
48 // NewResourceLock creates a new config map resource lock for use in a leader
50 func NewResourceLock(config *rest.Config, recorderProvider recorder.Provider, options Options) (resourcelock.Interface, error) {
51 if !options.LeaderElection {
55 // Default the LeaderElectionID
56 if options.LeaderElectionID == "" {
57 options.LeaderElectionID = "controller-leader-election-helper"
60 // Default the namespace (if running in cluster)
61 if options.LeaderElectionNamespace == "" {
63 options.LeaderElectionNamespace, err = getInClusterNamespace()
65 return nil, fmt.Errorf("unable to find leader election namespace: %v", err)
69 // Leader id, needs to be unique
70 id, err := os.Hostname()
74 id = id + "_" + string(uuid.NewUUID())
76 // Construct client for leader election
77 client, err := kubernetes.NewForConfig(config)
82 // TODO(JoelSpeed): switch to leaderelection object in 1.12
83 return resourcelock.New(resourcelock.ConfigMapsResourceLock,
84 options.LeaderElectionNamespace,
85 options.LeaderElectionID,
87 resourcelock.ResourceLockConfig{
89 EventRecorder: recorderProvider.GetEventRecorderFor(id),
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)
103 // Load the namespace file and return itss content
104 namespace, err := ioutil.ReadFile(inClusterNamespacePath)
106 return "", fmt.Errorf("error reading namespace file: %v", err)
108 return string(namespace), nil