github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/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  		// TODO(fwereade): we *should* handle interrupted actions, and make sure
    56  		// they're marked as failed, but that's not for now.
    57  		if localState.Hook != nil {
    58  			logger.Infof("found incomplete action %q; ignoring", localState.ActionId)
    59  			logger.Infof("recommitting prior %q hook", localState.Hook.Kind)
    60  			return opFactory.NewSkipHook(*localState.Hook)
    61  		} else {
    62  			logger.Infof("%q hook is nil", operation.RunAction)
    63  		}
    64  	case operation.Continue:
    65  		return opFactory.NewAction(nextAction)
    66  	}
    67  	return nil, resolver.ErrNoOperation
    68  }