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  }