github.com/anth0d/nomad@v0.0.0-20221214183521-ae3a0a2cad06/command/alloc_stop.go (about)

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