// OnEndpointsUpdate takes in a slice of updated endpoints. func (proxier *Proxier) OnEndpointsUpdate(allEndpoints []api.Endpoints) { proxier.mu.Lock() defer proxier.mu.Unlock() proxier.haveReceivedEndpointsUpdate = true registeredEndpoints := make(map[proxy.ServicePortName]bool) // use a map as a set // Update endpoints for services. for i := range allEndpoints { svcEndpoints := &allEndpoints[i] // We need to build a map of portname -> all ip:ports for that // portname. Explode Endpoints.Subsets[*] into this structure. portsToEndpoints := map[string][]hostPortPair{} for i := range svcEndpoints.Subsets { ss := &svcEndpoints.Subsets[i] for i := range ss.Ports { port := &ss.Ports[i] for i := range ss.Addresses { addr := &ss.Addresses[i] portsToEndpoints[port.Name] = append(portsToEndpoints[port.Name], hostPortPair{addr.IP, port.Port}) } } } for portname := range portsToEndpoints { svcPort := proxy.ServicePortName{NamespacedName: types.NamespacedName{Namespace: svcEndpoints.Namespace, Name: svcEndpoints.Name}, Port: portname} state, exists := proxier.serviceMap[svcPort] if !exists || state == nil { state = newServiceInfo(svcPort) proxier.serviceMap[svcPort] = state } curEndpoints := []string{} if state != nil { curEndpoints = state.endpoints } newEndpoints := flattenValidEndpoints(portsToEndpoints[portname]) if len(curEndpoints) != len(newEndpoints) || !slicesEquiv(slice.CopyStrings(curEndpoints), newEndpoints) { glog.V(1).Infof("Setting endpoints for %s to %+v", svcPort, newEndpoints) state.endpoints = newEndpoints } registeredEndpoints[svcPort] = true } } // Remove endpoints missing from the update. for service, info := range proxier.serviceMap { // if missing from update and not already set by previous endpoints event if _, exists := registeredEndpoints[service]; !exists && info.endpoints != nil { glog.V(2).Infof("Removing endpoints for %s", service) // Set the endpoints to nil, we will check for this in OnServiceUpdate so that we // only remove ServicePorts that have no endpoints and were not in the service update, // that way we only remove ServicePorts that were not in both. proxier.serviceMap[service].endpoints = nil } } proxier.syncProxyRules() }
// OnEndpointsUpdate takes in a slice of updated endpoints. func (proxier *Proxier) OnEndpointsUpdate(allEndpoints []api.Endpoints) { start := time.Now() defer func() { glog.V(4).Infof("OnEndpointsUpdate took %v for %d endpoints", time.Since(start), len(allEndpoints)) }() proxier.mu.Lock() defer proxier.mu.Unlock() proxier.haveReceivedEndpointsUpdate = true activeEndpoints := make(map[proxy.ServicePortName]bool) // use a map as a set // Update endpoints for services. for i := range allEndpoints { svcEndpoints := &allEndpoints[i] // We need to build a map of portname -> all ip:ports for that // portname. Explode Endpoints.Subsets[*] into this structure. portsToEndpoints := map[string][]hostPortPair{} for i := range svcEndpoints.Subsets { ss := &svcEndpoints.Subsets[i] for i := range ss.Ports { port := &ss.Ports[i] for i := range ss.Addresses { addr := &ss.Addresses[i] portsToEndpoints[port.Name] = append(portsToEndpoints[port.Name], hostPortPair{addr.IP, port.Port}) } } } for portname := range portsToEndpoints { svcPort := proxy.ServicePortName{NamespacedName: types.NamespacedName{Namespace: svcEndpoints.Namespace, Name: svcEndpoints.Name}, Port: portname} curEndpoints := proxier.endpointsMap[svcPort] newEndpoints := flattenValidEndpoints(portsToEndpoints[portname]) if len(curEndpoints) != len(newEndpoints) || !slicesEquiv(slice.CopyStrings(curEndpoints), newEndpoints) { glog.V(1).Infof("Setting endpoints for %q to %+v", svcPort, newEndpoints) proxier.endpointsMap[svcPort] = newEndpoints } activeEndpoints[svcPort] = true } } // Remove endpoints missing from the update. for name := range proxier.endpointsMap { if !activeEndpoints[name] { glog.V(2).Infof("Removing endpoints for %q", name) delete(proxier.endpointsMap, name) } } proxier.syncProxyRules() }
// OnEndpointsUpdate manages the registered service endpoints. // Registered endpoints are updated if found in the update set or // unregistered if missing from the update set. func (lb *LoadBalancerRR) OnEndpointsUpdate(allEndpoints []api.Endpoints) { registeredEndpoints := make(map[proxy.ServicePortName]bool) lb.lock.Lock() defer lb.lock.Unlock() // Update endpoints for services. for i := range allEndpoints { svcEndpoints := &allEndpoints[i] // We need to build a map of portname -> all ip:ports for that // portname. Explode Endpoints.Subsets[*] into this structure. portsToEndpoints := map[string][]hostPortPair{} for i := range svcEndpoints.Subsets { ss := &svcEndpoints.Subsets[i] for i := range ss.Ports { port := &ss.Ports[i] for i := range ss.Addresses { addr := &ss.Addresses[i] portsToEndpoints[port.Name] = append(portsToEndpoints[port.Name], hostPortPair{addr.IP, int(port.Port)}) // Ignore the protocol field - we'll get that from the Service objects. } } } for portname := range portsToEndpoints { svcPort := proxy.ServicePortName{NamespacedName: types.NamespacedName{Namespace: svcEndpoints.Namespace, Name: svcEndpoints.Name}, Port: portname} state, exists := lb.services[svcPort] curEndpoints := []string{} if state != nil { curEndpoints = state.endpoints } newEndpoints := flattenValidEndpoints(portsToEndpoints[portname]) if !exists || state == nil || len(curEndpoints) != len(newEndpoints) || !slicesEquiv(slice.CopyStrings(curEndpoints), newEndpoints) { glog.V(1).Infof("LoadBalancerRR: Setting endpoints for %s to %+v", svcPort, newEndpoints) lb.updateAffinityMap(svcPort, newEndpoints) // OnEndpointsUpdate can be called without NewService being called externally. // To be safe we will call it here. A new service will only be created // if one does not already exist. The affinity will be updated // later, once NewService is called. state = lb.newServiceInternal(svcPort, api.ServiceAffinity(""), 0) state.endpoints = slice.ShuffleStrings(newEndpoints) // Reset the round-robin index. state.index = 0 } registeredEndpoints[svcPort] = true } } // Remove endpoints missing from the update. for k := range lb.services { if _, exists := registeredEndpoints[k]; !exists { glog.V(2).Infof("LoadBalancerRR: Removing endpoints for %s", k) // Reset but don't delete. state := lb.services[k] state.endpoints = []string{} state.index = 0 state.affinity.affinityMap = map[string]*affinityState{} } } }
// OnEndpointsUpdate takes in a slice of updated endpoints. func (proxier *Proxier) OnEndpointsUpdate(allEndpoints []api.Endpoints) { start := time.Now() defer func() { glog.V(4).Infof("OnEndpointsUpdate took %v for %d endpoints", time.Since(start), len(allEndpoints)) }() proxier.mu.Lock() defer proxier.mu.Unlock() proxier.haveReceivedEndpointsUpdate = true activeEndpoints := make(map[proxy.ServicePortName]bool) // use a map as a set staleConnections := make(map[endpointServicePair]bool) svcPortToInfoMap := make(map[proxy.ServicePortName][]hostPortInfo) // Update endpoints for services. for i := range allEndpoints { svcEndpoints := &allEndpoints[i] // We need to build a map of portname -> all ip:ports for that // portname. Explode Endpoints.Subsets[*] into this structure. portsToEndpoints := map[string][]hostPortInfo{} for i := range svcEndpoints.Subsets { ss := &svcEndpoints.Subsets[i] for i := range ss.Ports { port := &ss.Ports[i] for i := range ss.Addresses { addr := &ss.Addresses[i] var isLocalEndpoint bool if addr.NodeName != nil { isLocalEndpoint = *addr.NodeName == proxier.hostname isLocalEndpoint = featuregate.DefaultFeatureGate.ExternalTrafficLocalOnly() && isLocalEndpoint } hostPortObject := hostPortInfo{ host: addr.IP, port: int(port.Port), localEndpoint: isLocalEndpoint, } portsToEndpoints[port.Name] = append(portsToEndpoints[port.Name], hostPortObject) } } } for portname := range portsToEndpoints { svcPort := proxy.ServicePortName{NamespacedName: types.NamespacedName{Namespace: svcEndpoints.Namespace, Name: svcEndpoints.Name}, Port: portname} svcPortToInfoMap[svcPort] = portsToEndpoints[portname] curEndpoints := proxier.endpointsMap[svcPort] newEndpoints := flattenValidEndpoints(portsToEndpoints[portname]) // Flatten the list of current endpoint infos to just a list of ips as strings curEndpointIPs := flattenEndpointsInfo(curEndpoints) if len(curEndpointIPs) != len(newEndpoints) || !slicesEquiv(slice.CopyStrings(curEndpointIPs), newEndpoints) { removedEndpoints := getRemovedEndpoints(curEndpointIPs, newEndpoints) for _, ep := range removedEndpoints { staleConnections[endpointServicePair{endpoint: ep, servicePortName: svcPort}] = true } glog.V(3).Infof("Setting endpoints for %q to %+v", svcPort, newEndpoints) // Once the set operations using the list of ips are complete, build the list of endpoint infos proxier.endpointsMap[svcPort] = proxier.buildEndpointInfoList(portsToEndpoints[portname], newEndpoints) } activeEndpoints[svcPort] = true } } // Remove endpoints missing from the update. for svcPort := range proxier.endpointsMap { if !activeEndpoints[svcPort] { // record endpoints of unactive service to stale connections for _, ep := range proxier.endpointsMap[svcPort] { staleConnections[endpointServicePair{endpoint: ep.ip, servicePortName: svcPort}] = true } glog.V(2).Infof("Removing endpoints for %q", svcPort) delete(proxier.endpointsMap, svcPort) } proxier.updateHealthCheckEntries(svcPort.NamespacedName, svcPortToInfoMap[svcPort]) } proxier.syncProxyRules() proxier.deleteEndpointConnections(staleConnections) }