github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/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 "launchpad.net/tomb" 9 10 "github.com/juju/juju/cmd/jujud/agent/util" 11 "github.com/juju/juju/worker" 12 "github.com/juju/juju/worker/dependency" 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 util.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: util.FlagOutput, 43 Filter: bounceUnlocked, 44 } 45 } 46 47 // NewFlag returns a worker that implements util.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 go func() { 55 defer w.tomb.Done() 56 w.tomb.Kill(w.run()) 57 }() 58 return w, nil 59 } 60 61 // Flag uses a gate to implement util.Flag. 62 type Flag struct { 63 tomb tomb.Tomb 64 gate Waiter 65 unlocked bool 66 } 67 68 // Kill is part of the worker.Worker interface. 69 func (w *Flag) Kill() { 70 w.tomb.Kill(nil) 71 } 72 73 // Wait is part of the worker.Worker interface. 74 func (w *Flag) Wait() error { 75 return w.tomb.Wait() 76 } 77 78 // Check is part of the util.Flag interface. 79 func (w *Flag) Check() bool { 80 return w.unlocked 81 } 82 83 func (w *Flag) run() error { 84 var bounce <-chan struct{} 85 if !w.unlocked { 86 bounce = w.gate.Unlocked() 87 } 88 select { 89 case <-w.tomb.Dying(): 90 return tomb.ErrDying 91 case <-bounce: 92 return ErrUnlocked 93 } 94 } 95 96 // ErrUnlocked indicates that a Flag's gate has been unlocked and 97 // it should be restarted to reflect the new value. 98 var ErrUnlocked = errors.New("gate unlocked") 99 100 // bounceUnlocked returns dependency.ErrBounce if passed an error caused 101 // by ErrUnlocked; and otherwise returns the original error. 102 func bounceUnlocked(err error) error { 103 if errors.Cause(err) == ErrUnlocked { 104 return dependency.ErrBounce 105 } 106 return err 107 }