1package command
2
3import (
4	"fmt"
5	"strings"
6)
7
8type AllocStopCommand struct {
9	Meta
10}
11
12func (a *AllocStopCommand) Help() string {
13	helpText := `
14Usage: nomad alloc stop [options] <allocation>
15Alias: nomad stop
16
17  stop an existing allocation. This command is used to signal a specific alloc
18  to shut down. When the allocation has been shut down, it will then be
19  rescheduled. An interactive monitoring session will display log lines as the
20  allocation completes shutting down. It is safe to exit the monitor early with
21  ctrl-c.
22
23General Options:
24
25  ` + generalOptionsUsage() + `
26
27Stop Specific Options:
28
29  -detach
30    Return immediately instead of entering monitor mode. After the
31    stop command is submitted, a new evaluation ID is printed to the
32    screen, which can be used to examine the rescheduling evaluation using the
33    eval-status command.
34
35  -verbose
36    Show full information.
37`
38	return strings.TrimSpace(helpText)
39}
40
41func (c *AllocStopCommand) Name() string { return "alloc stop" }
42
43func (c *AllocStopCommand) Run(args []string) int {
44	var detach, verbose bool
45
46	flags := c.Meta.FlagSet(c.Name(), FlagSetClient)
47	flags.Usage = func() { c.Ui.Output(c.Help()) }
48	flags.BoolVar(&detach, "detach", false, "")
49	flags.BoolVar(&verbose, "verbose", false, "")
50
51	if err := flags.Parse(args); err != nil {
52		return 1
53	}
54
55	// Check that we got exactly one alloc
56	args = flags.Args()
57	if len(args) != 1 {
58		c.Ui.Error("This command takes one argument: <alloc-id>")
59		c.Ui.Error(commandErrorText(c))
60		return 1
61	}
62
63	allocID := args[0]
64
65	// Truncate the id unless full length is requested
66	length := shortId
67	if verbose {
68		length = fullId
69	}
70
71	// Query the allocation info
72	if len(allocID) == 1 {
73		c.Ui.Error(fmt.Sprintf("Alloc ID must contain at least two characters."))
74		return 1
75	}
76
77	allocID = sanitizeUUIDPrefix(allocID)
78
79	// Get the HTTP client
80	client, err := c.Meta.Client()
81	if err != nil {
82		c.Ui.Error(fmt.Sprintf("Error initializing client: %s", err))
83		return 1
84	}
85
86	allocs, _, err := client.Allocations().PrefixList(allocID)
87	if err != nil {
88		c.Ui.Error(fmt.Sprintf("Error querying allocation: %v", err))
89		return 1
90	}
91
92	if len(allocs) == 0 {
93		c.Ui.Error(fmt.Sprintf("No allocation(s) with prefix or id %q found", allocID))
94		return 1
95	}
96
97	if len(allocs) > 1 {
98		// Format the allocs
99		out := formatAllocListStubs(allocs, verbose, length)
100		c.Ui.Error(fmt.Sprintf("Prefix matched multiple allocations\n\n%s", out))
101		return 1
102	}
103
104	// Prefix lookup matched a single allocation
105	alloc, _, err := client.Allocations().Info(allocs[0].ID, nil)
106	if err != nil {
107		c.Ui.Error(fmt.Sprintf("Error querying allocation: %s", err))
108		return 1
109	}
110
111	resp, err := client.Allocations().Stop(alloc, nil)
112	if err != nil {
113		c.Ui.Error(fmt.Sprintf("Error stopping allocation: %s", err))
114		return 1
115	}
116
117	if detach {
118		c.Ui.Output(resp.EvalID)
119		return 0
120	}
121
122	mon := newMonitor(c.Ui, client, length)
123	return mon.monitor(resp.EvalID, false)
124}
125
126func (a *AllocStopCommand) Synopsis() string {
127	return "Stop and reschedule a running allocation"
128}
129