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 }