diff --git a/command/alloc_status.go b/command/alloc_status.go deleted file mode 100644 index 0c6e78d4f..000000000 --- a/command/alloc_status.go +++ /dev/null @@ -1,92 +0,0 @@ -package command - -import ( - "fmt" - "strings" - - "github.com/hashicorp/nomad/api" - "github.com/mitchellh/cli" -) - -type AllocStatusCommand struct { - Meta -} - -func (c *AllocStatusCommand) Help() string { - helpText := ` -Usage: nomad alloc-status [options] - - Display status and diagnostic information about an allocation. - -General Options: - - ` + generalOptionsUsage() - return strings.TrimSpace(helpText) -} - -func (c *AllocStatusCommand) Synopsis() string { - return "Display allocation status information and metrics" -} - -func (c *AllocStatusCommand) Run(args []string) int { - flags := c.Meta.FlagSet("alloc-status", FlagSetClient) - flags.Usage = func() { c.Ui.Output(c.Help()) } - if err := flags.Parse(args); err != nil { - return 1 - } - - // Check that we either got no jobs or exactly one. - args = flags.Args() - if len(args) != 1 { - c.Ui.Error(c.Help()) - return 1 - } - allocID := 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 - } - - // Query the allocation - alloc, _, err := client.Allocations().Info(allocID, nil) - if err != nil { - c.Ui.Error(fmt.Sprintf("Error querying allocation: %s", err)) - return 1 - } - - // Dump any allocation data - dumpAllocStatus(c.Ui, alloc) - return 0 -} - -// dumpAllocStatus is a helper to generate a more user-friendly error message -// for scheduling failures, displaying a high level status of why the job -// could not be scheduled out. -func dumpAllocStatus(ui cli.Ui, alloc *api.Allocation) { - // Print filter stats - ui.Output(fmt.Sprintf("Allocation %q status %q (%d/%d nodes filtered)", - alloc.ID, alloc.ClientStatus, - alloc.Metrics.NodesFiltered, alloc.Metrics.NodesEvaluated)) - - // Print exhaustion info - if ne := alloc.Metrics.NodesExhausted; ne > 0 { - ui.Output(fmt.Sprintf(" * Resources exhausted on %d nodes", ne)) - } - for class, num := range alloc.Metrics.ClassExhausted { - ui.Output(fmt.Sprintf(" * Class %q exhausted on %d nodes", class, num)) - } - for dim, num := range alloc.Metrics.DimensionExhausted { - ui.Output(fmt.Sprintf(" * Dimension %q exhausted on %d nodes", dim, num)) - } - - // Print filter info - for class, num := range alloc.Metrics.ClassFiltered { - ui.Output(fmt.Sprintf(" * Class %q filtered %d nodes", class, num)) - } - for cs, num := range alloc.Metrics.ConstraintFiltered { - ui.Output(fmt.Sprintf(" * Constraint %q filtered %d nodes", cs, num)) - } -} diff --git a/command/alloc_status_test.go b/command/alloc_status_test.go deleted file mode 100644 index eb20102df..000000000 --- a/command/alloc_status_test.go +++ /dev/null @@ -1,87 +0,0 @@ -package command - -import ( - "strings" - "testing" - - "github.com/hashicorp/nomad/api" - "github.com/hashicorp/nomad/nomad/structs" - "github.com/mitchellh/cli" -) - -func TestAllocStatusCommand_Implements(t *testing.T) { - var _ cli.Command = &AllocStatusCommand{} -} - -func TestAllocStatusCommand_Fails(t *testing.T) { - ui := new(cli.MockUi) - cmd := &AllocStatusCommand{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 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 querying allocation") { - t.Fatalf("expected failed query error, got: %s", out) - } -} - -func TestAllocStatus_DumpAllocStatus(t *testing.T) { - ui := new(cli.MockUi) - - // Create an allocation and dump its status to the UI - alloc := &api.Allocation{ - ID: "alloc1", - TaskGroup: "group1", - ClientStatus: structs.AllocClientStatusRunning, - Metrics: &api.AllocationMetric{ - NodesEvaluated: 10, - NodesFiltered: 5, - NodesExhausted: 1, - DimensionExhausted: map[string]int{ - "cpu": 1, - }, - ConstraintFiltered: map[string]int{ - "$attr.kernel.name = linux": 1, - }, - ClassExhausted: map[string]int{ - "web-large": 1, - }, - }, - } - dumpAllocStatus(ui, alloc) - - // Check the output - out := ui.OutputWriter.String() - if !strings.Contains(out, "alloc1") { - t.Fatalf("missing alloc\n\n%s", out) - } - if !strings.Contains(out, structs.AllocClientStatusRunning) { - t.Fatalf("missing status\n\n%s", out) - } - if !strings.Contains(out, "5/10") { - t.Fatalf("missing filter stats\n\n%s", out) - } - if !strings.Contains( - out, `Constraint "$attr.kernel.name = linux" filtered 1 nodes`) { - t.Fatalf("missing constraint\n\n%s", out) - } - if !strings.Contains(out, "Resources exhausted on 1 nodes") { - t.Fatalf("missing resource exhaustion\n\n%s", out) - } - if !strings.Contains(out, `Class "web-large" exhausted on 1 nodes`) { - t.Fatalf("missing class exhaustion\n\n%s", out) - } - if !strings.Contains(out, `Dimension "cpu" exhausted on 1 nodes`) { - t.Fatalf("missing dimension exhaustion\n\n%s", out) - } -} diff --git a/command/monitor.go b/command/monitor.go index 3d9c5ccad..e3e715c75 100644 --- a/command/monitor.go +++ b/command/monitor.go @@ -245,3 +245,32 @@ func (m *monitor) monitor(evalID string) int { return 0 } + +// dumpAllocStatus is a helper to generate a more user-friendly error message +// for scheduling failures, displaying a high level status of why the job +// could not be scheduled out. +func dumpAllocStatus(ui cli.Ui, alloc *api.Allocation) { + // Print filter stats + ui.Output(fmt.Sprintf("Allocation %q status %q (%d/%d nodes filtered)", + alloc.ID, alloc.ClientStatus, + alloc.Metrics.NodesFiltered, alloc.Metrics.NodesEvaluated)) + + // Print exhaustion info + if ne := alloc.Metrics.NodesExhausted; ne > 0 { + ui.Output(fmt.Sprintf(" * Resources exhausted on %d nodes", ne)) + } + for class, num := range alloc.Metrics.ClassExhausted { + ui.Output(fmt.Sprintf(" * Class %q exhausted on %d nodes", class, num)) + } + for dim, num := range alloc.Metrics.DimensionExhausted { + ui.Output(fmt.Sprintf(" * Dimension %q exhausted on %d nodes", dim, num)) + } + + // Print filter info + for class, num := range alloc.Metrics.ClassFiltered { + ui.Output(fmt.Sprintf(" * Class %q filtered %d nodes", class, num)) + } + for cs, num := range alloc.Metrics.ConstraintFiltered { + ui.Output(fmt.Sprintf(" * Constraint %q filtered %d nodes", cs, num)) + } +} diff --git a/command/monitor_test.go b/command/monitor_test.go index 81f88389a..562d1a0a4 100644 --- a/command/monitor_test.go +++ b/command/monitor_test.go @@ -262,3 +262,54 @@ func TestMonitor_Monitor(t *testing.T) { t.Fatalf("missing final status\n\n%s", out) } } + +func TestMonitor_DumpAllocStatus(t *testing.T) { + ui := new(cli.MockUi) + + // Create an allocation and dump its status to the UI + alloc := &api.Allocation{ + ID: "alloc1", + TaskGroup: "group1", + ClientStatus: structs.AllocClientStatusRunning, + Metrics: &api.AllocationMetric{ + NodesEvaluated: 10, + NodesFiltered: 5, + NodesExhausted: 1, + DimensionExhausted: map[string]int{ + "cpu": 1, + }, + ConstraintFiltered: map[string]int{ + "$attr.kernel.name = linux": 1, + }, + ClassExhausted: map[string]int{ + "web-large": 1, + }, + }, + } + dumpAllocStatus(ui, alloc) + + // Check the output + out := ui.OutputWriter.String() + if !strings.Contains(out, "alloc1") { + t.Fatalf("missing alloc\n\n%s", out) + } + if !strings.Contains(out, structs.AllocClientStatusRunning) { + t.Fatalf("missing status\n\n%s", out) + } + if !strings.Contains(out, "5/10") { + t.Fatalf("missing filter stats\n\n%s", out) + } + if !strings.Contains( + out, `Constraint "$attr.kernel.name = linux" filtered 1 nodes`) { + t.Fatalf("missing constraint\n\n%s", out) + } + if !strings.Contains(out, "Resources exhausted on 1 nodes") { + t.Fatalf("missing resource exhaustion\n\n%s", out) + } + if !strings.Contains(out, `Class "web-large" exhausted on 1 nodes`) { + t.Fatalf("missing class exhaustion\n\n%s", out) + } + if !strings.Contains(out, `Dimension "cpu" exhausted on 1 nodes`) { + t.Fatalf("missing dimension exhaustion\n\n%s", out) + } +} diff --git a/commands.go b/commands.go index 71fab0f78..921606307 100644 --- a/commands.go +++ b/commands.go @@ -24,12 +24,6 @@ func Commands(metaPtr *command.Meta) map[string]cli.CommandFactory { } return map[string]cli.CommandFactory{ - "alloc-status": func() (cli.Command, error) { - return &command.AllocStatusCommand{ - Meta: meta, - }, nil - }, - "agent": func() (cli.Command, error) { return &agent.Command{ Revision: GitCommit,