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