github.com/Pankov404/juju@v0.0.0-20150703034450-be266991dceb/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  	RequiresMachineLock
    24  }
    25  
    26  // String is part of the Operation interface.
    27  func (ra *runAction) String() string {
    28  	return fmt.Sprintf("run action %s", ra.actionId)
    29  }
    30  
    31  // Prepare ensures that the action is valid and can be executed. If not, it
    32  // will return ErrSkipExecute. It preserves any hook recorded in the supplied
    33  // state.
    34  // Prepare is part of the Operation interface.
    35  func (ra *runAction) Prepare(state State) (*State, error) {
    36  	rnr, err := ra.runnerFactory.NewActionRunner(ra.actionId)
    37  	if cause := errors.Cause(err); runner.IsBadActionError(cause) {
    38  		if err := ra.callbacks.FailAction(ra.actionId, err.Error()); err != nil {
    39  			return nil, err
    40  		}
    41  		return nil, ErrSkipExecute
    42  	} else if cause == runner.ErrActionNotAvailable {
    43  		return nil, ErrSkipExecute
    44  	} else if err != nil {
    45  		return nil, errors.Annotatef(err, "cannot create runner for action %q", ra.actionId)
    46  	}
    47  	actionData, err := rnr.Context().ActionData()
    48  	if err != nil {
    49  		// this should *really* never happen, but let's not panic
    50  		return nil, errors.Trace(err)
    51  	}
    52  	ra.name = actionData.ActionName
    53  	ra.runner = rnr
    54  	return stateChange{
    55  		Kind:     RunAction,
    56  		Step:     Pending,
    57  		ActionId: &ra.actionId,
    58  		Hook:     state.Hook,
    59  	}.apply(state), nil
    60  }
    61  
    62  // Execute runs the action, and preserves any hook recorded in the supplied state.
    63  // Execute is part of the Operation interface.
    64  func (ra *runAction) Execute(state State) (*State, error) {
    65  	message := fmt.Sprintf("running action %s", ra.name)
    66  
    67  	if err := ra.callbacks.SetExecutingStatus(message); err != nil {
    68  		return nil, err
    69  	}
    70  
    71  	err := ra.runner.RunAction(ra.name)
    72  	if err != nil {
    73  		// This indicates an actual error -- an action merely failing should
    74  		// be handled inside the Runner, and returned as nil.
    75  		return nil, errors.Annotatef(err, "running action %q", ra.name)
    76  	}
    77  	return stateChange{
    78  		Kind:     RunAction,
    79  		Step:     Done,
    80  		ActionId: &ra.actionId,
    81  		Hook:     state.Hook,
    82  	}.apply(state), nil
    83  }
    84  
    85  // Commit preserves the recorded hook, and returns a neutral state.
    86  // Commit is part of the Operation interface.
    87  func (ra *runAction) Commit(state State) (*State, error) {
    88  	return stateChange{
    89  		Kind: continuationKind(state),
    90  		Step: Pending,
    91  		Hook: state.Hook,
    92  	}.apply(state), nil
    93  }
    94  
    95  // continuationKind determines what State Kind the operation
    96  // should return after Commit.
    97  func continuationKind(state State) Kind {
    98  	switch {
    99  	case state.Hook != nil:
   100  		return RunHook
   101  	default:
   102  		return Continue
   103  	}
   104  }