github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/cmd/juju/action/cancel.go (about) 1 // Copyright 2014-2017 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package action 5 6 import ( 7 "fmt" 8 9 "github.com/juju/cmd" 10 "github.com/juju/errors" 11 "github.com/juju/gnuflag" 12 "gopkg.in/juju/names.v2" 13 14 "github.com/juju/juju/apiserver/params" 15 jujucmd "github.com/juju/juju/cmd" 16 "github.com/juju/juju/cmd/modelcmd" 17 "github.com/juju/juju/cmd/output" 18 ) 19 20 func NewCancelCommand() cmd.Command { 21 return modelcmd.Wrap(&cancelCommand{}) 22 } 23 24 type cancelCommand struct { 25 ActionCommandBase 26 out cmd.Output 27 requestedIds []string 28 } 29 30 // Set up the output. 31 func (c *cancelCommand) SetFlags(f *gnuflag.FlagSet) { 32 c.ActionCommandBase.SetFlags(f) 33 c.out.AddFlags(f, "yaml", output.DefaultFormatters) 34 } 35 36 const cancelDoc = ` 37 Cancel actions matching given IDs or partial ID prefixes.` 38 39 func (c *cancelCommand) Info() *cmd.Info { 40 return jujucmd.Info(&cmd.Info{ 41 Name: "cancel-action", 42 Args: "<<action ID | action ID prefix>...>", 43 Purpose: "Cancel pending actions.", 44 Doc: cancelDoc, 45 }) 46 } 47 48 func (c *cancelCommand) Init(args []string) error { 49 c.requestedIds = args 50 return nil 51 } 52 53 func (c *cancelCommand) Run(ctx *cmd.Context) error { 54 api, err := c.NewActionAPIClient() 55 if err != nil { 56 return err 57 } 58 defer api.Close() 59 60 if len(c.requestedIds) == 0 { 61 return errors.Errorf("no actions specified") 62 } 63 64 var actionTags []names.ActionTag 65 for _, requestedId := range c.requestedIds { 66 requestedActionTags, err := getActionTagsByPrefix(api, requestedId) 67 if err != nil { 68 return err 69 } 70 71 // If a non existing ID was submitted we abort the command taking no further action. 72 if len(requestedActionTags) < 1 { 73 return errors.Errorf("no actions found matching prefix %s, no actions have been canceled", requestedId) 74 } 75 76 actionTags = append(actionTags, requestedActionTags...) 77 } 78 79 entities := []params.Entity{} 80 for _, tag := range actionTags { 81 entities = append(entities, params.Entity{Tag: tag.String()}) 82 } 83 84 actions, err := api.Cancel(params.Entities{Entities: entities}) 85 if err != nil { 86 return err 87 } 88 89 if len(actions.Results) < 1 { 90 return errors.Errorf("identifier(s) %q matched action(s) %q, but no actions were canceled", c.requestedIds, actionTags) 91 } 92 93 type unCanceledAction struct { 94 ActionTag names.ActionTag 95 Result *params.ActionResult 96 } 97 var unCanceledActions []unCanceledAction 98 var canceledActions []params.ActionResult 99 100 for i, result := range actions.Results { 101 if result.Action != nil { 102 canceledActions = append(canceledActions, result) 103 } else { 104 unCanceledActions = append(unCanceledActions, unCanceledAction{actionTags[i], &result}) 105 } 106 } 107 108 if len(canceledActions) > 0 { 109 err = c.out.Write(ctx, resultsToMap(canceledActions)) 110 } 111 112 if len(unCanceledActions) > 0 { 113 message := ("The following actions could not be canceled:\n") 114 for _, a := range unCanceledActions { 115 message += fmt.Sprintf("action: %s, error: %s\n", a.ActionTag, a.Result.Message) 116 } 117 118 logger.Warningf(message) 119 } 120 121 return err 122 }