github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/worker/migrationflag/worker.go (about)

     1  // Copyright 2016 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package migrationflag
     5  
     6  import (
     7  	"github.com/juju/errors"
     8  	"github.com/juju/utils"
     9  
    10  	"github.com/juju/juju/core/migration"
    11  	"github.com/juju/juju/watcher"
    12  	"github.com/juju/juju/worker/catacomb"
    13  )
    14  
    15  // ErrChanged indicates that a Worker has stopped because its
    16  // Check result is no longer valid.
    17  var ErrChanged = errors.New("migration flag value changed")
    18  
    19  // Facade exposes controller functionality required by a Worker.
    20  type Facade interface {
    21  	Watch(uuid string) (watcher.NotifyWatcher, error)
    22  	Phase(uuid string) (migration.Phase, error)
    23  }
    24  
    25  // Predicate defines a predicate.
    26  type Predicate func(migration.Phase) bool
    27  
    28  // IsNone is a predicate.
    29  func IsNone(phase migration.Phase) bool {
    30  	return phase == migration.NONE
    31  }
    32  
    33  // Config holds the dependencies and configuration for a Worker.
    34  type Config struct {
    35  	Facade Facade
    36  	Model  string
    37  	Check  Predicate
    38  }
    39  
    40  // Validate returns an error if the config cannot be expected to
    41  // drive a functional Worker.
    42  func (config Config) Validate() error {
    43  	if config.Facade == nil {
    44  		return errors.NotValidf("nil Facade")
    45  	}
    46  	if !utils.IsValidUUIDString(config.Model) {
    47  		return errors.NotValidf("Model %q", config.Model)
    48  	}
    49  	if config.Check == nil {
    50  		return errors.NotValidf("nil Check")
    51  	}
    52  	return nil
    53  }
    54  
    55  // New returns a Worker that tracks the result of the configured
    56  // Check on the Model's migration phase, as exposed by the Facade.
    57  func New(config Config) (*Worker, error) {
    58  	if err := config.Validate(); err != nil {
    59  		return nil, errors.Trace(err)
    60  	}
    61  	phase, err := config.Facade.Phase(config.Model)
    62  	if err != nil {
    63  		return nil, errors.Trace(err)
    64  	}
    65  
    66  	w := &Worker{
    67  		config: config,
    68  		phase:  phase,
    69  	}
    70  	err = catacomb.Invoke(catacomb.Plan{
    71  		Site: &w.catacomb,
    72  		Work: w.loop,
    73  	})
    74  	if err != nil {
    75  		return nil, errors.Trace(err)
    76  	}
    77  	return w, nil
    78  }
    79  
    80  // Worker implements worker.Worker and util.Flag, and exits
    81  // with ErrChanged whenever the result of its configured Check of
    82  // the Model's migration phase changes.
    83  type Worker struct {
    84  	catacomb catacomb.Catacomb
    85  	config   Config
    86  	phase    migration.Phase
    87  }
    88  
    89  // Kill is part of the worker.Worker interface.
    90  func (w *Worker) Kill() {
    91  	w.catacomb.Kill(nil)
    92  }
    93  
    94  // Wait is part of the worker.Worker interface.
    95  func (w *Worker) Wait() error {
    96  	return w.catacomb.Wait()
    97  }
    98  
    99  // Check is part of the util.Flag interface.
   100  func (w *Worker) Check() bool {
   101  	return w.config.Check(w.phase)
   102  }
   103  
   104  func (w *Worker) loop() error {
   105  	model := w.config.Model
   106  	facade := w.config.Facade
   107  	watcher, err := facade.Watch(model)
   108  	if err != nil {
   109  		return errors.Trace(err)
   110  	}
   111  	if err := w.catacomb.Add(watcher); err != nil {
   112  		return errors.Trace(err)
   113  	}
   114  	for {
   115  		select {
   116  		case <-w.catacomb.Dying():
   117  			return w.catacomb.ErrDying()
   118  		case <-watcher.Changes():
   119  			phase, err := facade.Phase(model)
   120  			if err != nil {
   121  				return errors.Trace(err)
   122  			}
   123  			if w.Check() != w.config.Check(phase) {
   124  				return ErrChanged
   125  			}
   126  		}
   127  	}
   128  }