func (cc *clusterClientCache) persistFedServiceUpdate(cachedService *cachedService, fedClient federation_release_1_3.Interface) error { service := cachedService.lastState glog.V(5).Infof("Persist federation service status %s/%s", service.Namespace, service.Name) var err error for i := 0; i < clientRetryCount; i++ { _, err := fedClient.Core().Services(service.Namespace).Get(service.Name) if errors.IsNotFound(err) { glog.Infof("Not persisting update to service '%s/%s' that no longer exists: %v", service.Namespace, service.Name, err) return nil } _, err = fedClient.Core().Services(service.Namespace).UpdateStatus(service) if err == nil { glog.V(2).Infof("Successfully update service %s/%s to federation apiserver", service.Namespace, service.Name) return nil } if errors.IsNotFound(err) { glog.Infof("Not persisting update to service '%s/%s' that no longer exists: %v", service.Namespace, service.Name, err) return nil } if errors.IsConflict(err) { glog.V(4).Infof("Not persisting update to service '%s/%s' that has been changed since we received it: %v", service.Namespace, service.Name, err) return err } time.Sleep(cachedService.nextFedUpdateDelay()) } return err }
// Whenever there is change on service, the federation service should be updated func (cc *clusterClientCache) syncService(key, clusterName string, clusterCache *clusterCache, serviceCache *serviceCache, fedClient federation_release_1_3.Interface, sc *ServiceController) error { // obj holds the latest service info from apiserver, return if there is no federation cache for the service cachedService, ok := serviceCache.get(key) if !ok { // if serviceCache does not exists, that means the service is not created by federation, we should skip it return nil } serviceInterface, exists, err := clusterCache.serviceStore.GetByKey(key) if err != nil { glog.Infof("Did not successfully get %v from store: %v, will retry later", key, err) clusterCache.serviceQueue.Add(key) return err } var needUpdate, isDeletion bool if exists { service, ok := serviceInterface.(*v1.Service) if ok { glog.V(4).Infof("Found service for federation service %s/%s from cluster %s", service.Namespace, service.Name, clusterName) needUpdate = cc.processServiceUpdate(cachedService, service, clusterName) } else { _, ok := serviceInterface.(cache.DeletedFinalStateUnknown) if !ok { return fmt.Errorf("Object contained wasn't a service or a deleted key: %+v", serviceInterface) } glog.Infof("Found tombstone for %v", key) needUpdate = cc.processServiceDeletion(cachedService, clusterName) isDeletion = true } } else { glog.Infof("Can not get service %v for cluster %s from serviceStore", key, clusterName) needUpdate = cc.processServiceDeletion(cachedService, clusterName) isDeletion = true } if needUpdate { for i := 0; i < clientRetryCount; i++ { err := sc.ensureDnsRecords(clusterName, cachedService) if err == nil { break } glog.V(4).Infof("Error ensuring DNS Records for service %s on cluster %s: %v", key, clusterName, err) time.Sleep(cachedService.nextDNSUpdateDelay()) clusterCache.serviceQueue.Add(key) // did not retry here as we still want to persist federation apiserver even ensure dns records fails } err := cc.persistFedServiceUpdate(cachedService, fedClient) if err == nil { cachedService.appliedState = cachedService.lastState cachedService.resetFedUpdateDelay() } else { if err != nil { glog.Errorf("Failed to sync service: %+v, put back to service queue", err) clusterCache.serviceQueue.Add(key) } } } if isDeletion { // cachedService is not reliable here as // deleting cache is the last step of federation service deletion _, err := fedClient.Core().Services(cachedService.lastState.Namespace).Get(cachedService.lastState.Name) // rebuild service if federation service still exists if err == nil || !errors.IsNotFound(err) { return sc.ensureClusterService(cachedService, clusterName, cachedService.appliedState, clusterCache.clientset) } } return nil }