istio.io/istio@v0.0.0-20240520182934-d79c90f27776/pilot/pkg/leaderelection/k8sleaderelection/k8sresourcelock/endpointslock.go (about)

     1  /*
     2  Copyright 2016 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  	v1 "k8s.io/api/core/v1"
    26  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    27  	corev1client "k8s.io/client-go/kubernetes/typed/core/v1"
    28  )
    29  
    30  type EndpointsLock struct {
    31  	// EndpointsMeta should contain a Name and a Namespace of an
    32  	// Endpoints object that the LeaderElector will attempt to lead.
    33  	EndpointsMeta metav1.ObjectMeta
    34  	Client        corev1client.EndpointsGetter
    35  	LockConfig    ResourceLockConfig
    36  	e             *v1.Endpoints
    37  }
    38  
    39  // Get returns the election record from a Endpoints Annotation
    40  func (el *EndpointsLock) Get(ctx context.Context) (*LeaderElectionRecord, []byte, error) {
    41  	var record LeaderElectionRecord
    42  	var err error
    43  	el.e, err = el.Client.Endpoints(el.EndpointsMeta.Namespace).Get(ctx, el.EndpointsMeta.Name, metav1.GetOptions{})
    44  	if err != nil {
    45  		return nil, nil, err
    46  	}
    47  	if el.e.Annotations == nil {
    48  		el.e.Annotations = make(map[string]string)
    49  	}
    50  	recordStr, found := el.e.Annotations[LeaderElectionRecordAnnotationKey]
    51  	recordBytes := []byte(recordStr)
    52  	if found {
    53  		if err := json.Unmarshal(recordBytes, &record); err != nil {
    54  			return nil, nil, err
    55  		}
    56  	}
    57  	return &record, recordBytes, nil
    58  }
    59  
    60  // Create attempts to create a LeaderElectionRecord annotation
    61  func (el *EndpointsLock) Create(ctx context.Context, ler LeaderElectionRecord) error {
    62  	recordBytes, err := json.Marshal(ler)
    63  	if err != nil {
    64  		return err
    65  	}
    66  	el.e, err = el.Client.Endpoints(el.EndpointsMeta.Namespace).Create(ctx, &v1.Endpoints{
    67  		ObjectMeta: metav1.ObjectMeta{
    68  			Name:      el.EndpointsMeta.Name,
    69  			Namespace: el.EndpointsMeta.Namespace,
    70  			Annotations: map[string]string{
    71  				LeaderElectionRecordAnnotationKey: string(recordBytes),
    72  			},
    73  		},
    74  	}, metav1.CreateOptions{})
    75  	return err
    76  }
    77  
    78  // Update will update and existing annotation on a given resource.
    79  func (el *EndpointsLock) Update(ctx context.Context, ler LeaderElectionRecord) error {
    80  	if el.e == nil {
    81  		return errors.New("endpoint not initialized, call get or create first")
    82  	}
    83  	recordBytes, err := json.Marshal(ler)
    84  	if err != nil {
    85  		return err
    86  	}
    87  	if el.e.Annotations == nil {
    88  		el.e.Annotations = make(map[string]string)
    89  	}
    90  	el.e.Annotations[LeaderElectionRecordAnnotationKey] = string(recordBytes)
    91  	e, err := el.Client.Endpoints(el.EndpointsMeta.Namespace).Update(ctx, el.e, metav1.UpdateOptions{})
    92  	if err != nil {
    93  		return err
    94  	}
    95  	el.e = e
    96  	return nil
    97  }
    98  
    99  // RecordEvent in leader election while adding meta-data
   100  func (el *EndpointsLock) RecordEvent(s string) {
   101  	if el.LockConfig.EventRecorder == nil {
   102  		return
   103  	}
   104  	events := fmt.Sprintf("%v %v", el.LockConfig.Identity, s)
   105  	el.LockConfig.EventRecorder.Eventf(&v1.Endpoints{ObjectMeta: el.e.ObjectMeta}, v1.EventTypeNormal, "LeaderElection", events)
   106  }
   107  
   108  // Describe is used to convert details on current resource lock
   109  // into a string
   110  func (el *EndpointsLock) Describe() string {
   111  	return fmt.Sprintf("%v/%v", el.EndpointsMeta.Namespace, el.EndpointsMeta.Name)
   112  }
   113  
   114  // Identity returns the Identity of the lock
   115  func (el *EndpointsLock) Identity() string {
   116  	return el.LockConfig.Identity
   117  }
   118  
   119  // Key returns the Key of the lock
   120  func (el *EndpointsLock) Key() string {
   121  	return el.LockConfig.Key
   122  }