github.com/cloudbase/juju-core@v0.0.0-20140504232958-a7271ac7912f/state/apiserver/common/environwatcher.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 "launchpad.net/juju-core/environs" 8 "launchpad.net/juju-core/state" 9 "launchpad.net/juju-core/state/api/params" 10 "launchpad.net/juju-core/state/watcher" 11 ) 12 13 // EnvironWatcher implements two common methods for use by various 14 // facades - WatchForEnvironConfigChanges and EnvironConfig. 15 type EnvironWatcher struct { 16 st state.EnvironAccessor 17 resources *Resources 18 getCanWatch GetAuthFunc 19 getCanReadSecrets GetAuthFunc 20 } 21 22 // NewEnvironWatcher returns a new EnvironWatcher. Active watchers 23 // will be stored in the provided Resources. The two GetAuthFunc 24 // callbacks will be used on each invocation of the methods to 25 // determine current permissions. 26 // Right now, environment tags are not used, so both created AuthFuncs 27 // are called with "" for tag, which means "the current environment". 28 func NewEnvironWatcher(st state.EnvironAccessor, resources *Resources, getCanWatch, getCanReadSecrets GetAuthFunc) *EnvironWatcher { 29 return &EnvironWatcher{ 30 st: st, 31 resources: resources, 32 getCanWatch: getCanWatch, 33 getCanReadSecrets: getCanReadSecrets, 34 } 35 } 36 37 // WatchForEnvironConfigChanges returns a NotifyWatcher that observes 38 // changes to the environment configuration. 39 func (e *EnvironWatcher) WatchForEnvironConfigChanges() (params.NotifyWatchResult, error) { 40 result := params.NotifyWatchResult{} 41 42 canWatch, err := e.getCanWatch() 43 if err != nil { 44 return result, err 45 } 46 // TODO(dimitern) If we have multiple environments in state, use a 47 // tag argument here and as a method argument. 48 if !canWatch("") { 49 result.Error = ServerError(ErrPerm) 50 return result, ErrPerm 51 } 52 53 watch := e.st.WatchForEnvironConfigChanges() 54 // Consume the initial event. Technically, API 55 // calls to Watch 'transmit' the initial event 56 // in the Watch response. But NotifyWatchers 57 // have no state to transmit. 58 if _, ok := <-watch.Changes(); ok { 59 result.NotifyWatcherId = e.resources.Register(watch) 60 } else { 61 return result, watcher.MustErr(watch) 62 } 63 return result, nil 64 } 65 66 // EnvironConfig returns the current environment's configuration. 67 func (e *EnvironWatcher) EnvironConfig() (params.EnvironConfigResult, error) { 68 result := params.EnvironConfigResult{} 69 70 canReadSecrets, err := e.getCanReadSecrets() 71 if err != nil { 72 return result, err 73 } 74 75 config, err := e.st.EnvironConfig() 76 if err != nil { 77 return result, err 78 } 79 allAttrs := config.AllAttrs() 80 81 // TODO(dimitern) If we have multiple environments in state, use a 82 // tag argument here and as a method argument. 83 if !canReadSecrets("") { 84 // Mask out any secrets in the environment configuration 85 // with values of the same type, so it'll pass validation. 86 // 87 // TODO(dimitern) 201309-26 bug #1231384 88 // Delete the code below and mark the bug as fixed, 89 // once it's live tested on MAAS and 1.16 compatibility 90 // is dropped. 91 env, err := environs.New(config) 92 if err != nil { 93 return result, err 94 } 95 secretAttrs, err := env.Provider().SecretAttrs(config) 96 for k := range secretAttrs { 97 allAttrs[k] = "not available" 98 } 99 } 100 result.Config = allAttrs 101 return result, nil 102 }