github.com/Ilhicas/nomad@v1.0.4-0.20210304152020-e86851182bc3/command/alloc_signal.go (about)

     1  package command
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  
     7  	"github.com/hashicorp/nomad/api"
     8  	"github.com/hashicorp/nomad/api/contexts"
     9  	"github.com/posener/complete"
    10  )
    11  
    12  type AllocSignalCommand struct {
    13  	Meta
    14  }
    15  
    16  func (a *AllocSignalCommand) Help() string {
    17  	helpText := `
    18  Usage: nomad alloc signal [options] <signal> <allocation> <task>
    19  
    20    signal an existing allocation. This command is used to signal a specific alloc
    21    and its subtasks. If no task is provided then all of the allocations subtasks
    22    will receive the signal.
    23  
    24    When ACLs are enabled, this command requires a token with the
    25    'alloc-lifecycle', 'read-job', and 'list-jobs' capabilities for the
    26    allocation's namespace.
    27  
    28  General Options:
    29  
    30    ` + generalOptionsUsage(usageOptsDefault) + `
    31  
    32  Signal Specific Options:
    33  
    34    -s
    35      Specify the signal that the selected tasks should receive.
    36  
    37    -verbose
    38      Show full information.
    39  `
    40  	return strings.TrimSpace(helpText)
    41  }
    42  
    43  func (c *AllocSignalCommand) Name() string { return "alloc signal" }
    44  
    45  func (c *AllocSignalCommand) Run(args []string) int {
    46  	var verbose bool
    47  	var signal string
    48  
    49  	flags := c.Meta.FlagSet(c.Name(), FlagSetClient)
    50  	flags.Usage = func() { c.Ui.Output(c.Help()) }
    51  	flags.BoolVar(&verbose, "verbose", false, "")
    52  	flags.StringVar(&signal, "s", "SIGKILL", "")
    53  
    54  	if err := flags.Parse(args); err != nil {
    55  		return 1
    56  	}
    57  
    58  	// Check that we got exactly one alloc
    59  	args = flags.Args()
    60  	if len(args) < 1 || len(args) > 2 {
    61  		c.Ui.Error("This command takes up to two arguments: <alloc-id> <task>")
    62  		c.Ui.Error(commandErrorText(c))
    63  		return 1
    64  	}
    65  
    66  	allocID := args[0]
    67  
    68  	// Truncate the id unless full length is requested
    69  	length := shortId
    70  	if verbose {
    71  		length = fullId
    72  	}
    73  
    74  	// Query the allocation info
    75  	if len(allocID) == 1 {
    76  		c.Ui.Error("Alloc ID must contain at least two characters.")
    77  		return 1
    78  	}
    79  
    80  	allocID = sanitizeUUIDPrefix(allocID)
    81  
    82  	// Get the HTTP client
    83  	client, err := c.Meta.Client()
    84  	if err != nil {
    85  		c.Ui.Error(fmt.Sprintf("Error initializing client: %s", err))
    86  		return 1
    87  	}
    88  
    89  	allocs, _, err := client.Allocations().PrefixList(allocID)
    90  	if err != nil {
    91  		c.Ui.Error(fmt.Sprintf("Error querying allocation: %v", err))
    92  		return 1
    93  	}
    94  
    95  	if len(allocs) == 0 {
    96  		c.Ui.Error(fmt.Sprintf("No allocation(s) with prefix or id %q found", allocID))
    97  		return 1
    98  	}
    99  
   100  	if len(allocs) > 1 {
   101  		// Format the allocs
   102  		out := formatAllocListStubs(allocs, verbose, length)
   103  		c.Ui.Error(fmt.Sprintf("Prefix matched multiple allocations\n\n%s", out))
   104  		return 1
   105  	}
   106  
   107  	// Prefix lookup matched a single allocation
   108  	q := &api.QueryOptions{Namespace: allocs[0].Namespace}
   109  	alloc, _, err := client.Allocations().Info(allocs[0].ID, q)
   110  	if err != nil {
   111  		c.Ui.Error(fmt.Sprintf("Error querying allocation: %s", err))
   112  		return 1
   113  	}
   114  
   115  	var taskName string
   116  	if len(args) == 2 {
   117  		// Validate Task
   118  		taskName = args[1]
   119  		err := validateTaskExistsInAllocation(taskName, alloc)
   120  		if err != nil {
   121  			c.Ui.Error(err.Error())
   122  			return 1
   123  		}
   124  	}
   125  
   126  	err = client.Allocations().Signal(alloc, nil, taskName, signal)
   127  	if err != nil {
   128  		c.Ui.Error(fmt.Sprintf("Error signalling allocation: %s", err))
   129  		return 1
   130  	}
   131  
   132  	return 0
   133  }
   134  
   135  func (a *AllocSignalCommand) Synopsis() string {
   136  	return "Signal a running allocation"
   137  }
   138  
   139  func (c *AllocSignalCommand) AutocompleteFlags() complete.Flags {
   140  	return mergeAutocompleteFlags(c.Meta.AutocompleteFlags(FlagSetClient),
   141  		complete.Flags{
   142  			"-s":       complete.PredictNothing,
   143  			"-verbose": complete.PredictNothing,
   144  		})
   145  }
   146  func (c *AllocSignalCommand) AutocompleteArgs() complete.Predictor {
   147  	// Here we only autocomplete allocation names. Eventually we may consider
   148  	// expanding this to also autocomplete task names. To do so, we'll need to
   149  	// either change the autocompletion api, or implement parsing such that we can
   150  	// easily compute the current arg position.
   151  	return complete.PredictFunc(func(a complete.Args) []string {
   152  		client, err := c.Meta.Client()
   153  		if err != nil {
   154  			return nil
   155  		}
   156  
   157  		resp, _, err := client.Search().PrefixSearch(a.Last, contexts.Allocs, nil)
   158  		if err != nil {
   159  			return []string{}
   160  		}
   161  		return resp.Matches[contexts.Allocs]
   162  	})
   163  }