github.com/altoros/juju-vmware@v0.0.0-20150312064031-f19ae857ccca/apiserver/common/watch.go (about)

     1  // Copyright 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package common
     5  
     6  import (
     7  	"github.com/juju/errors"
     8  	"github.com/juju/juju/apiserver/params"
     9  	"github.com/juju/juju/state"
    10  	"github.com/juju/juju/state/watcher"
    11  	"github.com/juju/names"
    12  )
    13  
    14  // AgentEntityWatcher implements a common Watch method for use by
    15  // various facades.
    16  type AgentEntityWatcher struct {
    17  	st          state.EntityFinder
    18  	resources   *Resources
    19  	getCanWatch GetAuthFunc
    20  }
    21  
    22  // NewAgentEntityWatcher returns a new AgentEntityWatcher. The
    23  // GetAuthFunc will be used on each invocation of Watch to determine
    24  // current permissions.
    25  func NewAgentEntityWatcher(st state.EntityFinder, resources *Resources, getCanWatch GetAuthFunc) *AgentEntityWatcher {
    26  	return &AgentEntityWatcher{
    27  		st:          st,
    28  		resources:   resources,
    29  		getCanWatch: getCanWatch,
    30  	}
    31  }
    32  
    33  func (a *AgentEntityWatcher) watchEntity(tag names.Tag) (string, error) {
    34  	entity0, err := a.st.FindEntity(tag)
    35  	if err != nil {
    36  		return "", err
    37  	}
    38  	entity, ok := entity0.(state.NotifyWatcherFactory)
    39  	if !ok {
    40  		return "", NotSupportedError(tag, "watching")
    41  	}
    42  	watch := entity.Watch()
    43  	// Consume the initial event. Technically, API
    44  	// calls to Watch 'transmit' the initial event
    45  	// in the Watch response. But NotifyWatchers
    46  	// have no state to transmit.
    47  	if _, ok := <-watch.Changes(); ok {
    48  		return a.resources.Register(watch), nil
    49  	}
    50  	return "", watcher.EnsureErr(watch)
    51  }
    52  
    53  // Watch starts an NotifyWatcher for each given entity.
    54  func (a *AgentEntityWatcher) Watch(args params.Entities) (params.NotifyWatchResults, error) {
    55  	result := params.NotifyWatchResults{
    56  		Results: make([]params.NotifyWatchResult, len(args.Entities)),
    57  	}
    58  	if len(args.Entities) == 0 {
    59  		return result, nil
    60  	}
    61  	canWatch, err := a.getCanWatch()
    62  	if err != nil {
    63  		return params.NotifyWatchResults{}, errors.Trace(err)
    64  	}
    65  	for i, entity := range args.Entities {
    66  		tag, err := names.ParseTag(entity.Tag)
    67  		if err != nil {
    68  			result.Results[i].Error = ServerError(ErrPerm)
    69  			continue
    70  		}
    71  		err = ErrPerm
    72  		watcherId := ""
    73  		if canWatch(tag) {
    74  			watcherId, err = a.watchEntity(tag)
    75  		}
    76  		result.Results[i].NotifyWatcherId = watcherId
    77  		result.Results[i].Error = ServerError(err)
    78  	}
    79  	return result, nil
    80  }