// run loops forever looking for changes to endpoints. func (s *endpointsReflector) run(resourceVersion *string) { if len(*resourceVersion) == 0 { endpoints, err := s.watcher.List(labels.Everything()) if err != nil { glog.Errorf("Unable to load endpoints: %v", err) time.Sleep(wait.Jitter(s.waitDuration, 0.0)) return } *resourceVersion = endpoints.ResourceVersion s.endpoints <- EndpointsUpdate{Op: SET, Endpoints: endpoints.Items} } watcher, err := s.watcher.Watch(labels.Everything(), fields.Everything(), *resourceVersion) if err != nil { glog.Errorf("Unable to watch for endpoints changes: %v", err) if !client.IsTimeout(err) { // Reset so that we do a fresh get request *resourceVersion = "" } time.Sleep(wait.Jitter(s.waitDuration, 0.0)) return } defer watcher.Stop() ch := watcher.ResultChan() s.watchHandler(resourceVersion, ch, s.endpoints) }
// run loops forever looking for changes to services. func (s *servicesReflector) run(resourceVersion *string) { if len(*resourceVersion) == 0 { services, err := s.watcher.List(labels.Everything()) if err != nil { glog.Errorf("Unable to load services: %v", err) // TODO: reconcile with pkg/client/cache which doesn't use reflector. time.Sleep(wait.Jitter(s.waitDuration, 0.0)) return } *resourceVersion = services.ResourceVersion // TODO: replace with code to update the s.services <- ServiceUpdate{Op: SET, Services: services.Items} } watcher, err := s.watcher.Watch(labels.Everything(), fields.Everything(), *resourceVersion) if err != nil { glog.Errorf("Unable to watch for services changes: %v", err) if !client.IsTimeout(err) { // Reset so that we do a fresh get request *resourceVersion = "" } time.Sleep(wait.Jitter(s.waitDuration, 0.0)) return } defer watcher.Stop() ch := watcher.ResultChan() s.watchHandler(resourceVersion, ch, s.services) }
// secretDeleted reacts to a Secret being deleted by removing a reference from the corresponding ServiceAccount if needed func (e *TokensController) secretDeleted(obj interface{}) { secret, ok := obj.(*api.Secret) if !ok { // Unknown type. If we missed a Secret deletion, the corresponding ServiceAccount (if it exists) // will get a secret recreated (if needed) during the ServiceAccount re-list return } serviceAccount, err := e.getServiceAccount(secret, false) if err != nil { glog.Error(err) return } if serviceAccount == nil { return } for i := 1; i <= NumServiceAccountRemoveReferenceRetries; i++ { if _, err := e.removeSecretReferenceIfNeeded(serviceAccount, secret.Name); err != nil { if apierrors.IsConflict(err) && i < NumServiceAccountRemoveReferenceRetries { time.Sleep(wait.Jitter(100*time.Millisecond, 0.0)) continue } glog.Error(err) break } break } }
// secretDeleted reacts to a Secret being deleted by looking to see if it's a dockercfg secret for a service account, in which case it // it removes the references from the service account and removes the token created to back the dockercfgSecret func (e *DockercfgDeletedController) secretDeleted(obj interface{}) { dockercfgSecret, ok := obj.(*api.Secret) if !ok { return } if _, exists := dockercfgSecret.Annotations[ServiceAccountTokenSecretNameKey]; !exists { return } for i := 1; i <= NumServiceAccountUpdateRetries; i++ { if err := e.removeDockercfgSecretReference(dockercfgSecret); err != nil { if kapierrors.IsConflict(err) && i < NumServiceAccountUpdateRetries { time.Sleep(wait.Jitter(100*time.Millisecond, 0.0)) continue } glog.Error(err) break } break } // remove the reference token secret if err := e.client.Secrets(dockercfgSecret.Namespace).Delete(dockercfgSecret.Annotations[ServiceAccountTokenSecretNameKey]); (err != nil) && !kapierrors.IsNotFound(err) { util.HandleError(err) } }
// runServices loops forever looking for changes to services func (s *SourceAPI) runServices(resourceVersion *uint64) { watcher, err := s.client.WatchServices(labels.Everything(), labels.Everything(), *resourceVersion) if err != nil { glog.Errorf("Unable to watch for services changes: %v", err) time.Sleep(wait.Jitter(s.waitDuration, 0.0)) return } defer watcher.Stop() ch := watcher.ResultChan() handleServicesWatch(resourceVersion, ch, s.services) }
// NewSourceAPI creates a config source that watches for changes to the services and endpoints func NewSourceAPI(client Watcher, period time.Duration, services chan<- ServiceUpdate, endpoints chan<- EndpointsUpdate) *SourceAPI { config := &SourceAPI{ client: client, services: services, endpoints: endpoints, waitDuration: period, // prevent hot loops if the server starts to misbehave reconnectDuration: time.Second * 1, } serviceVersion := uint64(0) go util.Forever(func() { config.runServices(&serviceVersion) time.Sleep(wait.Jitter(config.reconnectDuration, 0.0)) }, period) endpointVersion := uint64(0) go util.Forever(func() { config.runEndpoints(&endpointVersion) time.Sleep(wait.Jitter(config.reconnectDuration, 0.0)) }, period) return config }
// runServices loops forever looking for changes to services. func (s *SourceAPI) runServices(resourceVersion *uint64) { if *resourceVersion == 0 { services, err := s.client.ListServices(labels.Everything()) if err != nil { glog.Errorf("Unable to load services: %v", err) time.Sleep(wait.Jitter(s.waitDuration, 0.0)) return } *resourceVersion = services.ResourceVersion s.services <- ServiceUpdate{Op: SET, Services: services.Items} } watcher, err := s.client.WatchServices(labels.Everything(), labels.Everything(), *resourceVersion) if err != nil { glog.Errorf("Unable to watch for services changes: %v", err) time.Sleep(wait.Jitter(s.waitDuration, 0.0)) return } defer watcher.Stop() ch := watcher.ResultChan() handleServicesWatch(resourceVersion, ch, s.services) }
// runEndpoints loops forever looking for changes to endpoints. func (s *SourceAPI) runEndpoints(resourceVersion *uint64) { if *resourceVersion == 0 { endpoints, err := s.client.ListEndpoints(labels.Everything()) if err != nil { glog.Errorf("Unable to load endpoints: %v", err) time.Sleep(wait.Jitter(s.waitDuration, 0.0)) return } *resourceVersion = endpoints.ResourceVersion s.endpoints <- EndpointsUpdate{Op: SET, Endpoints: endpoints.Items} } watcher, err := s.client.WatchEndpoints(labels.Everything(), labels.Everything(), *resourceVersion) if err != nil { glog.Errorf("Unable to watch for endpoints changes: %v", err) time.Sleep(wait.Jitter(s.waitDuration, 0.0)) return } defer watcher.Stop() ch := watcher.ResultChan() handleEndpointsWatch(resourceVersion, ch, s.endpoints) }
// createTokenSecret creates a token secret for a given service account. Returns the name of the token func (e *DockercfgController) createTokenSecret(serviceAccount *api.ServiceAccount) (*api.Secret, error) { tokenSecret := &api.Secret{ ObjectMeta: api.ObjectMeta{ Name: secret.Strategy.GenerateName(getTokenSecretNamePrefix(serviceAccount)), Namespace: serviceAccount.Namespace, Annotations: map[string]string{ api.ServiceAccountNameKey: serviceAccount.Name, api.ServiceAccountUIDKey: string(serviceAccount.UID), }, }, Type: api.SecretTypeServiceAccountToken, Data: map[string][]byte{}, } _, err := e.client.Secrets(tokenSecret.Namespace).Create(tokenSecret) if err != nil { return nil, err } // now we have to wait for the service account token controller to make this valid // TODO remove this once we have a create-token endpoint for i := 0; i <= tokenSecretWaitTimes; i++ { liveTokenSecret, err := e.client.Secrets(tokenSecret.Namespace).Get(tokenSecret.Name) if err != nil { return nil, err } if len(liveTokenSecret.Data[api.ServiceAccountTokenKey]) > 0 { return liveTokenSecret, nil } time.Sleep(wait.Jitter(tokenSecretWaitInterval, 0.0)) } // the token wasn't ever created, attempt deletion glog.Warningf("Deleting unfilled token secret %s/%s", tokenSecret.Namespace, tokenSecret.Name) if err := e.client.Secrets(tokenSecret.Namespace).Delete(tokenSecret.Name); (err != nil) && !kapierrors.IsNotFound(err) { util.HandleError(err) } return nil, fmt.Errorf("token never generated for %s", tokenSecret.Name) }
func (r *endpointsReflector) listAndWatch() { r.run(&r.resourceVersion) time.Sleep(wait.Jitter(r.reconnectDuration, 0.0)) }