github.phpd.cn/cilium/cilium@v1.6.12/operator/k8s_identity.go (about)

     1  // Copyright 2019 Authors of Cilium
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package main
    16  
    17  import (
    18  	"context"
    19  	"time"
    20  
    21  	"github.com/cilium/cilium/pkg/controller"
    22  	"github.com/cilium/cilium/pkg/k8s/apis/cilium.io/v2"
    23  	"github.com/cilium/cilium/pkg/k8s/informer"
    24  	"github.com/cilium/cilium/pkg/k8s/types"
    25  	"github.com/cilium/cilium/pkg/logging/logfields"
    26  	"github.com/sirupsen/logrus"
    27  
    28  	"k8s.io/api/core/v1"
    29  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    30  	"k8s.io/apimachinery/pkg/fields"
    31  	"k8s.io/apimachinery/pkg/util/wait"
    32  	"k8s.io/client-go/tools/cache"
    33  )
    34  
    35  var identityStore cache.Store
    36  
    37  // deleteIdentity deletes an identity. It includes the resource version and
    38  // will error if the object has since been changed.
    39  func deleteIdentity(identity *types.Identity) error {
    40  	err := ciliumK8sClient.CiliumV2().CiliumIdentities().Delete(
    41  		identity.Name,
    42  		&metav1.DeleteOptions{
    43  			Preconditions: &metav1.Preconditions{
    44  				UID:             &identity.UID,
    45  				ResourceVersion: &identity.ResourceVersion,
    46  			},
    47  		})
    48  	if err != nil {
    49  		log.WithError(err).Error("Unable to delete identity")
    50  	} else {
    51  		log.WithFields(logrus.Fields{"identity": identity.GetName()}).Info("Garbage collected identity")
    52  	}
    53  
    54  	return err
    55  }
    56  
    57  // identityGCIteration is a single iteration of a garbage collection. It will
    58  // delete identities that have node status entries that are all older than
    59  // k8sIdentityHeartbeatTimeout.
    60  // Note: cilium-operator deletes identities in the OnDelete handler when they
    61  // have no nodes using them (status is empty). This generally means that
    62  // deletes here are for longer lived identities with no active users.
    63  func identityGCIteration() {
    64  	if identityStore == nil {
    65  		return
    66  	}
    67  
    68  nextIdentity:
    69  	for _, identityObject := range identityStore.List() {
    70  		identity, ok := identityObject.(*types.Identity)
    71  		if !ok {
    72  			log.WithField(logfields.Object, identityObject).
    73  				Errorf("Saw %T object while expecting k8s/types.Identity", identityObject)
    74  			continue
    75  		}
    76  
    77  		for _, heartbeat := range identity.Status.Nodes {
    78  			if time.Since(heartbeat.Time) < k8sIdentityHeartbeatTimeout {
    79  				continue nextIdentity
    80  			}
    81  		}
    82  
    83  		log.WithFields(logrus.Fields{
    84  			logfields.Identity: identity,
    85  			"nodes":            identity.Status.Nodes,
    86  		}).Debug("Deleting unused identity")
    87  		deleteIdentity(identity)
    88  	}
    89  }
    90  
    91  func startCRDIdentityGC() {
    92  	controller.NewManager().UpdateController("crd-identity-gc",
    93  		controller.ControllerParams{
    94  			RunInterval: identityGCInterval,
    95  			DoFunc: func(ctx context.Context) error {
    96  				identityGCIteration()
    97  				return nil
    98  			},
    99  		})
   100  }
   101  
   102  func handleIdentityUpdate(identity *types.Identity) {
   103  	// If no more nodes are using this identity, release the ID for reuse.
   104  	// If deleteIdentity fails the identity will be removed by the periodic GC.
   105  	if len(identity.Status.Nodes) == 0 {
   106  		deleteIdentity(identity)
   107  	}
   108  }
   109  
   110  func startManagingK8sIdentities() {
   111  	identityStore = cache.NewStore(cache.DeletionHandlingMetaNamespaceKeyFunc)
   112  	identityInformer := informer.NewInformerWithStore(
   113  		cache.NewListWatchFromClient(ciliumK8sClient.CiliumV2().RESTClient(),
   114  			"ciliumidentities", v1.NamespaceAll, fields.Everything()),
   115  		&v2.CiliumIdentity{},
   116  		0,
   117  		cache.ResourceEventHandlerFuncs{
   118  			UpdateFunc: func(oldObj, newObj interface{}) {
   119  				if identity, ok := newObj.(*types.Identity); ok {
   120  					handleIdentityUpdate(identity)
   121  				}
   122  			},
   123  		},
   124  		types.ConvertToIdentity,
   125  		identityStore,
   126  	)
   127  
   128  	go identityInformer.Run(wait.NeverStop)
   129  }