github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/cmd/juju/action/status.go (about) 1 // Copyright 2014-2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package action 5 6 import ( 7 "time" 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 NewStatusCommand() cmd.Command { 21 return modelcmd.Wrap(&statusCommand{}) 22 } 23 24 // statusCommand shows the status of an Action by ID. 25 type statusCommand struct { 26 ActionCommandBase 27 out cmd.Output 28 requestedId string 29 name string 30 } 31 32 const statusDoc = ` 33 Show the status of Actions matching given ID, partial ID prefix, or all Actions if no ID is supplied. 34 If --name <name> is provided the search will be done by name rather than by ID. 35 ` 36 37 // Set up the output. 38 func (c *statusCommand) SetFlags(f *gnuflag.FlagSet) { 39 c.ActionCommandBase.SetFlags(f) 40 c.out.AddFlags(f, "yaml", output.DefaultFormatters) 41 f.StringVar(&c.name, "name", "", "Action name") 42 } 43 44 func (c *statusCommand) Info() *cmd.Info { 45 return jujucmd.Info(&cmd.Info{ 46 Name: "show-action-status", 47 Args: "[<action ID>|<action ID prefix>]", 48 Purpose: "Show results of all actions filtered by optional ID prefix.", 49 Doc: statusDoc, 50 }) 51 } 52 53 func (c *statusCommand) Init(args []string) error { 54 switch len(args) { 55 case 0: 56 c.requestedId = "" 57 return nil 58 case 1: 59 c.requestedId = args[0] 60 return nil 61 default: 62 return cmd.CheckEmpty(args[1:]) 63 } 64 } 65 66 func (c *statusCommand) Run(ctx *cmd.Context) error { 67 api, err := c.NewActionAPIClient() 68 if err != nil { 69 return err 70 } 71 defer api.Close() 72 73 if c.name != "" { 74 actions, err := GetActionsByName(api, c.name) 75 if err != nil { 76 return errors.Trace(err) 77 } 78 return c.out.Write(ctx, resultsToMap(actions)) 79 } 80 81 actionTags, err := getActionTagsByPrefix(api, c.requestedId) 82 if err != nil { 83 return err 84 } 85 86 if len(actionTags) < 1 { 87 if len(c.requestedId) == 0 { 88 return errors.Errorf("no actions found") 89 } else { 90 return errors.Errorf("no actions found matching prefix %q", c.requestedId) 91 } 92 } 93 94 entities := []params.Entity{} 95 for _, tag := range actionTags { 96 entities = append(entities, params.Entity{Tag: tag.String()}) 97 } 98 99 actions, err := api.Actions(params.Entities{Entities: entities}) 100 if err != nil { 101 return err 102 } 103 104 if len(actions.Results) < 1 { 105 return errors.Errorf("identifier %q matched action(s) %v, but found no results", c.requestedId, actionTags) 106 } 107 108 return c.out.Write(ctx, resultsToMap(actions.Results)) 109 } 110 111 // resultsToMap is a helper function that takes in a []params.ActionResult 112 // and returns a map[string]interface{} ready to be served to the 113 // formatter for printing. 114 func resultsToMap(results []params.ActionResult) map[string]interface{} { 115 items := []map[string]interface{}{} 116 for _, item := range results { 117 items = append(items, resultToMap(item)) 118 } 119 return map[string]interface{}{"actions": items} 120 } 121 122 func resultToMap(result params.ActionResult) map[string]interface{} { 123 item := map[string]interface{}{} 124 if result.Error != nil { 125 item["error"] = result.Error.Error() 126 } 127 if result.Action != nil { 128 item["action"] = result.Action.Name 129 atag, err := names.ParseActionTag(result.Action.Tag) 130 if err != nil { 131 item["id"] = result.Action.Tag 132 } else { 133 item["id"] = atag.Id() 134 } 135 136 rtag, err := names.ParseUnitTag(result.Action.Receiver) 137 if err != nil { 138 item["unit"] = result.Action.Receiver 139 } else { 140 item["unit"] = rtag.Id() 141 } 142 143 } 144 item["status"] = result.Status 145 146 // result.Completed uses the zero-value to indicate not completed 147 if result.Completed.Equal(time.Time{}) { 148 item["completed at"] = "n/a" 149 } else { 150 item["completed at"] = result.Completed.UTC().Format("2006-01-02 15:04:05") 151 } 152 153 return item 154 } 155 156 // GetActionsByName takes an action APIClient and a name and returns a list of 157 // ActionResults. 158 func GetActionsByName(api APIClient, name string) ([]params.ActionResult, error) { 159 nothing := []params.ActionResult{} 160 results, err := api.FindActionsByNames(params.FindActionsByNames{ActionNames: []string{name}}) 161 if err != nil { 162 return nothing, errors.Trace(err) 163 } 164 if len(results.Actions) != 1 { 165 return nothing, errors.Errorf("expected one result got %d", len(results.Actions)) 166 } 167 result := results.Actions[0] 168 if result.Error != nil { 169 return nothing, result.Error 170 } 171 if len(result.Actions) < 1 { 172 return nothing, errors.Errorf("no actions were found for name %s", name) 173 } 174 return result.Actions, nil 175 176 }