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  }