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  }