// 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) } } }
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 }
func (testServiceGenerator) Generate(genericParams map[string]interface{}) (runtime.Object, error) { params := map[string]string{} for key, value := range genericParams { strVal, isString := value.(string) if !isString { return nil, fmt.Errorf("expected string, saw %v for '%s'", value, key) } params[key] = strVal } labelsString, found := params["labels"] var labels map[string]string var err error if found && len(labelsString) > 0 { labels, err = kubectl.ParseLabels(labelsString) if err != nil { return nil, err } } name, found := params["name"] if !found || len(name) == 0 { name, found = params["default-name"] if !found || len(name) == 0 { return nil, fmt.Errorf("'name' is a required parameter.") } } portString, found := params["port"] if !found { return nil, fmt.Errorf("'port' is a required parameter.") } port, err := strconv.Atoi(portString) if err != nil { return nil, err } servicePortName, found := params["port-name"] if !found { // Leave the port unnamed. servicePortName = "" } service := api.Service{ ObjectMeta: api.ObjectMeta{ Name: name, Labels: labels, }, Spec: api.ServiceSpec{ Ports: []api.ServicePort{ { Name: servicePortName, Port: port, Protocol: api.Protocol(params["protocol"]), }, }, }, } targetPort, found := params["target-port"] if !found { targetPort, found = params["container-port"] } if found && len(targetPort) > 0 { if portNum, err := strconv.Atoi(targetPort); err != nil { service.Spec.Ports[0].TargetPort = util.NewIntOrStringFromString(targetPort) } else { service.Spec.Ports[0].TargetPort = util.NewIntOrStringFromInt(portNum) } } else { service.Spec.Ports[0].TargetPort = util.NewIntOrStringFromInt(port) } if params["create-external-load-balancer"] == "true" { service.Spec.Type = api.ServiceTypeLoadBalancer } if len(params["external-ip"]) > 0 { service.Spec.ExternalIPs = []string{params["external-ip"]} } if len(params["type"]) != 0 { service.Spec.Type = api.ServiceType(params["type"]) } if len(params["session-affinity"]) != 0 { switch api.ServiceAffinity(params["session-affinity"]) { case api.ServiceAffinityNone: service.Spec.SessionAffinity = api.ServiceAffinityNone case api.ServiceAffinityClientIP: service.Spec.SessionAffinity = api.ServiceAffinityClientIP default: return nil, fmt.Errorf("unknown session affinity: %s", params["session-affinity"]) } } return &service, nil }
func generate(genericParams map[string]interface{}) (runtime.Object, error) { params := map[string]string{} for key, value := range genericParams { strVal, isString := value.(string) if !isString { return nil, fmt.Errorf("expected string, saw %v for '%s'", value, key) } params[key] = strVal } selectorString, found := params["selector"] if !found || len(selectorString) == 0 { return nil, fmt.Errorf("'selector' is a required parameter.") } selector, err := ParseLabels(selectorString) if err != nil { return nil, err } labelsString, found := params["labels"] var labels map[string]string if found && len(labelsString) > 0 { labels, err = ParseLabels(labelsString) if err != nil { return nil, err } } name, found := params["name"] if !found || len(name) == 0 { name, found = params["default-name"] if !found || len(name) == 0 { return nil, fmt.Errorf("'name' is a required parameter.") } } ports := []api.ServicePort{} servicePortName, found := params["port-name"] if !found { // Leave the port unnamed. servicePortName = "" } // ports takes precedence over port since it will be // specified only when the user hasn't specified a port // via --port and the exposed object has multiple ports. var portString string if portString, found = params["ports"]; !found { portString, found = params["port"] if !found { return nil, fmt.Errorf("'port' is a required parameter.") } } portStringSlice := strings.Split(portString, ",") for i, stillPortString := range portStringSlice { port, err := strconv.Atoi(stillPortString) if err != nil { return nil, err } name := servicePortName // If we are going to assign multiple ports to a service, we need to // generate a different name for each one. if len(portStringSlice) > 1 { name = fmt.Sprintf("port-%d", i+1) } ports = append(ports, api.ServicePort{ Name: name, Port: port, Protocol: api.Protocol(params["protocol"]), }) } service := api.Service{ ObjectMeta: api.ObjectMeta{ Name: name, Labels: labels, }, Spec: api.ServiceSpec{ Selector: selector, Ports: ports, }, } targetPortString, found := params["target-port"] if !found { targetPortString, found = params["container-port"] } if found && len(targetPortString) > 0 { var targetPort util.IntOrString if portNum, err := strconv.Atoi(targetPortString); err != nil { targetPort = util.NewIntOrStringFromString(targetPortString) } else { targetPort = util.NewIntOrStringFromInt(portNum) } // Use the same target-port for every port for i := range service.Spec.Ports { service.Spec.Ports[i].TargetPort = targetPort } } else { // If --target-port or --container-port haven't been specified, this // should be the same as Port for i := range service.Spec.Ports { port := service.Spec.Ports[i].Port service.Spec.Ports[i].TargetPort = util.NewIntOrStringFromInt(port) } } if params["create-external-load-balancer"] == "true" { service.Spec.Type = api.ServiceTypeLoadBalancer } if len(params["external-ip"]) > 0 { service.Spec.ExternalIPs = []string{params["external-ip"]} } if len(params["type"]) != 0 { service.Spec.Type = api.ServiceType(params["type"]) } if service.Spec.Type == api.ServiceTypeLoadBalancer { service.Spec.LoadBalancerIP = params["load-balancer-ip"] } if len(params["session-affinity"]) != 0 { switch api.ServiceAffinity(params["session-affinity"]) { case api.ServiceAffinityNone: service.Spec.SessionAffinity = api.ServiceAffinityNone case api.ServiceAffinityClientIP: service.Spec.SessionAffinity = api.ServiceAffinityClientIP default: return nil, fmt.Errorf("unknown session affinity: %s", params["session-affinity"]) } } return &service, nil }