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