github.com/hhrutter/nomad@v0.6.0-rc2.0.20170723054333-80c4b03f0705/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  		c.Ui.Error(fmt.Sprintf("Prefix matched multiple jobs\n\n%s", createStatusListOutput(jobs)))
    98  		return 1
    99  	}
   100  	// Prefix lookup matched a single job
   101  	job, _, err := client.Jobs().Info(jobs[0].ID, nil)
   102  	if err != nil {
   103  		c.Ui.Error(fmt.Sprintf("Error deregistering job: %s", err))
   104  		return 1
   105  	}
   106  
   107  	// Confirm the stop if the job was a prefix match.
   108  	if jobID != *job.ID && !autoYes {
   109  		question := fmt.Sprintf("Are you sure you want to stop job %q? [y/N]", *job.ID)
   110  		answer, err := c.Ui.Ask(question)
   111  		if err != nil {
   112  			c.Ui.Error(fmt.Sprintf("Failed to parse answer: %v", err))
   113  			return 1
   114  		}
   115  
   116  		if answer == "" || strings.ToLower(answer)[0] == 'n' {
   117  			// No case
   118  			c.Ui.Output("Cancelling job stop")
   119  			return 0
   120  		} else if strings.ToLower(answer)[0] == 'y' && len(answer) > 1 {
   121  			// Non exact match yes
   122  			c.Ui.Output("For confirmation, an exact ‘y’ is required.")
   123  			return 0
   124  		} else if answer != "y" {
   125  			c.Ui.Output("No confirmation detected. For confirmation, an exact 'y' is required.")
   126  			return 1
   127  		}
   128  	}
   129  
   130  	// Invoke the stop
   131  	evalID, _, err := client.Jobs().Deregister(*job.ID, purge, nil)
   132  	if err != nil {
   133  		c.Ui.Error(fmt.Sprintf("Error deregistering job: %s", err))
   134  		return 1
   135  	}
   136  
   137  	// If we are stopping a periodic job there won't be an evalID.
   138  	if evalID == "" {
   139  		return 0
   140  	}
   141  
   142  	if detach {
   143  		c.Ui.Output(evalID)
   144  		return 0
   145  	}
   146  
   147  	// Start monitoring the stop eval
   148  	mon := newMonitor(c.Ui, client, length)
   149  	return mon.monitor(evalID, false)
   150  }