github.com/looshlee/beatles@v0.0.0-20220727174639-742810ab631c/pkg/identity/identitymanager/manager.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 identitymanager
    16  
    17  import (
    18  	"github.com/cilium/cilium/api/v1/models"
    19  	"github.com/cilium/cilium/pkg/identity"
    20  	"github.com/cilium/cilium/pkg/lock"
    21  	"github.com/cilium/cilium/pkg/logging/logfields"
    22  
    23  	"github.com/sirupsen/logrus"
    24  )
    25  
    26  var (
    27  	// GlobalIdentityManager is a singleton instance of an IdentityManager, used
    28  	// for easy updating / tracking lifecycles of identities on the local node
    29  	// without having to pass around a specific instance of an IdentityManager
    30  	// throughout Cilium.
    31  	GlobalIdentityManager = NewIdentityManager()
    32  )
    33  
    34  // IdentityManager caches information about a set of identities, currently a
    35  // reference count of how many users there are for each identity.
    36  type IdentityManager struct {
    37  	mutex      lock.RWMutex
    38  	identities map[identity.NumericIdentity]*identityMetadata
    39  	observers  map[Observer]struct{}
    40  }
    41  
    42  type identityMetadata struct {
    43  	identity *identity.Identity
    44  	refCount uint
    45  }
    46  
    47  // NewIdentityManager returns an initialized IdentityManager.
    48  func NewIdentityManager() *IdentityManager {
    49  	return &IdentityManager{
    50  		identities: make(map[identity.NumericIdentity]*identityMetadata),
    51  		observers:  make(map[Observer]struct{}),
    52  	}
    53  }
    54  
    55  // Add inserts the identity into the GlobalIdentityManager.
    56  func Add(identity *identity.Identity) {
    57  	GlobalIdentityManager.Add(identity)
    58  }
    59  
    60  // Remove deletes the identity from the GlobalIdentityManager.
    61  func Remove(identity *identity.Identity) {
    62  	GlobalIdentityManager.Remove(identity)
    63  }
    64  
    65  // Add inserts the identity into the identity manager. If the identity is
    66  // already in the identity manager, the reference count for the identity is
    67  // incremented.
    68  func (idm *IdentityManager) Add(identity *identity.Identity) {
    69  	log.WithFields(logrus.Fields{
    70  		logfields.Identity: identity,
    71  	}).Debug("Adding identity to the identity manager")
    72  
    73  	idm.mutex.Lock()
    74  	defer idm.mutex.Unlock()
    75  	idm.add(identity)
    76  }
    77  
    78  func (idm *IdentityManager) add(identity *identity.Identity) {
    79  
    80  	if identity == nil {
    81  		return
    82  	}
    83  
    84  	idMeta, exists := idm.identities[identity.ID]
    85  	if !exists {
    86  		idm.identities[identity.ID] = &identityMetadata{
    87  			identity: identity,
    88  			refCount: 1,
    89  		}
    90  		for o := range idm.observers {
    91  			o.LocalEndpointIdentityAdded(identity)
    92  		}
    93  	} else {
    94  		idMeta.refCount++
    95  	}
    96  }
    97  
    98  // RemoveOldAddNew removes old from the identity manager and inserts new
    99  // into the IdentityManager.
   100  // Caller must have previously added the old identity with Add().
   101  // This is a no-op if both identities have the same numeric ID.
   102  func (idm *IdentityManager) RemoveOldAddNew(old, new *identity.Identity) {
   103  	idm.mutex.Lock()
   104  	defer idm.mutex.Unlock()
   105  
   106  	if old == nil && new == nil {
   107  		return
   108  	}
   109  	if old != nil && new != nil && old.ID == new.ID {
   110  		return
   111  	}
   112  
   113  	log.WithFields(logrus.Fields{
   114  		"old": old,
   115  		"new": new,
   116  	}).Debug("removing old and adding new identity")
   117  
   118  	idm.remove(old)
   119  	idm.add(new)
   120  }
   121  
   122  // RemoveOldAddNew removes old from and inserts new into the
   123  // GlobalIdentityManager.
   124  func RemoveOldAddNew(old, new *identity.Identity) {
   125  	GlobalIdentityManager.RemoveOldAddNew(old, new)
   126  }
   127  
   128  // Remove deletes the identity from the identity manager. If the identity is
   129  // already in the identity manager, the reference count for the identity is
   130  // decremented. If the identity is not in the cache, this is a no-op. If the
   131  // ref count becomes zero, the identity is removed from the cache.
   132  func (idm *IdentityManager) Remove(identity *identity.Identity) {
   133  	log.WithFields(logrus.Fields{
   134  		logfields.Identity: identity,
   135  	}).Debug("Removing identity from the identity manager")
   136  
   137  	idm.mutex.Lock()
   138  	defer idm.mutex.Unlock()
   139  	idm.remove(identity)
   140  }
   141  
   142  func (idm *IdentityManager) remove(identity *identity.Identity) {
   143  
   144  	if identity == nil {
   145  		return
   146  	}
   147  
   148  	idMeta, exists := idm.identities[identity.ID]
   149  	if !exists {
   150  		log.WithFields(logrus.Fields{
   151  			logfields.Identity: identity,
   152  		}).Error("removing identity not added to the identity manager!")
   153  		return
   154  	}
   155  	idMeta.refCount--
   156  	if idMeta.refCount == 0 {
   157  		delete(idm.identities, identity.ID)
   158  		for o := range idm.observers {
   159  			o.LocalEndpointIdentityRemoved(identity)
   160  		}
   161  	}
   162  
   163  }
   164  
   165  // GetIdentityModels returns the API representation of the IdentityManager.
   166  func (idm *IdentityManager) GetIdentityModels() []*models.IdentityEndpoints {
   167  	idm.mutex.RLock()
   168  	defer idm.mutex.RUnlock()
   169  
   170  	identities := make([]*models.IdentityEndpoints, 0, len(idm.identities))
   171  
   172  	for _, v := range idm.identities {
   173  		identities = append(identities, &models.IdentityEndpoints{
   174  			Identity: v.identity.GetModel(),
   175  			RefCount: int64(v.refCount),
   176  		})
   177  	}
   178  
   179  	return identities
   180  }
   181  
   182  func (idm *IdentityManager) subscribe(o Observer) {
   183  	idm.mutex.Lock()
   184  	defer idm.mutex.Unlock()
   185  	idm.observers[o] = struct{}{}
   186  }
   187  
   188  // GetIdentityModels returns the API model of all identities in the
   189  // GlobalIdentityManager.
   190  func GetIdentityModels() []*models.IdentityEndpoints {
   191  	return GlobalIdentityManager.GetIdentityModels()
   192  }
   193  
   194  // IdentitiesModel is a wrapper so that we can implement the sort.Interface
   195  // to sort the slice by ID
   196  type IdentitiesModel []*models.IdentityEndpoints
   197  
   198  // Less returns true if the element in index `i` is lower than the element
   199  // in index `j`
   200  func (s IdentitiesModel) Less(i, j int) bool {
   201  	return s[i].Identity.ID < s[j].Identity.ID
   202  }
   203  
   204  // Subscribe adds the specified Observer to the global identity manager, to be
   205  // notified upon changes to local identity usage.
   206  func Subscribe(o Observer) {
   207  	GlobalIdentityManager.subscribe(o)
   208  }