istio.io/istio@v0.0.0-20240520182934-d79c90f27776/pilot/pkg/leaderelection/k8sleaderelection/k8sresourcelock/multilock.go (about) 1 /* 2 Copyright 2019 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 "bytes" 21 "context" 22 "encoding/json" 23 24 kerrors "k8s.io/apimachinery/pkg/api/errors" 25 ) 26 27 const ( 28 UnknownLeader = "leaderelection.k8s.io/unknown" 29 ) 30 31 // MultiLock is used for lock's migration 32 type MultiLock struct { 33 Primary Interface 34 Secondary Interface 35 } 36 37 // Get returns the older election record of the lock 38 func (ml *MultiLock) Get(ctx context.Context) (*LeaderElectionRecord, []byte, error) { 39 primary, primaryRaw, err := ml.Primary.Get(ctx) 40 if err != nil { 41 return nil, nil, err 42 } 43 44 secondary, secondaryRaw, err := ml.Secondary.Get(ctx) 45 if err != nil { 46 // Lock is held by old client 47 if kerrors.IsNotFound(err) && primary.HolderIdentity != ml.Identity() { 48 return primary, primaryRaw, nil 49 } 50 return nil, nil, err 51 } 52 53 if primary.HolderIdentity != secondary.HolderIdentity { 54 primary.HolderIdentity = UnknownLeader 55 primaryRaw, err = json.Marshal(primary) 56 if err != nil { 57 return nil, nil, err 58 } 59 } 60 return primary, ConcatRawRecord(primaryRaw, secondaryRaw), nil 61 } 62 63 // Create attempts to create both primary lock and secondary lock 64 func (ml *MultiLock) Create(ctx context.Context, ler LeaderElectionRecord) error { 65 err := ml.Primary.Create(ctx, ler) 66 if err != nil && !kerrors.IsAlreadyExists(err) { 67 return err 68 } 69 return ml.Secondary.Create(ctx, ler) 70 } 71 72 // Update will update and existing annotation on both two resources. 73 func (ml *MultiLock) Update(ctx context.Context, ler LeaderElectionRecord) error { 74 err := ml.Primary.Update(ctx, ler) 75 if err != nil { 76 return err 77 } 78 _, _, err = ml.Secondary.Get(ctx) 79 if err != nil && kerrors.IsNotFound(err) { 80 return ml.Secondary.Create(ctx, ler) 81 } 82 return ml.Secondary.Update(ctx, ler) 83 } 84 85 // RecordEvent in leader election while adding meta-data 86 func (ml *MultiLock) RecordEvent(s string) { 87 ml.Primary.RecordEvent(s) 88 ml.Secondary.RecordEvent(s) 89 } 90 91 // Describe is used to convert details on current resource lock 92 // into a string 93 func (ml *MultiLock) Describe() string { 94 return ml.Primary.Describe() 95 } 96 97 // Identity returns the Identity of the lock 98 func (ml *MultiLock) Identity() string { 99 return ml.Primary.Identity() 100 } 101 102 // Key returns the Key of the lock 103 func (ml *MultiLock) Key() string { 104 return ml.Primary.Key() 105 } 106 107 func ConcatRawRecord(primaryRaw, secondaryRaw []byte) []byte { 108 return bytes.Join([][]byte{primaryRaw, secondaryRaw}, []byte(",")) 109 }