func sameConfig(info *serviceInfo, service *api.Service, port *api.ServicePort) bool { if info.protocol != port.Protocol || info.portalPort != port.Port || info.nodePort != port.NodePort { return false } if !info.portalIP.Equal(net.ParseIP(service.Spec.PortalIP)) { return false } if !ipsEqual(info.deprecatedPublicIPs, service.Spec.DeprecatedPublicIPs) { return false } if !api.LoadBalancerStatusEqual(&info.loadBalancerStatus, &service.Status.LoadBalancer) { return false } if info.sessionAffinityType != service.Spec.SessionAffinity { return false } return true }
// Returns whatever error occurred along with a boolean indicator of whether it // should be retried. func (s *ServiceController) createLoadBalancerIfNeeded(namespacedName types.NamespacedName, service, cachedService *api.Service) (error, bool) { if cachedService != nil && !needsUpdate(cachedService, service) { glog.Infof("LB already exists and doesn't need update for service %s", namespacedName) return nil, notRetryable } if cachedService != nil { // If the service already exists but needs to be updated, delete it so that // we can recreate it cleanly. if wantsExternalLoadBalancer(cachedService) { glog.Infof("Deleting existing load balancer for service %s that needs an updated load balancer.", namespacedName) if err := s.balancer.EnsureTCPLoadBalancerDeleted(s.loadBalancerName(cachedService), s.zone.Region); err != nil { return err, retryable } } } else { // If we don't have any cached memory of the load balancer, we have to ask // the cloud provider for what it knows about it. status, exists, err := s.balancer.GetTCPLoadBalancer(s.loadBalancerName(service), s.zone.Region) if err != nil { return fmt.Errorf("Error getting LB for service %s: %v", namespacedName, err), retryable } if exists && api.LoadBalancerStatusEqual(status, &service.Status.LoadBalancer) { glog.Infof("LB already exists with status %s for previously uncached service %s", status, namespacedName) return nil, notRetryable } else if exists { glog.Infof("Deleting old LB for previously uncached service %s whose endpoint %s doesn't match the service's desired IPs %v", namespacedName, status, service.Spec.DeprecatedPublicIPs) if err := s.balancer.EnsureTCPLoadBalancerDeleted(s.loadBalancerName(service), s.zone.Region); err != nil { return err, retryable } } } // Save the state so we can avoid a write if it doesn't change previousState := api.LoadBalancerStatusDeepCopy(&service.Status.LoadBalancer) if !wantsExternalLoadBalancer(service) { glog.Infof("Not creating LB for service %s that doesn't want one.", namespacedName) service.Status.LoadBalancer = api.LoadBalancerStatus{} } else { glog.V(2).Infof("Creating LB for service %s", namespacedName) // The load balancer doesn't exist yet, so create it. err := s.createExternalLoadBalancer(service) if err != nil { return fmt.Errorf("failed to create external load balancer for service %s: %v", namespacedName, err), retryable } } // Write the state if changed // TODO: Be careful here ... what if there were other changes to the service? if !api.LoadBalancerStatusEqual(previousState, &service.Status.LoadBalancer) { if err := s.persistUpdate(service); err != nil { return fmt.Errorf("Failed to persist updated status to apiserver, even after retries. Giving up: %v", err), notRetryable } } else { glog.Infof("Not persisting unchanged LoadBalancerStatus to registry.") } return nil, notRetryable }