// OnUpdate 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) OnUpdate(allEndpoints []api.Endpoints) {
	registeredEndpoints := make(map[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 := ServicePortName{types.NamespacedName{svcEndpoints.Namespace, svcEndpoints.Name}, 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)
				// OnUpdate 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.
				state = lb.newServiceInternal(svcPort, api.AffinityTypeNone, 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)
		}
	}
}
Example #2
0
// OnUpdate 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) OnUpdate(allEndpoints []api.Endpoints) {
	registeredEndpoints := make(map[types.NamespacedName]bool)
	lb.lock.Lock()
	defer lb.lock.Unlock()

	// Update endpoints for services.
	for _, svcEndpoints := range allEndpoints {
		name := types.NamespacedName{svcEndpoints.Namespace, svcEndpoints.Name}
		key := name
		state, exists := lb.services[key]
		curEndpoints := []string{}
		if state != nil {
			curEndpoints = state.endpoints
		}
		newEndpoints := filterValidEndpoints(svcEndpoints.Endpoints)
		if !exists || state == nil || len(curEndpoints) != len(newEndpoints) || !slicesEquiv(slice.CopyStrings(curEndpoints), newEndpoints) {
			glog.V(3).Infof("LoadBalancerRR: Setting endpoints for %s to %+v", svcEndpoints.Name, svcEndpoints.Endpoints)
			lb.updateAffinityMap(key, newEndpoints)
			// On update 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.
			state = lb.newServiceInternal(name, api.AffinityTypeNone, 0)
			state.endpoints = slice.ShuffleStrings(newEndpoints)

			// Reset the round-robin index.
			state.index = 0
		}
		registeredEndpoints[key] = true
	}
	// Remove endpoints missing from the update.
	for k := range lb.services {
		if _, exists := registeredEndpoints[k]; !exists {
			glog.V(3).Infof("LoadBalancerRR: Removing endpoints for %s", k)
			delete(lb.services, k)
		}
	}
}