github.com/mhilton/juju-juju@v0.0.0-20150901100907-a94dd2c73455/worker/uniter/runner/factory.go (about)

     1  // Copyright 2012-2014 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package runner
     5  
     6  import (
     7  	"github.com/juju/errors"
     8  	"github.com/juju/names"
     9  	"gopkg.in/juju/charm.v5"
    10  
    11  	"github.com/juju/juju/api/uniter"
    12  	"github.com/juju/juju/apiserver/params"
    13  	"github.com/juju/juju/worker/uniter/hook"
    14  )
    15  
    16  type CommandInfo struct {
    17  	// RelationId is the relation context to execute the commands in.
    18  	RelationId int
    19  	// RemoteUnitName is the remote unit for the relation context.
    20  	RemoteUnitName string
    21  	// ForceRemoteUnit skips unit inference and existence validation.
    22  	ForceRemoteUnit bool
    23  }
    24  
    25  // Factory represents a long-lived object that can create runners
    26  // relevant to a specific unit.
    27  type Factory interface {
    28  
    29  	// NewCommandRunner returns an execution context suitable for running
    30  	// an arbitrary script.
    31  	NewCommandRunner(commandInfo CommandInfo) (Runner, error)
    32  
    33  	// NewHookRunner returns an execution context suitable for running the
    34  	// supplied hook definition (which must be valid).
    35  	NewHookRunner(hookInfo hook.Info) (Runner, error)
    36  
    37  	// NewActionRunner returns an execution context suitable for running the
    38  	// action identified by the supplied id.
    39  	NewActionRunner(actionId string) (Runner, error)
    40  }
    41  
    42  // NewFactory returns a Factory capable of creating runners for executing
    43  // charm hooks, actions and commands.
    44  func NewFactory(
    45  	state *uniter.State,
    46  	paths Paths,
    47  	contextFactory ContextFactory,
    48  ) (
    49  	Factory, error,
    50  ) {
    51  	f := &factory{
    52  		state:          state,
    53  		paths:          paths,
    54  		contextFactory: contextFactory,
    55  	}
    56  
    57  	return f, nil
    58  }
    59  
    60  type factory struct {
    61  	contextFactory ContextFactory
    62  
    63  	// API connection fields.
    64  	state *uniter.State
    65  
    66  	// Fields that shouldn't change in a factory's lifetime.
    67  	paths Paths
    68  }
    69  
    70  // NewCommandRunner exists to satisfy the Factory interface.
    71  func (f *factory) NewCommandRunner(commandInfo CommandInfo) (Runner, error) {
    72  	ctx, err := f.contextFactory.CommandContext(commandInfo)
    73  	if err != nil {
    74  		return nil, errors.Trace(err)
    75  	}
    76  	runner := NewRunner(ctx, f.paths)
    77  	return runner, nil
    78  }
    79  
    80  // NewHookRunner exists to satisfy the Factory interface.
    81  func (f *factory) NewHookRunner(hookInfo hook.Info) (Runner, error) {
    82  	if err := hookInfo.Validate(); err != nil {
    83  		return nil, errors.Trace(err)
    84  	}
    85  
    86  	ctx, err := f.contextFactory.HookContext(hookInfo)
    87  	if err != nil {
    88  		return nil, errors.Trace(err)
    89  	}
    90  	runner := NewRunner(ctx, f.paths)
    91  	return runner, nil
    92  }
    93  
    94  // NewActionRunner exists to satisfy the Factory interface.
    95  func (f *factory) NewActionRunner(actionId string) (Runner, error) {
    96  	ch, err := getCharm(f.paths.GetCharmDir())
    97  	if err != nil {
    98  		return nil, errors.Trace(err)
    99  	}
   100  
   101  	ok := names.IsValidAction(actionId)
   102  	if !ok {
   103  		return nil, &badActionError{actionId, "not valid actionId"}
   104  	}
   105  	tag := names.NewActionTag(actionId)
   106  	action, err := f.state.Action(tag)
   107  	if params.IsCodeNotFoundOrCodeUnauthorized(err) {
   108  		return nil, ErrActionNotAvailable
   109  	} else if params.IsCodeActionNotAvailable(err) {
   110  		return nil, ErrActionNotAvailable
   111  	} else if err != nil {
   112  		return nil, errors.Trace(err)
   113  	}
   114  
   115  	name := action.Name()
   116  	spec, ok := ch.Actions().ActionSpecs[name]
   117  	if !ok {
   118  		return nil, &badActionError{name, "not defined"}
   119  	}
   120  	params := action.Params()
   121  	if err := spec.ValidateParams(params); err != nil {
   122  		return nil, &badActionError{name, err.Error()}
   123  	}
   124  
   125  	actionData := newActionData(name, &tag, params)
   126  	ctx, err := f.contextFactory.ActionContext(actionData)
   127  	runner := NewRunner(ctx, f.paths)
   128  	return runner, nil
   129  }
   130  
   131  func getCharm(charmPath string) (charm.Charm, error) {
   132  	ch, err := charm.ReadCharm(charmPath)
   133  	if err != nil {
   134  		return nil, err
   135  	}
   136  	return ch, nil
   137  }