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 }