예제 #1
0
// 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
}
예제 #2
0
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
}
예제 #3
0
파일: kv.go 프로젝트: drcapulet/p2
// 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:
		}
	}
}