mirror of
https://github.com/kemko/nomad.git
synced 2026-01-01 16:05:42 +03:00
command: remove unnecessary alloc-status command
This commit is contained in:
@@ -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] <allocation>
|
||||
|
||||
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))
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user