// 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 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, 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) delete(lb.services, k) } } }