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 }