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  }