mirror of
https://github.com/kemko/nomad.git
synced 2026-01-01 16:05:42 +03:00
Some operators use very long group/task `shutdown_delay` settings to safely drain network connections to their workloads after service deregistration. But during incident response, they may want to cause that drain to be skipped so they can quickly shed load. Provide a `-no-shutdown-delay` flag on the `nomad alloc stop` and `nomad job stop` commands that bypasses the delay. This sets a new desired transition state on the affected allocations that the allocation/task runner will identify during pre-kill on the client. Note (as documented here) that using this flag will almost always result in failed inbound network connections for workloads as the tasks will exit before clients receive updated service discovery information and won't be gracefully drained.
148 lines
3.7 KiB
Go
148 lines
3.7 KiB
Go
package command
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
|
|
"github.com/hashicorp/nomad/api"
|
|
)
|
|
|
|
type AllocStopCommand struct {
|
|
Meta
|
|
}
|
|
|
|
func (a *AllocStopCommand) Help() string {
|
|
helpText := `
|
|
Usage: nomad alloc stop [options] <allocation>
|
|
Alias: nomad stop
|
|
|
|
Stop an existing allocation. This command is used to signal a specific alloc
|
|
to shut down. When the allocation has been shut down, it will then be
|
|
rescheduled. An interactive monitoring session will display log lines as the
|
|
allocation completes shutting down. It is safe to exit the monitor early with
|
|
ctrl-c.
|
|
|
|
When ACLs are enabled, this command requires a token with the
|
|
'alloc-lifecycle', 'read-job', and 'list-jobs' capabilities for the
|
|
allocation's namespace.
|
|
|
|
General Options:
|
|
|
|
` + generalOptionsUsage(usageOptsDefault) + `
|
|
|
|
Stop Specific Options:
|
|
|
|
-detach
|
|
Return immediately instead of entering monitor mode. After the
|
|
stop command is submitted, a new evaluation ID is printed to the
|
|
screen, which can be used to examine the rescheduling evaluation using the
|
|
eval-status command.
|
|
|
|
-no-shutdown-delay
|
|
Ignore the the group and task shutdown_delay configuration so there is no
|
|
delay between service deregistration and task shutdown. Note that using
|
|
this flag will result in failed network connections to the allocation
|
|
being stopped.
|
|
|
|
-verbose
|
|
Show full information.
|
|
`
|
|
return strings.TrimSpace(helpText)
|
|
}
|
|
|
|
func (c *AllocStopCommand) Name() string { return "alloc stop" }
|
|
|
|
func (c *AllocStopCommand) Run(args []string) int {
|
|
var detach, verbose, noShutdownDelay bool
|
|
|
|
flags := c.Meta.FlagSet(c.Name(), FlagSetClient)
|
|
flags.Usage = func() { c.Ui.Output(c.Help()) }
|
|
flags.BoolVar(&detach, "detach", false, "")
|
|
flags.BoolVar(&verbose, "verbose", false, "")
|
|
flags.BoolVar(&noShutdownDelay, "no-shutdown-delay", false, "")
|
|
|
|
if err := flags.Parse(args); err != nil {
|
|
return 1
|
|
}
|
|
|
|
// Check that we got exactly one alloc
|
|
args = flags.Args()
|
|
if len(args) != 1 {
|
|
c.Ui.Error("This command takes one argument: <alloc-id>")
|
|
c.Ui.Error(commandErrorText(c))
|
|
return 1
|
|
}
|
|
|
|
allocID := args[0]
|
|
|
|
// Truncate the id unless full length is requested
|
|
length := shortId
|
|
if verbose {
|
|
length = fullId
|
|
}
|
|
|
|
// Query the allocation info
|
|
if len(allocID) == 1 {
|
|
c.Ui.Error("Alloc ID must contain at least two characters.")
|
|
return 1
|
|
}
|
|
|
|
allocID = sanitizeUUIDPrefix(allocID)
|
|
|
|
// Get the HTTP client
|
|
client, err := c.Meta.Client()
|
|
if err != nil {
|
|
c.Ui.Error(fmt.Sprintf("Error initializing client: %s", err))
|
|
return 1
|
|
}
|
|
|
|
allocs, _, err := client.Allocations().PrefixList(allocID)
|
|
if err != nil {
|
|
c.Ui.Error(fmt.Sprintf("Error querying allocation: %v", err))
|
|
return 1
|
|
}
|
|
|
|
if len(allocs) == 0 {
|
|
c.Ui.Error(fmt.Sprintf("No allocation(s) with prefix or id %q found", allocID))
|
|
return 1
|
|
}
|
|
|
|
if len(allocs) > 1 {
|
|
// Format the allocs
|
|
out := formatAllocListStubs(allocs, verbose, length)
|
|
c.Ui.Error(fmt.Sprintf("Prefix matched multiple allocations\n\n%s", out))
|
|
return 1
|
|
}
|
|
|
|
// Prefix lookup matched a single allocation
|
|
q := &api.QueryOptions{Namespace: allocs[0].Namespace}
|
|
alloc, _, err := client.Allocations().Info(allocs[0].ID, q)
|
|
if err != nil {
|
|
c.Ui.Error(fmt.Sprintf("Error querying allocation: %s", err))
|
|
return 1
|
|
}
|
|
|
|
var opts *api.QueryOptions
|
|
if noShutdownDelay {
|
|
opts = &api.QueryOptions{Params: map[string]string{"no_shutdown_delay": "true"}}
|
|
}
|
|
|
|
resp, err := client.Allocations().Stop(alloc, opts)
|
|
if err != nil {
|
|
c.Ui.Error(fmt.Sprintf("Error stopping allocation: %s", err))
|
|
return 1
|
|
}
|
|
|
|
if detach {
|
|
c.Ui.Output(resp.EvalID)
|
|
return 0
|
|
}
|
|
|
|
mon := newMonitor(c.Ui, client, length)
|
|
return mon.monitor(resp.EvalID)
|
|
}
|
|
|
|
func (a *AllocStopCommand) Synopsis() string {
|
|
return "Stop and reschedule a running allocation"
|
|
}
|