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