github.com/hooklift/nomad@v0.5.7-0.20170407200202-db11e7dd7b55/command/stop.go (about)

     1  package command
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  )
     7  
     8  type StopCommand struct {
     9  	Meta
    10  }
    11  
    12  func (c *StopCommand) Help() string {
    13  	helpText := `
    14  Usage: nomad stop [options] <job>
    15  
    16    Stop an existing job. This command is used to signal allocations
    17    to shut down for the given job ID. Upon successful deregistraion,
    18    an interactive monitor session will start to display log lines as
    19    the job unwinds its allocations and completes shutting down. It
    20    is safe to exit the monitor early using ctrl+c.
    21  
    22  General Options:
    23  
    24    ` + generalOptionsUsage() + `
    25  
    26  Stop Options:
    27  
    28    -detach
    29      Return immediately instead of entering monitor mode. After the
    30      deregister command is submitted, a new evaluation ID is printed to the
    31      screen, which can be used to examine the evaluation using the eval-status
    32      command.
    33  
    34    -yes
    35      Automatic yes to prompts.
    36  
    37    -verbose
    38      Display full information.
    39  `
    40  	return strings.TrimSpace(helpText)
    41  }
    42  
    43  func (c *StopCommand) Synopsis() string {
    44  	return "Stop a running job"
    45  }
    46  
    47  func (c *StopCommand) Run(args []string) int {
    48  	var detach, verbose, autoYes bool
    49  
    50  	flags := c.Meta.FlagSet("stop", FlagSetClient)
    51  	flags.Usage = func() { c.Ui.Output(c.Help()) }
    52  	flags.BoolVar(&detach, "detach", false, "")
    53  	flags.BoolVar(&verbose, "verbose", false, "")
    54  	flags.BoolVar(&autoYes, "yes", false, "")
    55  
    56  	if err := flags.Parse(args); err != nil {
    57  		return 1
    58  	}
    59  
    60  	// Truncate the id unless full length is requested
    61  	length := shortId
    62  	if verbose {
    63  		length = fullId
    64  	}
    65  
    66  	// Check that we got exactly one job
    67  	args = flags.Args()
    68  	if len(args) != 1 {
    69  		c.Ui.Error(c.Help())
    70  		return 1
    71  	}
    72  	jobID := args[0]
    73  
    74  	// Get the HTTP client
    75  	client, err := c.Meta.Client()
    76  	if err != nil {
    77  		c.Ui.Error(fmt.Sprintf("Error initializing client: %s", err))
    78  		return 1
    79  	}
    80  
    81  	// Check if the job exists
    82  	jobs, _, err := client.Jobs().PrefixList(jobID)
    83  	if err != nil {
    84  		c.Ui.Error(fmt.Sprintf("Error deregistering job: %s", err))
    85  		return 1
    86  	}
    87  	if len(jobs) == 0 {
    88  		c.Ui.Error(fmt.Sprintf("No job(s) with prefix or id %q found", jobID))
    89  		return 1
    90  	}
    91  	if len(jobs) > 1 && strings.TrimSpace(jobID) != jobs[0].ID {
    92  		out := make([]string, len(jobs)+1)
    93  		out[0] = "ID|Type|Priority|Status"
    94  		for i, job := range jobs {
    95  			out[i+1] = fmt.Sprintf("%s|%s|%d|%s",
    96  				job.ID,
    97  				job.Type,
    98  				job.Priority,
    99  				job.Status)
   100  		}
   101  		c.Ui.Output(fmt.Sprintf("Prefix matched multiple jobs\n\n%s", formatList(out)))
   102  		return 0
   103  	}
   104  	// Prefix lookup matched a single job
   105  	job, _, err := client.Jobs().Info(jobs[0].ID, nil)
   106  	if err != nil {
   107  		c.Ui.Error(fmt.Sprintf("Error deregistering job: %s", err))
   108  		return 1
   109  	}
   110  
   111  	// Confirm the stop if the job was a prefix match.
   112  	if jobID != *job.ID && !autoYes {
   113  		question := fmt.Sprintf("Are you sure you want to stop job %q? [y/N]", *job.ID)
   114  		answer, err := c.Ui.Ask(question)
   115  		if err != nil {
   116  			c.Ui.Error(fmt.Sprintf("Failed to parse answer: %v", err))
   117  			return 1
   118  		}
   119  
   120  		if answer == "" || strings.ToLower(answer)[0] == 'n' {
   121  			// No case
   122  			c.Ui.Output("Cancelling job stop")
   123  			return 0
   124  		} else if strings.ToLower(answer)[0] == 'y' && len(answer) > 1 {
   125  			// Non exact match yes
   126  			c.Ui.Output("For confirmation, an exact ‘y’ is required.")
   127  			return 0
   128  		} else if answer != "y" {
   129  			c.Ui.Output("No confirmation detected. For confirmation, an exact 'y' is required.")
   130  			return 1
   131  		}
   132  	}
   133  
   134  	// Invoke the stop
   135  	evalID, _, err := client.Jobs().Deregister(*job.ID, nil)
   136  	if err != nil {
   137  		c.Ui.Error(fmt.Sprintf("Error deregistering job: %s", err))
   138  		return 1
   139  	}
   140  
   141  	// If we are stopping a periodic job there won't be an evalID.
   142  	if evalID == "" {
   143  		return 0
   144  	}
   145  
   146  	if detach {
   147  		c.Ui.Output(evalID)
   148  		return 0
   149  	}
   150  
   151  	// Start monitoring the stop eval
   152  	mon := newMonitor(c.Ui, client, length)
   153  	return mon.monitor(evalID, false)
   154  }