github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/worker/gate/flag.go (about)

     1  // Copyright 2016 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package gate
     5  
     6  import (
     7  	"github.com/juju/errors"
     8  	"gopkg.in/juju/worker.v1"
     9  	"gopkg.in/juju/worker.v1/dependency"
    10  	"gopkg.in/tomb.v2"
    11  
    12  	"github.com/juju/juju/cmd/jujud/agent/engine"
    13  )
    14  
    15  // FlagManifoldConfig holds the dependencies required to run a Flag
    16  // in a dependency.Engine.
    17  type FlagManifoldConfig struct {
    18  	GateName  string
    19  	NewWorker func(gate Waiter) (worker.Worker, error)
    20  }
    21  
    22  // start is a dependency.StartFunc that uses config.
    23  func (config FlagManifoldConfig) start(context dependency.Context) (worker.Worker, error) {
    24  	var gate Waiter
    25  	if err := context.Get(config.GateName, &gate); err != nil {
    26  		return nil, errors.Trace(err)
    27  	}
    28  	worker, err := config.NewWorker(gate)
    29  	if err != nil {
    30  		return nil, errors.Trace(err)
    31  	}
    32  	return worker, nil
    33  
    34  }
    35  
    36  // FlagManifold runs a worker that implements engine.Flag such that
    37  // it's only considered set when the referenced gate is unlocked.
    38  func FlagManifold(config FlagManifoldConfig) dependency.Manifold {
    39  	return dependency.Manifold{
    40  		Inputs: []string{config.GateName},
    41  		Start:  config.start,
    42  		Output: engine.FlagOutput,
    43  		Filter: bounceUnlocked,
    44  	}
    45  }
    46  
    47  // NewFlag returns a worker that implements engine.Flag,
    48  // backed by the supplied gate's unlockedness.
    49  func NewFlag(gate Waiter) (*Flag, error) {
    50  	w := &Flag{
    51  		gate:     gate,
    52  		unlocked: gate.IsUnlocked(),
    53  	}
    54  	w.tomb.Go(w.run)
    55  	return w, nil
    56  }
    57  
    58  // Flag uses a gate to implement engine.Flag.
    59  type Flag struct {
    60  	tomb     tomb.Tomb
    61  	gate     Waiter
    62  	unlocked bool
    63  }
    64  
    65  // Kill is part of the worker.Worker interface.
    66  func (w *Flag) Kill() {
    67  	w.tomb.Kill(nil)
    68  }
    69  
    70  // Wait is part of the worker.Worker interface.
    71  func (w *Flag) Wait() error {
    72  	return w.tomb.Wait()
    73  }
    74  
    75  // Check is part of the engine.Flag interface.
    76  func (w *Flag) Check() bool {
    77  	return w.unlocked
    78  }
    79  
    80  func (w *Flag) run() error {
    81  	var bounce <-chan struct{}
    82  	if !w.unlocked {
    83  		bounce = w.gate.Unlocked()
    84  	}
    85  	select {
    86  	case <-w.tomb.Dying():
    87  		return tomb.ErrDying
    88  	case <-bounce:
    89  		return ErrUnlocked
    90  	}
    91  }
    92  
    93  // ErrUnlocked indicates that a Flag's gate has been unlocked and
    94  // it should be restarted to reflect the new value.
    95  var ErrUnlocked = errors.New("gate unlocked")
    96  
    97  // bounceUnlocked returns dependency.ErrBounce if passed an error caused
    98  // by ErrUnlocked; and otherwise returns the original error.
    99  func bounceUnlocked(err error) error {
   100  	if errors.Cause(err) == ErrUnlocked {
   101  		return dependency.ErrBounce
   102  	}
   103  	return err
   104  }