// 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. 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) } } }
func convert_v1beta3_ServiceSpec_To_api_ServiceSpec(in *ServiceSpec, out *api.ServiceSpec, s conversion.Scope) error { if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found { defaulting.(func(*ServiceSpec))(in) } if in.Ports != nil { out.Ports = make([]api.ServicePort, len(in.Ports)) for i := range in.Ports { if err := convert_v1beta3_ServicePort_To_api_ServicePort(&in.Ports[i], &out.Ports[i], s); err != nil { return err } } } else { out.Ports = nil } if in.Selector != nil { out.Selector = make(map[string]string) for key, val := range in.Selector { out.Selector[key] = val } } else { out.Selector = nil } out.ClusterIP = in.PortalIP typeIn := in.Type if typeIn == "" { if in.CreateExternalLoadBalancer { typeIn = ServiceTypeLoadBalancer } else { typeIn = ServiceTypeClusterIP } } if err := s.Convert(&typeIn, &out.Type, 0); err != nil { return err } if in.PublicIPs != nil { out.DeprecatedPublicIPs = make([]string, len(in.PublicIPs)) for i := range in.PublicIPs { out.DeprecatedPublicIPs[i] = in.PublicIPs[i] } } else { out.DeprecatedPublicIPs = nil } out.SessionAffinity = api.ServiceAffinity(in.SessionAffinity) return nil }