istio.io/istio@v0.0.0-20240520182934-d79c90f27776/pilot/pkg/leaderelection/k8sleaderelection/k8sresourcelock/interface.go (about) 1 /* 2 Copyright 2016 The Kubernetes Authors. 3 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 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 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. 15 */ 16 17 package k8sresourcelock 18 19 import ( 20 "context" 21 "fmt" 22 "time" 23 24 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 25 "k8s.io/apimachinery/pkg/runtime" 26 clientset "k8s.io/client-go/kubernetes" 27 coordinationv1 "k8s.io/client-go/kubernetes/typed/coordination/v1" 28 corev1 "k8s.io/client-go/kubernetes/typed/core/v1" 29 restclient "k8s.io/client-go/rest" 30 ) 31 32 const ( 33 LeaderElectionRecordAnnotationKey = "control-plane.alpha.kubernetes.io/leader" 34 EndpointsResourceLock = "endpoints" 35 ConfigMapsResourceLock = "configmaps" 36 LeasesResourceLock = "leases" 37 EndpointsLeasesResourceLock = "endpointsleases" 38 ConfigMapsLeasesResourceLock = "configmapsleases" 39 ) 40 41 // LeaderElectionRecord is the record that is stored in the leader election annotation. 42 // This information should be used for observational purposes only and could be replaced 43 // with a random string (e.g. UUID) with only slight modification of this code. 44 // TODO(mikedanese): this should potentially be versioned 45 type LeaderElectionRecord struct { 46 // HolderIdentity is the ID that owns the lease. If empty, no one owns this lease and 47 // all callers may acquire. Versions of this library prior to Kubernetes 1.14 will not 48 // attempt to acquire leases with empty identities and will wait for the full lease 49 // interval to expire before attempting to reacquire. This value is set to empty when 50 // a client voluntarily steps down. 51 HolderIdentity string `json:"holderIdentity"` 52 // HolderKey is the Key of the lease owner. This may be empty if a key is not set. 53 HolderKey string `json:"holderKey"` 54 LeaseDurationSeconds int `json:"leaseDurationSeconds"` 55 AcquireTime metav1.Time `json:"acquireTime"` 56 RenewTime metav1.Time `json:"renewTime"` 57 LeaderTransitions int `json:"leaderTransitions"` 58 } 59 60 // EventRecorder records a change in the ResourceLock. 61 type EventRecorder interface { 62 Eventf(obj runtime.Object, eventType, reason, message string, args ...any) 63 } 64 65 // ResourceLockConfig common data that exists across different 66 // resource locks 67 type ResourceLockConfig struct { 68 // Identity is the unique string identifying a lease holder across 69 // all participants in an election. 70 Identity string 71 // Key is a user-defined value used to indicate how high priority this lock 72 // have. Other locks may steal the lock from us if they believe their key 73 // has a higher priority. 74 Key string 75 // EventRecorder is optional. 76 EventRecorder EventRecorder 77 } 78 79 // Interface offers a common interface for locking on arbitrary 80 // resources used in leader election. The Interface is used 81 // to hide the details on specific implementations in order to allow 82 // them to change over time. This interface is strictly for use 83 // by the leaderelection code. 84 type Interface interface { 85 // Get returns the LeaderElectionRecord 86 Get(ctx context.Context) (*LeaderElectionRecord, []byte, error) 87 88 // Create attempts to create a LeaderElectionRecord 89 Create(ctx context.Context, ler LeaderElectionRecord) error 90 91 // Update will update and existing LeaderElectionRecord 92 Update(ctx context.Context, ler LeaderElectionRecord) error 93 94 // RecordEvent is used to record events 95 RecordEvent(string) 96 97 // Identity will return the locks Identity 98 Identity() string 99 Key() string 100 101 // Describe is used to convert details on current resource lock 102 // into a string 103 Describe() string 104 } 105 106 // Manufacture will create a lock of a given type according to the input parameters 107 // nolint: lll 108 func New(lockType string, ns string, name string, coreClient corev1.CoreV1Interface, coordinationClient coordinationv1.CoordinationV1Interface, rlc ResourceLockConfig) (Interface, error) { 109 endpointsLock := &EndpointsLock{ 110 EndpointsMeta: metav1.ObjectMeta{ 111 Namespace: ns, 112 Name: name, 113 }, 114 Client: coreClient, 115 LockConfig: rlc, 116 } 117 configmapLock := &ConfigMapLock{ 118 ConfigMapMeta: metav1.ObjectMeta{ 119 Namespace: ns, 120 Name: name, 121 }, 122 Client: coreClient, 123 LockConfig: rlc, 124 } 125 leaseLock := &LeaseLock{ 126 LeaseMeta: metav1.ObjectMeta{ 127 Namespace: ns, 128 Name: name, 129 }, 130 Client: coordinationClient, 131 LockConfig: rlc, 132 } 133 switch lockType { 134 case EndpointsResourceLock: 135 return endpointsLock, nil 136 case ConfigMapsResourceLock: 137 return configmapLock, nil 138 case LeasesResourceLock: 139 return leaseLock, nil 140 case EndpointsLeasesResourceLock: 141 return &MultiLock{ 142 Primary: endpointsLock, 143 Secondary: leaseLock, 144 }, nil 145 case ConfigMapsLeasesResourceLock: 146 return &MultiLock{ 147 Primary: configmapLock, 148 Secondary: leaseLock, 149 }, nil 150 default: 151 return nil, fmt.Errorf("invalid lock-type %s", lockType) 152 } 153 } 154 155 // NewFromKubeconfig will create a lock of a given type according to the input parameters. 156 // Timeout set for a client used to contact to Kubernetes should be lower than 157 // RenewDeadline to keep a single hung request from forcing a leader loss. 158 // Setting it to max(time.Second, RenewDeadline/2) as a reasonable heuristic. 159 // nolint: lll 160 func NewFromKubeconfig(lockType string, ns string, name string, rlc ResourceLockConfig, kubeconfig *restclient.Config, renewDeadline time.Duration) (Interface, error) { 161 // shallow copy, do not modify the kubeconfig 162 config := *kubeconfig 163 timeout := renewDeadline / 2 164 if timeout < time.Second { 165 timeout = time.Second 166 } 167 config.Timeout = timeout 168 leaderElectionClient := clientset.NewForConfigOrDie(restclient.AddUserAgent(&config, "leader-election")) 169 return New(lockType, ns, name, leaderElectionClient.CoreV1(), leaderElectionClient.CoordinationV1(), rlc) 170 }