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 }