From 099fd00760c604ab281458bfbebaa2f72c4817e0 Mon Sep 17 00:00:00 2001 From: Ryan Uber Date: Wed, 16 Sep 2015 17:35:58 -0700 Subject: [PATCH] command/stop: inital stop command --- command/stop.go | 85 ++++++++++++++++++++++++++++++++++++++++++++ command/stop_test.go | 46 ++++++++++++++++++++++++ commands.go | 6 ++++ 3 files changed, 137 insertions(+) create mode 100644 command/stop.go create mode 100644 command/stop_test.go diff --git a/command/stop.go b/command/stop.go new file mode 100644 index 000000000..e6537ce5c --- /dev/null +++ b/command/stop.go @@ -0,0 +1,85 @@ +package command + +import ( + "fmt" + "strings" +) + +type StopCommand struct { + Meta +} + +func (c *StopCommand) Help() string { + helpText := ` +Usage: nomad stop [options] + + Stop an existing job. This command is used to signal allocations + to shut down for the given job ID. The shutdown happens + asynchronously, unless the -monitor flag is given, in which case + an interactive monitor session will display log lines as the + job unwinds and completes shutting down. + +General Options: + + ` + generalOptionsUsage() + ` + +Stop Options: + + -monitor + Starts an interactive monitor for the job deregistration. This + will display logs in the terminal related to the job shutdown, + and return once the job deregistration has completed. +` + return strings.TrimSpace(helpText) +} + +func (c *StopCommand) Synopsis() string { + return "Stop a running job" +} + +func (c *StopCommand) Run(args []string) int { + var monitor bool + + flags := c.Meta.FlagSet("stop", FlagSetClient) + flags.Usage = func() { c.Ui.Output(c.Help()) } + flags.BoolVar(&monitor, "monitor", false, "") + + if err := flags.Parse(args); err != nil { + return 1 + } + + // Check that we got exactly one job + args = flags.Args() + if len(args) != 1 { + c.Ui.Error(c.Help()) + return 1 + } + jobID := args[0] + + // Get the HTTP client + client, err := c.Meta.Client() + if err != nil { + c.Ui.Error(fmt.Sprintf("Error initializing client: %s", err)) + return 1 + } + + // Check if the job exists + if _, _, err := client.Jobs().Info(jobID, nil); err != nil { + c.Ui.Error(fmt.Sprintf("Error deregistering job: %s", err)) + return 1 + } + + // Invoke the stop + evalID, _, err := client.Jobs().Deregister(jobID, nil) + if err != nil { + c.Ui.Error(fmt.Sprintf("Error deregistering job: %s", err)) + return 1 + } + + if monitor { + mon := newMonitor(c.Ui, client) + return mon.monitor(evalID) + } + + return 0 +} diff --git a/command/stop_test.go b/command/stop_test.go new file mode 100644 index 000000000..2195cbf8a --- /dev/null +++ b/command/stop_test.go @@ -0,0 +1,46 @@ +package command + +import ( + "strings" + "testing" + + "github.com/mitchellh/cli" +) + +func TestStopCommand_Implements(t *testing.T) { + var _ cli.Command = &StopCommand{} +} + +func TestStopCommand_Fails(t *testing.T) { + srv, _, url := testServer(t, nil) + defer srv.Stop() + + ui := new(cli.MockUi) + cmd := &StopCommand{Meta: Meta{Ui: ui}} + + // Fails on misuse + if code := cmd.Run([]string{"some", "bad", "args"}); code != 1 { + t.Fatalf("expected exit code 1, got: %d", code) + } + if out := ui.ErrorWriter.String(); !strings.Contains(out, cmd.Help()) { + t.Fatalf("expected help output, got: %s", out) + } + ui.ErrorWriter.Reset() + + // Fails on non-existent job ID + if code := cmd.Run([]string{"-address=" + url, "nope"}); code != 1 { + t.Fatalf("expect exit 1, got: %d", code) + } + if out := ui.ErrorWriter.String(); !strings.Contains(out, "not found") { + t.Fatalf("expect not found error, got: %s", out) + } + ui.ErrorWriter.Reset() + + // Fails on connection failure + if code := cmd.Run([]string{"-address=nope", "nope"}); code != 1 { + t.Fatalf("expected exit code 1, got: %d", code) + } + if out := ui.ErrorWriter.String(); !strings.Contains(out, "Error deregistering job") { + t.Fatalf("expected failed query error, got: %s", out) + } +} diff --git a/commands.go b/commands.go index 7c804a912..921606307 100644 --- a/commands.go +++ b/commands.go @@ -94,6 +94,12 @@ func Commands(metaPtr *command.Meta) map[string]cli.CommandFactory { }, nil }, + "stop": func() (cli.Command, error) { + return &command.StopCommand{ + Meta: meta, + }, nil + }, + "version": func() (cli.Command, error) { ver := Version rel := VersionPrerelease