github.com/fafucoder/cilium@v1.6.11/pkg/clustermesh/services.go (about)

     1  // Copyright 2018 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 clustermesh
    16  
    17  import (
    18  	"github.com/cilium/cilium/pkg/kvstore/store"
    19  	"github.com/cilium/cilium/pkg/lock"
    20  	"github.com/cilium/cilium/pkg/logging/logfields"
    21  	"github.com/cilium/cilium/pkg/service"
    22  
    23  	"github.com/sirupsen/logrus"
    24  )
    25  
    26  // ServiceMerger is the interface to be implemented by the owner of local
    27  // services. The functions have to merge service updates and deletions with
    28  // local services to provide a shared view.
    29  type ServiceMerger interface {
    30  	MergeExternalServiceUpdate(service *service.ClusterService)
    31  	MergeExternalServiceDelete(service *service.ClusterService)
    32  }
    33  
    34  type globalService struct {
    35  	clusterServices map[string]*service.ClusterService
    36  }
    37  
    38  func newGlobalService() *globalService {
    39  	return &globalService{
    40  		clusterServices: map[string]*service.ClusterService{},
    41  	}
    42  }
    43  
    44  type globalServiceCache struct {
    45  	mutex  lock.RWMutex
    46  	byName map[string]*globalService
    47  }
    48  
    49  func newGlobalServiceCache() *globalServiceCache {
    50  	return &globalServiceCache{
    51  		byName: map[string]*globalService{},
    52  	}
    53  }
    54  
    55  func (c *globalServiceCache) onUpdate(svc *service.ClusterService) {
    56  	c.mutex.Lock()
    57  
    58  	scopedLog := log.WithFields(logrus.Fields{
    59  		logfields.ServiceName: svc.String(),
    60  		logfields.ClusterName: svc.Cluster,
    61  	})
    62  
    63  	// Validate that the global service is known
    64  	globalSvc, ok := c.byName[svc.NamespaceServiceName()]
    65  	if !ok {
    66  		globalSvc = newGlobalService()
    67  		c.byName[svc.NamespaceServiceName()] = globalSvc
    68  		scopedLog.Debugf("Created global service %s", svc.NamespaceServiceName())
    69  	}
    70  
    71  	scopedLog.Debugf("Updated service definition of remote cluster %#v", svc)
    72  
    73  	globalSvc.clusterServices[svc.Cluster] = svc
    74  	c.mutex.Unlock()
    75  }
    76  
    77  // must be called with c.mutex held
    78  func (c *globalServiceCache) delete(globalService *globalService, clusterName, serviceName string) {
    79  	scopedLog := log.WithFields(logrus.Fields{
    80  		logfields.ServiceName: serviceName,
    81  		logfields.ClusterName: clusterName,
    82  	})
    83  
    84  	if _, ok := globalService.clusterServices[clusterName]; !ok {
    85  		scopedLog.Debug("Ignoring delete request for unknown cluster")
    86  		return
    87  	}
    88  
    89  	scopedLog.Debugf("Deleted service definition of remote cluster")
    90  	delete(globalService.clusterServices, clusterName)
    91  
    92  	// After the last cluster service is removed, remove the
    93  	// global service
    94  	if len(globalService.clusterServices) == 0 {
    95  		scopedLog.Debugf("Deleted global service %s", serviceName)
    96  		delete(c.byName, serviceName)
    97  	}
    98  }
    99  
   100  func (c *globalServiceCache) onDelete(svc *service.ClusterService) {
   101  	scopedLog := log.WithFields(logrus.Fields{logfields.ServiceName: svc.String()})
   102  	scopedLog.Debug("Delete event for service")
   103  
   104  	c.mutex.Lock()
   105  	if globalService, ok := c.byName[svc.NamespaceServiceName()]; ok {
   106  		c.delete(globalService, svc.NamespaceServiceName(), svc.Cluster)
   107  	} else {
   108  		scopedLog.Debugf("Ignoring delete request for unknown global service")
   109  	}
   110  	c.mutex.Unlock()
   111  }
   112  
   113  func (c *globalServiceCache) onClusterDelete(clusterName string) {
   114  	scopedLog := log.WithFields(logrus.Fields{logfields.ClusterName: clusterName})
   115  	scopedLog.Debugf("Cluster deletion event")
   116  
   117  	c.mutex.Lock()
   118  	for serviceName, globalService := range c.byName {
   119  		c.delete(globalService, serviceName, clusterName)
   120  	}
   121  	c.mutex.Unlock()
   122  }
   123  
   124  type remoteServiceObserver struct {
   125  	remoteCluster *remoteCluster
   126  }
   127  
   128  // OnUpdate is called when a service in a remote cluster is updated
   129  func (r *remoteServiceObserver) OnUpdate(key store.Key) {
   130  	if svc, ok := key.(*service.ClusterService); ok {
   131  		scopedLog := log.WithFields(logrus.Fields{logfields.ServiceName: svc.String()})
   132  		scopedLog.Debugf("Update event of remote service %#v", svc)
   133  
   134  		mesh := r.remoteCluster.mesh
   135  		mesh.globalServices.onUpdate(svc)
   136  
   137  		if merger := mesh.conf.ServiceMerger; merger != nil {
   138  			merger.MergeExternalServiceUpdate(svc)
   139  		} else {
   140  			scopedLog.Debugf("Ignoring remote service update. Missing merger function")
   141  		}
   142  	} else {
   143  		log.Warningf("Received unexpected remote service update object %+v", key)
   144  	}
   145  }
   146  
   147  // OnDelete is called when a service in a remote cluster is deleted
   148  func (r *remoteServiceObserver) OnDelete(key store.NamedKey) {
   149  	if svc, ok := key.(*service.ClusterService); ok {
   150  		scopedLog := log.WithFields(logrus.Fields{logfields.ServiceName: svc.String()})
   151  		scopedLog.Debugf("Update event of remote service %#v", svc)
   152  
   153  		mesh := r.remoteCluster.mesh
   154  		mesh.globalServices.onDelete(svc)
   155  
   156  		if merger := mesh.conf.ServiceMerger; merger != nil {
   157  			merger.MergeExternalServiceDelete(svc)
   158  		} else {
   159  			scopedLog.Debugf("Ignoring remote service update. Missing merger function")
   160  		}
   161  	} else {
   162  		log.Warningf("Received unexpected remote service delete object %+v", key)
   163  	}
   164  }