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