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  }