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