// WatchPodCluster implements a watch for the Pod cluster at _id_ // It will return a blocking channel on which the client can read // WatchedPodCluster objects. The goroutine maintaining the watch will block on // writing to this channel so it's up to the caller to read it with haste. // This function will return ErrNoPodCluster if the podCluster goes away. In // this case, the caller should close the quit chan. // The caller may shutdown this watch by sending a sentinel on the quitChan. func (s *consulStore) WatchPodCluster(id fields.ID, quit <-chan struct{}) <-chan WatchedPodCluster { inCh := make(chan *api.KVPair) outCh := make(chan WatchedPodCluster) errChan := make(chan error, 1) quitWatch := make(chan struct{}) key := path.Join(podClusterTree, string(id)) go consulutil.WatchSingle(key, s.kv, inCh, quitWatch, errChan) go func() { var kvp *api.KVPair for { select { case <-quit: return case err := <-errChan: s.logger.WithError(err).Errorf("WatchSingle returned error, recovered.") case kvp = <-inCh: if kvp == nil { // PodCluster at _id_ has been deleted select { case <-quit: return case outCh <- WatchedPodCluster{PodCluster: nil, Err: NoPodCluster}: } return } } pc, err := kvpToPC(kvp) var wpc WatchedPodCluster if err != nil { wpc.Err = err } else { wpc.PodCluster = &pc } select { case <-quit: return case outCh <- wpc: } } }() return outCh }
func (s *consulStore) Watch(rc *fields.RC, quit <-chan struct{}) (<-chan struct{}, <-chan error) { updated := make(chan struct{}) rcp, err := s.rcPath(rc.ID) if err != nil { errors := make(chan error, 1) errors <- err close(errors) close(updated) return updated, errors } errors := make(chan error) input := make(chan *api.KVPair) go consulutil.WatchSingle(rcp, s.kv, input, quit, errors) go func() { defer close(updated) defer close(errors) for kvp := range input { if kvp == nil { // seems this RC got deleted from under us. quitting // would be unexpected, so we'll just wait for it to // reappear in consul continue } newRC, err := kvpToRC(kvp) if err != nil { select { case errors <- err: case <-quit: } } else { *rc = newRC select { case updated <- struct{}{}: case <-quit: } } } }() return updated, errors }
// WatchPod is like WatchPods, but for a single key only. The output channel // may contain nil manifests, if the target key does not exist. func (c consulStore) WatchPod( podPrefix PodPrefix, nodename types.NodeName, podId types.PodID, quitChan <-chan struct{}, errChan chan<- error, podChan chan<- ManifestResult, ) { defer close(podChan) key, err := podPath(podPrefix, nodename, podId) if err != nil { select { case <-quitChan: case errChan <- err: } return } kvpChan := make(chan *api.KVPair) go consulutil.WatchSingle(key, c.client.KV(), kvpChan, quitChan, errChan) for pair := range kvpChan { out := ManifestResult{} if pair != nil { out, err = c.manifestResultFromPair(pair) if err != nil { select { case <-quitChan: return case errChan <- util.Errorf("Could not parse pod manifest at %s: %s. Content follows: \n%s", pair.Key, err, pair.Value): continue } } } select { case <-quitChan: return case podChan <- out: } } }