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 }