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