istio.io/istio@v0.0.0-20240520182934-d79c90f27776/pilot/pkg/leaderelection/k8sleaderelection/k8sresourcelock/leaselock.go (about) 1 /* 2 Copyright 2018 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 "encoding/json" 22 "errors" 23 "fmt" 24 25 coordinationv1 "k8s.io/api/coordination/v1" 26 corev1 "k8s.io/api/core/v1" 27 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 28 coordinationv1client "k8s.io/client-go/kubernetes/typed/coordination/v1" 29 ) 30 31 type LeaseLock struct { 32 // LeaseMeta should contain a Name and a Namespace of a 33 // LeaseMeta object that the LeaderElector will attempt to lead. 34 LeaseMeta metav1.ObjectMeta 35 Client coordinationv1client.LeasesGetter 36 LockConfig ResourceLockConfig 37 lease *coordinationv1.Lease 38 } 39 40 // Get returns the election record from a Lease spec 41 func (ll *LeaseLock) Get(ctx context.Context) (*LeaderElectionRecord, []byte, error) { 42 var err error 43 ll.lease, err = ll.Client.Leases(ll.LeaseMeta.Namespace).Get(ctx, ll.LeaseMeta.Name, metav1.GetOptions{}) 44 if err != nil { 45 return nil, nil, err 46 } 47 record := LeaseSpecToLeaderElectionRecord(&ll.lease.Spec) 48 recordByte, err := json.Marshal(*record) 49 if err != nil { 50 return nil, nil, err 51 } 52 return record, recordByte, nil 53 } 54 55 // Create attempts to create a Lease 56 func (ll *LeaseLock) Create(ctx context.Context, ler LeaderElectionRecord) error { 57 var err error 58 ll.lease, err = ll.Client.Leases(ll.LeaseMeta.Namespace).Create(ctx, &coordinationv1.Lease{ 59 ObjectMeta: metav1.ObjectMeta{ 60 Name: ll.LeaseMeta.Name, 61 Namespace: ll.LeaseMeta.Namespace, 62 }, 63 Spec: LeaderElectionRecordToLeaseSpec(&ler), 64 }, metav1.CreateOptions{}) 65 return err 66 } 67 68 // Update will update an existing Lease spec. 69 func (ll *LeaseLock) Update(ctx context.Context, ler LeaderElectionRecord) error { 70 if ll.lease == nil { 71 return errors.New("lease not initialized, call get or create first") 72 } 73 ll.lease.Spec = LeaderElectionRecordToLeaseSpec(&ler) 74 75 lease, err := ll.Client.Leases(ll.LeaseMeta.Namespace).Update(ctx, ll.lease, metav1.UpdateOptions{}) 76 if err != nil { 77 return err 78 } 79 80 ll.lease = lease 81 return nil 82 } 83 84 // RecordEvent in leader election while adding meta-data 85 func (ll *LeaseLock) RecordEvent(s string) { 86 if ll.LockConfig.EventRecorder == nil { 87 return 88 } 89 events := fmt.Sprintf("%v %v", ll.LockConfig.Identity, s) 90 ll.LockConfig.EventRecorder.Eventf(&coordinationv1.Lease{ObjectMeta: ll.lease.ObjectMeta}, corev1.EventTypeNormal, "LeaderElection", events) 91 } 92 93 // Describe is used to convert details on current resource lock 94 // into a string 95 func (ll *LeaseLock) Describe() string { 96 return fmt.Sprintf("%v/%v", ll.LeaseMeta.Namespace, ll.LeaseMeta.Name) 97 } 98 99 // Identity returns the Identity of the lock 100 func (ll *LeaseLock) Identity() string { 101 return ll.LockConfig.Identity 102 } 103 104 // Key returns the Key of the lock 105 func (ll *LeaseLock) Key() string { 106 return ll.LockConfig.Key 107 } 108 109 func LeaseSpecToLeaderElectionRecord(spec *coordinationv1.LeaseSpec) *LeaderElectionRecord { 110 var r LeaderElectionRecord 111 if spec.HolderIdentity != nil { 112 r.HolderIdentity = *spec.HolderIdentity 113 } 114 if spec.LeaseDurationSeconds != nil { 115 r.LeaseDurationSeconds = int(*spec.LeaseDurationSeconds) 116 } 117 if spec.LeaseTransitions != nil { 118 r.LeaderTransitions = int(*spec.LeaseTransitions) 119 } 120 if spec.AcquireTime != nil { 121 r.AcquireTime = metav1.Time{Time: spec.AcquireTime.Time} 122 } 123 if spec.RenewTime != nil { 124 r.RenewTime = metav1.Time{Time: spec.RenewTime.Time} 125 } 126 return &r 127 } 128 129 func LeaderElectionRecordToLeaseSpec(ler *LeaderElectionRecord) coordinationv1.LeaseSpec { 130 leaseDurationSeconds := int32(ler.LeaseDurationSeconds) 131 leaseTransitions := int32(ler.LeaderTransitions) 132 return coordinationv1.LeaseSpec{ 133 HolderIdentity: &ler.HolderIdentity, 134 LeaseDurationSeconds: &leaseDurationSeconds, 135 AcquireTime: &metav1.MicroTime{Time: ler.AcquireTime.Time}, 136 RenewTime: &metav1.MicroTime{Time: ler.RenewTime.Time}, 137 LeaseTransitions: &leaseTransitions, 138 } 139 }