github.com/Pankov404/juju@v0.0.0-20150703034450-be266991dceb/worker/machinelock/manifold.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package machinelock 5 6 import ( 7 "github.com/juju/errors" 8 "github.com/juju/utils/fslock" 9 "launchpad.net/tomb" 10 11 cmdutil "github.com/juju/juju/cmd/jujud/util" 12 "github.com/juju/juju/worker" 13 "github.com/juju/juju/worker/agent" 14 "github.com/juju/juju/worker/dependency" 15 "github.com/juju/juju/worker/util" 16 ) 17 18 // createLock exists to be patched out in export_test.go 19 var createLock = cmdutil.HookExecutionLock 20 21 // ManifoldConfig specifies the names a machinelock manifold should use to 22 // address its dependencies. 23 type ManifoldConfig util.AgentManifoldConfig 24 25 // Manifold returns a dependency.Manifold that governs the construction of 26 // and access to a machine-wide lock intended to prevent various operations 27 // from running concurrently and interfering with one another. Examples (are 28 // not limited to): hook executions, package installation, synchronisation 29 // of reboots. 30 // Clients can access the lock by passing a **fslock.Lock into the out param 31 // of their GetResourceFunc. 32 func Manifold(config ManifoldConfig) dependency.Manifold { 33 manifold := util.AgentManifold(util.AgentManifoldConfig(config), newWorker) 34 manifold.Output = outputFunc 35 return manifold 36 } 37 38 // newWorker creates a degenerate worker that provides access to an fslock. 39 func newWorker(agent agent.Agent) (worker.Worker, error) { 40 dataDir := agent.CurrentConfig().DataDir() 41 lock, err := createLock(dataDir) 42 if err != nil { 43 return nil, errors.Trace(err) 44 } 45 w := &machineLockWorker{lock: lock} 46 go func() { 47 defer w.tomb.Done() 48 <-w.tomb.Dying() 49 }() 50 return w, nil 51 } 52 53 // outputFunc extracts a *fslock.Lock from a *machineLockWorker. 54 func outputFunc(in worker.Worker, out interface{}) error { 55 inWorker, _ := in.(*machineLockWorker) 56 outPointer, _ := out.(**fslock.Lock) 57 if inWorker == nil || outPointer == nil { 58 return errors.Errorf("expected %T->%T; got %T->%T", inWorker, outPointer, in, out) 59 } 60 *outPointer = inWorker.lock 61 return nil 62 } 63 64 // machineLockWorker is a degenerate worker that exists only to hold a reference 65 // to its lock. 66 type machineLockWorker struct { 67 tomb tomb.Tomb 68 lock *fslock.Lock 69 } 70 71 // Kill is part of the worker.Worker interface. 72 func (w *machineLockWorker) Kill() { 73 w.tomb.Kill(nil) 74 } 75 76 // Wait is part of the worker.Worker interface. 77 func (w *machineLockWorker) Wait() error { 78 return w.tomb.Wait() 79 }