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 }