github.com/diptanu/nomad@v0.5.7-0.20170516172507-d72e86cbe3d9/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    -purge
    35      Purge is used to stop the job and purge it from the system. If not set, the
    36      job will still be queryable and will be purged by the garbage collector.
    37  
    38    -yes
    39      Automatic yes to prompts.
    40  
    41    -verbose
    42      Display full information.
    43  `
    44  	return strings.TrimSpace(helpText)
    45  }
    46  
    47  func (c *StopCommand) Synopsis() string {
    48  	return "Stop a running job"
    49  }
    50  
    51  func (c *StopCommand) Run(args []string) int {
    52  	var detach, purge, verbose, autoYes bool
    53  
    54  	flags := c.Meta.FlagSet("stop", FlagSetClient)
    55  	flags.Usage = func() { c.Ui.Output(c.Help()) }
    56  	flags.BoolVar(&detach, "detach", false, "")
    57  	flags.BoolVar(&verbose, "verbose", false, "")
    58  	flags.BoolVar(&autoYes, "yes", false, "")
    59  	flags.BoolVar(&purge, "purge", false, "")
    60  
    61  	if err := flags.Parse(args); err != nil {
    62  		return 1
    63  	}
    64  
    65  	// Truncate the id unless full length is requested
    66  	length := shortId
    67  	if verbose {
    68  		length = fullId
    69  	}
    70  
    71  	// Check that we got exactly one job
    72  	args = flags.Args()
    73  	if len(args) != 1 {
    74  		c.Ui.Error(c.Help())
    75  		return 1
    76  	}
    77  	jobID := args[0]
    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  	// Check if the job exists
    87  	jobs, _, err := client.Jobs().PrefixList(jobID)
    88  	if err != nil {
    89  		c.Ui.Error(fmt.Sprintf("Error deregistering job: %s", err))
    90  		return 1
    91  	}
    92  	if len(jobs) == 0 {
    93  		c.Ui.Error(fmt.Sprintf("No job(s) with prefix or id %q found", jobID))
    94  		return 1
    95  	}
    96  	if len(jobs) > 1 && strings.TrimSpace(jobID) != jobs[0].ID {
    97  		out := make([]string, len(jobs)+1)
    98  		out[0] = "ID|Type|Priority|Status"
    99  		for i, job := range jobs {
   100  			out[i+1] = fmt.Sprintf("%s|%s|%d|%s",
   101  				job.ID,
   102  				job.Type,
   103  				job.Priority,
   104  				job.Status)
   105  		}
   106  		c.Ui.Output(fmt.Sprintf("Prefix matched multiple jobs\n\n%s", formatList(out)))
   107  		return 0
   108  	}
   109  	// Prefix lookup matched a single job
   110  	job, _, err := client.Jobs().Info(jobs[0].ID, nil)
   111  	if err != nil {
   112  		c.Ui.Error(fmt.Sprintf("Error deregistering job: %s", err))
   113  		return 1
   114  	}
   115  
   116  	// Confirm the stop if the job was a prefix match.
   117  	if jobID != *job.ID && !autoYes {
   118  		question := fmt.Sprintf("Are you sure you want to stop job %q? [y/N]", *job.ID)
   119  		answer, err := c.Ui.Ask(question)
   120  		if err != nil {
   121  			c.Ui.Error(fmt.Sprintf("Failed to parse answer: %v", err))
   122  			return 1
   123  		}
   124  
   125  		if answer == "" || strings.ToLower(answer)[0] == 'n' {
   126  			// No case
   127  			c.Ui.Output("Cancelling job stop")
   128  			return 0
   129  		} else if strings.ToLower(answer)[0] == 'y' && len(answer) > 1 {
   130  			// Non exact match yes
   131  			c.Ui.Output("For confirmation, an exact ‘y’ is required.")
   132  			return 0
   133  		} else if answer != "y" {
   134  			c.Ui.Output("No confirmation detected. For confirmation, an exact 'y' is required.")
   135  			return 1
   136  		}
   137  	}
   138  
   139  	// Invoke the stop
   140  	evalID, _, err := client.Jobs().Deregister(*job.ID, purge, nil)
   141  	if err != nil {
   142  		c.Ui.Error(fmt.Sprintf("Error deregistering job: %s", err))
   143  		return 1
   144  	}
   145  
   146  	// If we are stopping a periodic job there won't be an evalID.
   147  	if evalID == "" {
   148  		return 0
   149  	}
   150  
   151  	if detach {
   152  		c.Ui.Output(evalID)
   153  		return 0
   154  	}
   155  
   156  	// Start monitoring the stop eval
   157  	mon := newMonitor(c.Ui, client, length)
   158  	return mon.monitor(evalID, false)
   159  }