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 }