github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/worker/modelworkermanager/modelworkermanager.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package modelworkermanager 5 6 import ( 7 "time" 8 9 "github.com/juju/errors" 10 "github.com/juju/loggo" 11 12 "github.com/juju/juju/state" 13 "github.com/juju/juju/worker" 14 "github.com/juju/juju/worker/catacomb" 15 ) 16 17 var logger = loggo.GetLogger("juju.workers.modelworkermanager") 18 19 // Backend defines the State functionality used by the manager worker. 20 type Backend interface { 21 WatchModels() state.StringsWatcher 22 } 23 24 // NewWorkerFunc should return a worker responsible for running 25 // all a model's required workers; and for returning nil when 26 // there's no more model to manage. 27 type NewWorkerFunc func(controllerUUID, modelUUID string) (worker.Worker, error) 28 29 // Config holds the dependencies and configuration necessary to run 30 // a model worker manager. 31 type Config struct { 32 ControllerUUID string 33 Backend Backend 34 NewWorker NewWorkerFunc 35 ErrorDelay time.Duration 36 } 37 38 // Validate returns an error if config cannot be expected to drive 39 // a functional model worker manager. 40 func (config Config) Validate() error { 41 if config.ControllerUUID == "" { 42 return errors.NotValidf("missing controller UUID") 43 } 44 if config.Backend == nil { 45 return errors.NotValidf("nil Backend") 46 } 47 if config.NewWorker == nil { 48 return errors.NotValidf("nil NewWorker") 49 } 50 if config.ErrorDelay <= 0 { 51 return errors.NotValidf("non-positive ErrorDelay") 52 } 53 return nil 54 } 55 56 func New(config Config) (worker.Worker, error) { 57 if err := config.Validate(); err != nil { 58 return nil, errors.Trace(err) 59 } 60 m := &modelWorkerManager{ 61 config: config, 62 } 63 64 err := catacomb.Invoke(catacomb.Plan{ 65 Site: &m.catacomb, 66 Work: m.loop, 67 }) 68 if err != nil { 69 return nil, errors.Trace(err) 70 } 71 return m, nil 72 } 73 74 type modelWorkerManager struct { 75 catacomb catacomb.Catacomb 76 config Config 77 runner worker.Runner 78 } 79 80 // Kill satisfies the Worker interface. 81 func (m *modelWorkerManager) Kill() { 82 m.catacomb.Kill(nil) 83 } 84 85 // Wait satisfies the Worker interface. 86 func (m *modelWorkerManager) Wait() error { 87 return m.catacomb.Wait() 88 } 89 90 func (m *modelWorkerManager) loop() error { 91 m.runner = worker.NewRunner( 92 neverFatal, neverImportant, m.config.ErrorDelay, 93 ) 94 if err := m.catacomb.Add(m.runner); err != nil { 95 return errors.Trace(err) 96 } 97 watcher := m.config.Backend.WatchModels() 98 if err := m.catacomb.Add(watcher); err != nil { 99 return errors.Trace(err) 100 } 101 102 for { 103 select { 104 case <-m.catacomb.Dying(): 105 return m.catacomb.ErrDying() 106 case uuids, ok := <-watcher.Changes(): 107 if !ok { 108 return errors.New("changes stopped") 109 } 110 for _, modelUUID := range uuids { 111 if err := m.ensure(m.config.ControllerUUID, modelUUID); err != nil { 112 return errors.Trace(err) 113 } 114 } 115 } 116 } 117 } 118 119 func (m *modelWorkerManager) ensure(controllerUUID, modelUUID string) error { 120 starter := m.starter(controllerUUID, modelUUID) 121 if err := m.runner.StartWorker(modelUUID, starter); err != nil { 122 return errors.Trace(err) 123 } 124 return nil 125 } 126 127 func (m *modelWorkerManager) starter(controllerUUID, modelUUID string) func() (worker.Worker, error) { 128 return func() (worker.Worker, error) { 129 logger.Debugf("starting workers for model %q", modelUUID) 130 worker, err := m.config.NewWorker(controllerUUID, modelUUID) 131 if err != nil { 132 return nil, errors.Annotatef(err, "cannot manage model %q", modelUUID) 133 } 134 return worker, nil 135 } 136 } 137 138 func neverFatal(error) bool { 139 return false 140 } 141 142 func neverImportant(error, error) bool { 143 return false 144 }