k8s.io/client-go@v0.31.1/tools/leaderelection/resourcelock/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 resourcelock
    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  	lease, err := ll.Client.Leases(ll.LeaseMeta.Namespace).Get(ctx, ll.LeaseMeta.Name, metav1.GetOptions{})
    43  	if err != nil {
    44  		return nil, nil, err
    45  	}
    46  	ll.lease = lease
    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  	subject := &coordinationv1.Lease{ObjectMeta: ll.lease.ObjectMeta}
    91  	// Populate the type meta, so we don't have to get it from the schema
    92  	subject.Kind = "Lease"
    93  	subject.APIVersion = coordinationv1.SchemeGroupVersion.String()
    94  	ll.LockConfig.EventRecorder.Eventf(subject, corev1.EventTypeNormal, "LeaderElection", events)
    95  }
    96  
    97  // Describe is used to convert details on current resource lock
    98  // into a string
    99  func (ll *LeaseLock) Describe() string {
   100  	return fmt.Sprintf("%v/%v", ll.LeaseMeta.Namespace, ll.LeaseMeta.Name)
   101  }
   102  
   103  // Identity returns the Identity of the lock
   104  func (ll *LeaseLock) Identity() string {
   105  	return ll.LockConfig.Identity
   106  }
   107  
   108  func LeaseSpecToLeaderElectionRecord(spec *coordinationv1.LeaseSpec) *LeaderElectionRecord {
   109  	var r LeaderElectionRecord
   110  	if spec.HolderIdentity != nil {
   111  		r.HolderIdentity = *spec.HolderIdentity
   112  	}
   113  	if spec.LeaseDurationSeconds != nil {
   114  		r.LeaseDurationSeconds = int(*spec.LeaseDurationSeconds)
   115  	}
   116  	if spec.LeaseTransitions != nil {
   117  		r.LeaderTransitions = int(*spec.LeaseTransitions)
   118  	}
   119  	if spec.AcquireTime != nil {
   120  		r.AcquireTime = metav1.Time{Time: spec.AcquireTime.Time}
   121  	}
   122  	if spec.RenewTime != nil {
   123  		r.RenewTime = metav1.Time{Time: spec.RenewTime.Time}
   124  	}
   125  	if spec.PreferredHolder != nil {
   126  		r.PreferredHolder = *spec.PreferredHolder
   127  	}
   128  	if spec.Strategy != nil {
   129  		r.Strategy = *spec.Strategy
   130  	}
   131  	return &r
   132  
   133  }
   134  
   135  func LeaderElectionRecordToLeaseSpec(ler *LeaderElectionRecord) coordinationv1.LeaseSpec {
   136  	leaseDurationSeconds := int32(ler.LeaseDurationSeconds)
   137  	leaseTransitions := int32(ler.LeaderTransitions)
   138  	spec := coordinationv1.LeaseSpec{
   139  		HolderIdentity:       &ler.HolderIdentity,
   140  		LeaseDurationSeconds: &leaseDurationSeconds,
   141  		AcquireTime:          &metav1.MicroTime{Time: ler.AcquireTime.Time},
   142  		RenewTime:            &metav1.MicroTime{Time: ler.RenewTime.Time},
   143  		LeaseTransitions:     &leaseTransitions,
   144  	}
   145  	if ler.PreferredHolder != "" {
   146  		spec.PreferredHolder = &ler.PreferredHolder
   147  	}
   148  	if ler.Strategy != "" {
   149  		spec.Strategy = &ler.Strategy
   150  	}
   151  	return spec
   152  }