github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/worker/environ/environ.go (about) 1 // Copyright 2012-2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package environ 5 6 import ( 7 "github.com/juju/errors" 8 9 "github.com/juju/juju/environs" 10 "github.com/juju/juju/environs/config" 11 "github.com/juju/juju/watcher" 12 "github.com/juju/juju/worker/catacomb" 13 ) 14 15 // ConfigGetter exposes a model configuration to its clients. 16 type ConfigGetter interface { 17 ModelConfig() (*config.Config, error) 18 } 19 20 // ConfigObserver exposes a model configuration and a watch constructor 21 // that allows clients to be informed of changes to the configuration. 22 type ConfigObserver interface { 23 ConfigGetter 24 WatchForModelConfigChanges() (watcher.NotifyWatcher, error) 25 } 26 27 // Config describes the dependencies of a Tracker. 28 // 29 // It's arguable that it should be called TrackerConfig, because of the heavy 30 // use of model config in this package. 31 type Config struct { 32 Observer ConfigObserver 33 NewEnvironFunc NewEnvironFunc 34 } 35 36 // NewEnvironFunc is the type of a function that, given a model config, 37 // returns an Environ. This will typically be environs.New. 38 type NewEnvironFunc func(*config.Config) (environs.Environ, error) 39 40 // Validate returns an error if the config cannot be used to start a Tracker. 41 func (config Config) Validate() error { 42 if config.Observer == nil { 43 return errors.NotValidf("nil Observer") 44 } 45 if config.NewEnvironFunc == nil { 46 return errors.NotValidf("nil NewEnvironFunc") 47 } 48 return nil 49 } 50 51 // Tracker loads an environment, makes it available to clients, and updates 52 // the environment in response to config changes until it is killed. 53 type Tracker struct { 54 config Config 55 catacomb catacomb.Catacomb 56 environ environs.Environ 57 } 58 59 // NewTracker loads an environment from the observer and returns a new Tracker, 60 // or an error if anything goes wrong. If a tracker is returned, its Environ() 61 // method is immediately usable. 62 // 63 // The caller is responsible for Kill()ing the returned Tracker and Wait()ing 64 // for any errors it might return. 65 func NewTracker(config Config) (*Tracker, error) { 66 if err := config.Validate(); err != nil { 67 return nil, errors.Trace(err) 68 } 69 modelConfig, err := config.Observer.ModelConfig() 70 if err != nil { 71 return nil, errors.Annotate(err, "cannot read environ config") 72 } 73 environ, err := config.NewEnvironFunc(modelConfig) 74 if err != nil { 75 return nil, errors.Annotate(err, "cannot create environ") 76 } 77 78 t := &Tracker{ 79 config: config, 80 environ: environ, 81 } 82 err = catacomb.Invoke(catacomb.Plan{ 83 Site: &t.catacomb, 84 Work: t.loop, 85 }) 86 if err != nil { 87 return nil, errors.Trace(err) 88 } 89 return t, nil 90 } 91 92 // Environ returns the encapsulated Environ. It will continue to be updated in 93 // the background for as long as the Tracker continues to run. 94 func (t *Tracker) Environ() environs.Environ { 95 return t.environ 96 } 97 98 func (t *Tracker) loop() error { 99 environWatcher, err := t.config.Observer.WatchForModelConfigChanges() 100 if err != nil { 101 return errors.Annotate(err, "cannot watch environ config") 102 } 103 if err := t.catacomb.Add(environWatcher); err != nil { 104 return errors.Trace(err) 105 } 106 for { 107 logger.Debugf("waiting for environ watch notification") 108 select { 109 case <-t.catacomb.Dying(): 110 return t.catacomb.ErrDying() 111 case _, ok := <-environWatcher.Changes(): 112 if !ok { 113 return errors.New("environ config watch closed") 114 } 115 } 116 logger.Debugf("reloading environ config") 117 modelConfig, err := t.config.Observer.ModelConfig() 118 if err != nil { 119 return errors.Annotate(err, "cannot read environ config") 120 } 121 if err = t.environ.SetConfig(modelConfig); err != nil { 122 return errors.Annotate(err, "cannot update environ config") 123 } 124 } 125 } 126 127 // Kill is part of the worker.Worker interface. 128 func (t *Tracker) Kill() { 129 t.catacomb.Kill(nil) 130 } 131 132 // Wait is part of the worker.Worker interface. 133 func (t *Tracker) Wait() error { 134 return t.catacomb.Wait() 135 }