github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/apiserver/action/action.go (about) 1 // Copyright 2014 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package action 5 6 import ( 7 "github.com/juju/errors" 8 "github.com/juju/names" 9 10 "github.com/juju/juju/apiserver/common" 11 "github.com/juju/juju/apiserver/params" 12 "github.com/juju/juju/state" 13 ) 14 15 func init() { 16 common.RegisterStandardFacade("Action", 1, NewActionAPI) 17 } 18 19 // ActionAPI implements the client API for interacting with Actions 20 type ActionAPI struct { 21 state *state.State 22 resources *common.Resources 23 authorizer common.Authorizer 24 check *common.BlockChecker 25 } 26 27 // NewActionAPI returns an initialized ActionAPI 28 func NewActionAPI(st *state.State, resources *common.Resources, authorizer common.Authorizer) (*ActionAPI, error) { 29 if !authorizer.AuthClient() { 30 return nil, common.ErrPerm 31 } 32 33 return &ActionAPI{ 34 state: st, 35 resources: resources, 36 authorizer: authorizer, 37 check: common.NewBlockChecker(st), 38 }, nil 39 } 40 41 // Actions takes a list of ActionTags, and returns the full Action for 42 // each ID. 43 func (a *ActionAPI) Actions(arg params.Entities) (params.ActionResults, error) { 44 response := params.ActionResults{Results: make([]params.ActionResult, len(arg.Entities))} 45 for i, entity := range arg.Entities { 46 currentResult := &response.Results[i] 47 tag, err := names.ParseTag(entity.Tag) 48 if err != nil { 49 currentResult.Error = common.ServerError(common.ErrBadId) 50 continue 51 } 52 actionTag, ok := tag.(names.ActionTag) 53 if !ok { 54 currentResult.Error = common.ServerError(common.ErrBadId) 55 continue 56 } 57 action, err := a.state.ActionByTag(actionTag) 58 if err != nil { 59 currentResult.Error = common.ServerError(common.ErrBadId) 60 continue 61 } 62 receiverTag, err := names.ActionReceiverTag(action.Receiver()) 63 if err != nil { 64 currentResult.Error = common.ServerError(err) 65 continue 66 } 67 response.Results[i] = common.MakeActionResult(receiverTag, action) 68 } 69 return response, nil 70 } 71 72 // FindActionTagsByPrefix takes a list of string prefixes and finds 73 // corresponding ActionTags that match that prefix. 74 func (a *ActionAPI) FindActionTagsByPrefix(arg params.FindTags) (params.FindTagsResults, error) { 75 response := params.FindTagsResults{Matches: make(map[string][]params.Entity)} 76 for _, prefix := range arg.Prefixes { 77 found := a.state.FindActionTagsByPrefix(prefix) 78 matches := make([]params.Entity, len(found)) 79 for i, tag := range found { 80 matches[i] = params.Entity{Tag: tag.String()} 81 } 82 response.Matches[prefix] = matches 83 } 84 return response, nil 85 } 86 87 func (a *ActionAPI) FindActionsByNames(arg params.FindActionsByNames) (params.ActionsByNames, error) { 88 response := params.ActionsByNames{Actions: make([]params.ActionsByName, len(arg.ActionNames))} 89 for i, name := range arg.ActionNames { 90 currentResult := &response.Actions[i] 91 currentResult.Name = name 92 93 actions, err := a.state.FindActionsByName(name) 94 if err != nil { 95 currentResult.Error = common.ServerError(err) 96 continue 97 } 98 for _, action := range actions { 99 recvTag, err := names.ActionReceiverTag(action.Receiver()) 100 if err != nil { 101 currentResult.Actions = append(currentResult.Actions, params.ActionResult{Error: common.ServerError(err)}) 102 continue 103 } 104 currentAction := common.MakeActionResult(recvTag, action) 105 currentResult.Actions = append(currentResult.Actions, currentAction) 106 } 107 } 108 return response, nil 109 } 110 111 // Enqueue takes a list of Actions and queues them up to be executed by 112 // the designated ActionReceiver, returning the params.Action for each 113 // enqueued Action, or an error if there was a problem enqueueing the 114 // Action. 115 func (a *ActionAPI) Enqueue(arg params.Actions) (params.ActionResults, error) { 116 if err := a.check.ChangeAllowed(); err != nil { 117 return params.ActionResults{}, errors.Trace(err) 118 } 119 120 tagToActionReceiver := common.TagToActionReceiverFn(a.state.FindEntity) 121 response := params.ActionResults{Results: make([]params.ActionResult, len(arg.Actions))} 122 for i, action := range arg.Actions { 123 currentResult := &response.Results[i] 124 receiver, err := tagToActionReceiver(action.Receiver) 125 if err != nil { 126 currentResult.Error = common.ServerError(err) 127 continue 128 } 129 enqueued, err := receiver.AddAction(action.Name, action.Parameters) 130 if err != nil { 131 currentResult.Error = common.ServerError(err) 132 continue 133 } 134 135 response.Results[i] = common.MakeActionResult(receiver.Tag(), enqueued) 136 } 137 return response, nil 138 } 139 140 // ListAll takes a list of Entities representing ActionReceivers and 141 // returns all of the Actions that have been enqueued or run by each of 142 // those Entities. 143 func (a *ActionAPI) ListAll(arg params.Entities) (params.ActionsByReceivers, error) { 144 return a.internalList(arg, combine(pendingActions, runningActions, completedActions)) 145 } 146 147 // ListPending takes a list of Entities representing ActionReceivers 148 // and returns all of the Actions that are enqueued for each of those 149 // Entities. 150 func (a *ActionAPI) ListPending(arg params.Entities) (params.ActionsByReceivers, error) { 151 return a.internalList(arg, pendingActions) 152 } 153 154 // ListRunning takes a list of Entities representing ActionReceivers and 155 // returns all of the Actions that have are running on each of those 156 // Entities. 157 func (a *ActionAPI) ListRunning(arg params.Entities) (params.ActionsByReceivers, error) { 158 return a.internalList(arg, runningActions) 159 } 160 161 // ListCompleted takes a list of Entities representing ActionReceivers 162 // and returns all of the Actions that have been run on each of those 163 // Entities. 164 func (a *ActionAPI) ListCompleted(arg params.Entities) (params.ActionsByReceivers, error) { 165 return a.internalList(arg, completedActions) 166 } 167 168 // Cancel attempts to cancel enqueued Actions from running. 169 func (a *ActionAPI) Cancel(arg params.Entities) (params.ActionResults, error) { 170 if err := a.check.ChangeAllowed(); err != nil { 171 return params.ActionResults{}, errors.Trace(err) 172 } 173 174 response := params.ActionResults{Results: make([]params.ActionResult, len(arg.Entities))} 175 for i, entity := range arg.Entities { 176 currentResult := &response.Results[i] 177 tag, err := names.ParseTag(entity.Tag) 178 if err != nil { 179 currentResult.Error = common.ServerError(common.ErrBadId) 180 continue 181 } 182 actionTag, ok := tag.(names.ActionTag) 183 if !ok { 184 currentResult.Error = common.ServerError(common.ErrBadId) 185 continue 186 } 187 action, err := a.state.ActionByTag(actionTag) 188 if err != nil { 189 currentResult.Error = common.ServerError(err) 190 continue 191 } 192 result, err := action.Finish(state.ActionResults{Status: state.ActionCancelled, Message: "action cancelled via the API"}) 193 if err != nil { 194 currentResult.Error = common.ServerError(err) 195 continue 196 } 197 receiverTag, err := names.ActionReceiverTag(result.Receiver()) 198 if err != nil { 199 currentResult.Error = common.ServerError(err) 200 continue 201 } 202 203 response.Results[i] = common.MakeActionResult(receiverTag, result) 204 } 205 return response, nil 206 } 207 208 // ServicesCharmActions returns a slice of charm Actions for a slice of 209 // services. 210 func (a *ActionAPI) ServicesCharmActions(args params.Entities) (params.ServicesCharmActionsResults, error) { 211 result := params.ServicesCharmActionsResults{Results: make([]params.ServiceCharmActionsResult, len(args.Entities))} 212 for i, entity := range args.Entities { 213 currentResult := &result.Results[i] 214 svcTag, err := names.ParseServiceTag(entity.Tag) 215 if err != nil { 216 currentResult.Error = common.ServerError(common.ErrBadId) 217 continue 218 } 219 currentResult.ServiceTag = svcTag.String() 220 svc, err := a.state.Service(svcTag.Id()) 221 if err != nil { 222 currentResult.Error = common.ServerError(err) 223 continue 224 } 225 ch, _, err := svc.Charm() 226 if err != nil { 227 currentResult.Error = common.ServerError(err) 228 continue 229 } 230 currentResult.Actions = ch.Actions() 231 } 232 return result, nil 233 } 234 235 // internalList takes a list of Entities representing ActionReceivers 236 // and returns all of the Actions the extractorFn can get out of the 237 // ActionReceiver. 238 func (a *ActionAPI) internalList(arg params.Entities, fn extractorFn) (params.ActionsByReceivers, error) { 239 tagToActionReceiver := common.TagToActionReceiverFn(a.state.FindEntity) 240 response := params.ActionsByReceivers{Actions: make([]params.ActionsByReceiver, len(arg.Entities))} 241 for i, entity := range arg.Entities { 242 currentResult := &response.Actions[i] 243 receiver, err := tagToActionReceiver(entity.Tag) 244 if err != nil { 245 currentResult.Error = common.ServerError(common.ErrBadId) 246 continue 247 } 248 currentResult.Receiver = receiver.Tag().String() 249 250 results, err := fn(receiver) 251 if err != nil { 252 currentResult.Error = common.ServerError(err) 253 continue 254 } 255 currentResult.Actions = results 256 } 257 return response, nil 258 } 259 260 // extractorFn is the generic signature for functions that extract 261 // state.Actions from an ActionReceiver, and return them as a slice of 262 // params.ActionResult. 263 type extractorFn func(state.ActionReceiver) ([]params.ActionResult, error) 264 265 // combine takes multiple extractorFn's and combines them into one 266 // function. 267 func combine(funcs ...extractorFn) extractorFn { 268 return func(ar state.ActionReceiver) ([]params.ActionResult, error) { 269 result := []params.ActionResult{} 270 for _, fn := range funcs { 271 items, err := fn(ar) 272 if err != nil { 273 return result, err 274 } 275 result = append(result, items...) 276 } 277 return result, nil 278 } 279 } 280 281 // pendingActions iterates through the Actions() enqueued for an 282 // ActionReceiver, and converts them to a slice of params.ActionResult. 283 func pendingActions(ar state.ActionReceiver) ([]params.ActionResult, error) { 284 return common.ConvertActions(ar, ar.PendingActions) 285 } 286 287 // runningActions iterates through the Actions() running on an 288 // ActionReceiver, and converts them to a slice of params.ActionResult. 289 func runningActions(ar state.ActionReceiver) ([]params.ActionResult, error) { 290 return common.ConvertActions(ar, ar.RunningActions) 291 } 292 293 // completedActions iterates through the Actions() that have run to 294 // completion for an ActionReceiver, and converts them to a slice of 295 // params.ActionResult. 296 func completedActions(ar state.ActionReceiver) ([]params.ActionResult, error) { 297 return common.ConvertActions(ar, ar.CompletedActions) 298 }