github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/worker/meterstatus/runner.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package meterstatus 5 6 import ( 7 "fmt" 8 9 "github.com/juju/errors" 10 "github.com/juju/names" 11 "github.com/juju/utils/fslock" 12 "gopkg.in/juju/charm.v6-unstable/hooks" 13 "launchpad.net/tomb" 14 15 "github.com/juju/juju/agent" 16 "github.com/juju/juju/worker/uniter" 17 "github.com/juju/juju/worker/uniter/runner" 18 ) 19 20 // HookRunner implements the functionality necessary to run a meter-status-changed hook. 21 type HookRunner interface { 22 RunHook(string, string, <-chan struct{}) error 23 } 24 25 // hookRunner implements functionality for running a hook. 26 type hookRunner struct { 27 machineLock *fslock.Lock 28 config agent.Config 29 tag names.UnitTag 30 } 31 32 func NewHookRunner(tag names.UnitTag, lock *fslock.Lock, config agent.Config) HookRunner { 33 return &hookRunner{ 34 tag: tag, 35 machineLock: lock, 36 config: config, 37 } 38 } 39 40 // acquireExecutionLock acquires the machine-level execution lock and returns a function to be used 41 // to unlock it. 42 func (w *hookRunner) acquireExecutionLock(interrupt <-chan struct{}) (func() error, error) { 43 message := "running meter-status-changed hook" 44 logger.Tracef("lock: %v", message) 45 checkTomb := func() error { 46 select { 47 case <-interrupt: 48 return tomb.ErrDying 49 default: 50 return nil 51 } 52 } 53 message = fmt.Sprintf("%s: %s", w.tag.String(), message) 54 if err := w.machineLock.LockWithFunc(message, checkTomb); err != nil { 55 return nil, err 56 } 57 return func() error { 58 logger.Tracef("unlock: %v", message) 59 return w.machineLock.Unlock() 60 }, nil 61 } 62 63 func (w *hookRunner) RunHook(code, info string, interrupt <-chan struct{}) (runErr error) { 64 unitTag := w.tag 65 paths := uniter.NewPaths(w.config.DataDir(), unitTag) 66 ctx := NewLimitedContext(unitTag.String()) 67 ctx.SetEnvVars(map[string]string{ 68 "JUJU_METER_STATUS": code, 69 "JUJU_METER_INFO": info, 70 }) 71 r := runner.NewRunner(ctx, paths) 72 unlock, err := w.acquireExecutionLock(interrupt) 73 if err != nil { 74 return errors.Annotate(err, "failed to acquire machine lock") 75 } 76 defer func() { 77 unlockErr := unlock() 78 if unlockErr != nil { 79 logger.Criticalf("hook run resulted in error %v; unlock failure error: %v", runErr, unlockErr) 80 } 81 }() 82 return r.RunHook(string(hooks.MeterStatusChanged)) 83 }