github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/worker/uniter/actions/resolver.go (about)

     1  // Copyright 2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package actions
     5  
     6  import (
     7  	"github.com/juju/loggo"
     8  
     9  	"github.com/juju/juju/worker/uniter/operation"
    10  	"github.com/juju/juju/worker/uniter/remotestate"
    11  	"github.com/juju/juju/worker/uniter/resolver"
    12  )
    13  
    14  var logger = loggo.GetLogger("juju.worker.uniter.actions")
    15  
    16  type actionsResolver struct{}
    17  
    18  // NewResolver returns a new resolver with determines which action related operation
    19  // should be run based on local and remote uniter states.
    20  //
    21  // TODO(axw) 2015-10-27 #1510333
    22  // Use the same method as in the runcommands resolver
    23  // for updating the remote state snapshot when an
    24  // action is completed.
    25  func NewResolver() resolver.Resolver {
    26  	return &actionsResolver{}
    27  }
    28  
    29  func nextAction(pendingActions []string, completedActions map[string]struct{}) (string, error) {
    30  	for _, action := range pendingActions {
    31  		if _, ok := completedActions[action]; !ok {
    32  			return action, nil
    33  		}
    34  	}
    35  	return "", resolver.ErrNoOperation
    36  }
    37  
    38  // NextOp implements the resolver.Resolver interface.
    39  func (r *actionsResolver) NextOp(
    40  	localState resolver.LocalState,
    41  	remoteState remotestate.Snapshot,
    42  	opFactory operation.Factory,
    43  ) (operation.Operation, error) {
    44  	nextAction, err := nextAction(remoteState.Actions, localState.CompletedActions)
    45  	if err != nil {
    46  		return nil, err
    47  	}
    48  	switch localState.Kind {
    49  	case operation.RunHook:
    50  		// We can still run actions if the unit is in a hook error state.
    51  		if localState.Step == operation.Pending {
    52  			return opFactory.NewAction(nextAction)
    53  		}
    54  	case operation.RunAction:
    55  		if localState.Hook != nil {
    56  			logger.Infof("found incomplete action %q; ignoring", localState.ActionId)
    57  			logger.Infof("recommitting prior %q hook", localState.Hook.Kind)
    58  			return opFactory.NewSkipHook(*localState.Hook)
    59  		} else {
    60  			logger.Infof("%q hook is nil", operation.RunAction)
    61  			return opFactory.NewFailAction(*localState.ActionId)
    62  		}
    63  	case operation.Continue:
    64  		return opFactory.NewAction(nextAction)
    65  	}
    66  	return nil, resolver.ErrNoOperation
    67  }