github.com/altoros/juju-vmware@v0.0.0-20150312064031-f19ae857ccca/worker/uniter/operation/runaction.go (about)

     1  // Copyright 2014 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package operation
     5  
     6  import (
     7  	"fmt"
     8  
     9  	"github.com/juju/errors"
    10  
    11  	"github.com/juju/juju/worker/uniter/runner"
    12  )
    13  
    14  type runAction struct {
    15  	actionId string
    16  
    17  	callbacks     Callbacks
    18  	runnerFactory runner.Factory
    19  
    20  	name   string
    21  	runner runner.Runner
    22  }
    23  
    24  // String is part of the Operation interface.
    25  func (ra *runAction) String() string {
    26  	return fmt.Sprintf("run action %s", ra.actionId)
    27  }
    28  
    29  // Prepare ensures that the action is valid and can be executed. If not, it
    30  // will return ErrSkipExecute. It preserves any hook recorded in the supplied
    31  // state.
    32  // Prepare is part of the Operation interface.
    33  func (ra *runAction) Prepare(state State) (*State, error) {
    34  	rnr, err := ra.runnerFactory.NewActionRunner(ra.actionId)
    35  	if cause := errors.Cause(err); runner.IsBadActionError(cause) {
    36  		if err := ra.callbacks.FailAction(ra.actionId, err.Error()); err != nil {
    37  			return nil, err
    38  		}
    39  		return nil, ErrSkipExecute
    40  	} else if cause == runner.ErrActionNotAvailable {
    41  		return nil, ErrSkipExecute
    42  	} else if err != nil {
    43  		return nil, errors.Annotatef(err, "cannot create runner for action %q", ra.actionId)
    44  	}
    45  	actionData, err := rnr.Context().ActionData()
    46  	if err != nil {
    47  		// this should *really* never happen, but let's not panic
    48  		return nil, errors.Trace(err)
    49  	}
    50  	ra.name = actionData.ActionName
    51  	ra.runner = rnr
    52  	return stateChange{
    53  		Kind:     RunAction,
    54  		Step:     Pending,
    55  		ActionId: &ra.actionId,
    56  		Hook:     state.Hook,
    57  	}.apply(state), nil
    58  }
    59  
    60  // Execute runs the action, and preserves any hook recorded in the supplied state.
    61  // Execute is part of the Operation interface.
    62  func (ra *runAction) Execute(state State) (*State, error) {
    63  	message := fmt.Sprintf("running action %s", ra.name)
    64  	unlock, err := ra.callbacks.AcquireExecutionLock(message)
    65  	if err != nil {
    66  		return nil, err
    67  	}
    68  	defer unlock()
    69  
    70  	err = ra.runner.RunAction(ra.name)
    71  	if err != nil {
    72  		// This indicates an actual error -- an action merely failing should
    73  		// be handled inside the Runner, and returned as nil.
    74  		return nil, errors.Annotatef(err, "running action %q", ra.name)
    75  	}
    76  	return stateChange{
    77  		Kind:     RunAction,
    78  		Step:     Done,
    79  		ActionId: &ra.actionId,
    80  		Hook:     state.Hook,
    81  	}.apply(state), nil
    82  }
    83  
    84  // Commit preserves the recorded hook, and returns a neutral state.
    85  // Commit is part of the Operation interface.
    86  func (ra *runAction) Commit(state State) (*State, error) {
    87  	return stateChange{
    88  		Kind: Continue,
    89  		Step: Pending,
    90  		Hook: state.Hook,
    91  	}.apply(state), nil
    92  }