diff --git a/command/alloc_status.go b/command/alloc_status.go index 46f1f18db6b3..9c60ce51e18e 100644 --- a/command/alloc_status.go +++ b/command/alloc_status.go @@ -268,7 +268,7 @@ func (c *AllocStatusCommand) outputTaskStatus(state *api.TaskState) { size := len(state.Events) for i, event := range state.Events { - formatedTime := c.formatUnixNanoTime(event.Time) + formatedTime := formatUnixNanoTime(event.Time) // Build up the description based on the event type. var desc string @@ -474,7 +474,7 @@ func (c *AllocStatusCommand) shortTaskStatus(alloc *api.Allocation) { if l != 0 { last := state.Events[l-1] lastEvent = last.Type - lastTime = c.formatUnixNanoTime(last.Time) + lastTime = formatUnixNanoTime(last.Time) } tasks = append(tasks, fmt.Sprintf("%s|%s|%s|%s", @@ -504,9 +504,3 @@ func (c *AllocStatusCommand) sortedTaskStateIterator(m map[string]*api.TaskState close(output) return output } - -// formatUnixNanoTime is a helper for formating time for output. -func (c *AllocStatusCommand) formatUnixNanoTime(nano int64) string { - t := time.Unix(0, nano) - return formatTime(t) -} diff --git a/command/helpers.go b/command/helpers.go index b9c4a6be7af2..123f4b70e0ac 100644 --- a/command/helpers.go +++ b/command/helpers.go @@ -51,6 +51,12 @@ func formatTime(t time.Time) string { return t.Format("01/02/06 15:04:05 MST") } +// formatUnixNanoTime is a helper for formatting time for output. +func formatUnixNanoTime(nano int64) string { + t := time.Unix(0, nano) + return formatTime(t) +} + // formatTimeDifference takes two times and determines their duration difference // truncating to a passed unit. // E.g. formatTimeDifference(first=1m22s33ms, second=1m28s55ms, time.Second) -> 6s diff --git a/command/status.go b/command/status.go index dcca9c1bd874..8b94997a5859 100644 --- a/command/status.go +++ b/command/status.go @@ -20,8 +20,9 @@ const ( type StatusCommand struct { Meta - length int - showEvals, verbose bool + length int + evals bool + verbose bool } func (c *StatusCommand) Help() string { @@ -60,7 +61,7 @@ func (c *StatusCommand) Run(args []string) int { flags := c.Meta.FlagSet("status", FlagSetClient) flags.Usage = func() { c.Ui.Output(c.Help()) } flags.BoolVar(&short, "short", false, "") - flags.BoolVar(&c.showEvals, "evals", false, "") + flags.BoolVar(&c.evals, "evals", false, "") flags.BoolVar(&c.verbose, "verbose", false, "") if err := flags.Parse(args); err != nil { @@ -95,22 +96,12 @@ func (c *StatusCommand) Run(args []string) int { return 1 } - // No output if we have no jobs if len(jobs) == 0 { + // No output if we have no jobs c.Ui.Output("No running jobs") - return 0 + } else { + c.Ui.Output(createStatusListOutput(jobs)) } - - out := make([]string, len(jobs)+1) - out[0] = "ID|Type|Priority|Status" - for i, job := range jobs { - out[i+1] = fmt.Sprintf("%s|%s|%d|%s", - job.ID, - job.Type, - job.Priority, - job.Status) - } - c.Ui.Output(formatList(out)) return 0 } @@ -126,16 +117,7 @@ func (c *StatusCommand) Run(args []string) int { return 1 } if len(jobs) > 1 && strings.TrimSpace(jobID) != jobs[0].ID { - out := make([]string, len(jobs)+1) - out[0] = "ID|Type|Priority|Status" - for i, job := range jobs { - out[i+1] = fmt.Sprintf("%s|%s|%d|%s", - job.ID, - job.Type, - job.Priority, - job.Status) - } - c.Ui.Output(fmt.Sprintf("Prefix matched multiple jobs\n\n%s", formatList(out))) + c.Ui.Output(fmt.Sprintf("Prefix matched multiple jobs\n\n%s", createStatusListOutput(jobs))) return 0 } // Prefix lookup matched a single job @@ -306,7 +288,7 @@ func (c *StatusCommand) outputJobInfo(client *api.Client, job *api.Job) error { } } - if c.verbose || c.showEvals { + if c.verbose || c.evals { c.Ui.Output(c.Colorize().Color("\n[bold]Evaluations[reset]")) c.Ui.Output(formatList(evals)) } @@ -319,15 +301,16 @@ func (c *StatusCommand) outputJobInfo(client *api.Client, job *api.Job) error { c.Ui.Output(c.Colorize().Color("\n[bold]Allocations[reset]")) if len(jobAllocs) > 0 { allocs = make([]string, len(jobAllocs)+1) - allocs[0] = "ID|Eval ID|Node ID|Task Group|Desired|Status" + allocs[0] = "ID|Eval ID|Node ID|Task Group|Desired|Status|Created At" for i, alloc := range jobAllocs { - allocs[i+1] = fmt.Sprintf("%s|%s|%s|%s|%s|%s", + allocs[i+1] = fmt.Sprintf("%s|%s|%s|%s|%s|%s|%s", limit(alloc.ID, c.length), limit(alloc.EvalID, c.length), limit(alloc.NodeID, c.length), alloc.TaskGroup, alloc.DesiredStatus, - alloc.ClientStatus) + alloc.ClientStatus, + formatUnixNanoTime(alloc.CreateTime)) } c.Ui.Output(formatList(allocs)) @@ -379,3 +362,17 @@ func convertApiJob(in *api.Job) (*structs.Job, error) { } return structJob, nil } + +// list general information about a list of jobs +func createStatusListOutput(jobs []*api.JobListStub) string { + out := make([]string, len(jobs)+1) + out[0] = "ID|Type|Priority|Status" + for i, job := range jobs { + out[i+1] = fmt.Sprintf("%s|%s|%d|%s", + job.ID, + job.Type, + job.Priority, + job.Status) + } + return formatList(out) +} diff --git a/command/status_test.go b/command/status_test.go index 270d913571b3..6d6801b6dd52 100644 --- a/command/status_test.go +++ b/command/status_test.go @@ -4,6 +4,8 @@ import ( "strings" "testing" + "github.com/hashicorp/nomad/api" + "github.com/hashicorp/nomad/testutil" "github.com/mitchellh/cli" ) @@ -12,7 +14,9 @@ func TestStatusCommand_Implements(t *testing.T) { } func TestStatusCommand_Run(t *testing.T) { - srv, client, url := testServer(t, nil) + srv, client, url := testServer(t, func(c *testutil.TestServerConfig) { + c.DevMode = true + }) defer srv.Stop() ui := new(cli.MockUi) @@ -33,14 +37,22 @@ func TestStatusCommand_Run(t *testing.T) { // Register two jobs job1 := testJob("job1_sfx") - evalId, _, err := client.Jobs().Register(job1, nil) + evalId1, _, err := client.Jobs().Register(job1, nil) if err != nil { t.Fatalf("err: %s", err) } + if code := waitForSuccess(ui, client, fullId, t, evalId1); code != 0 { + t.Fatalf("status code non zero saw %d", code) + } + job2 := testJob("job2_sfx") - if _, _, err := client.Jobs().Register(job2, nil); err != nil { + evalId2, _, err := client.Jobs().Register(job2, nil) + if err != nil { t.Fatalf("err: %s", err) } + if code := waitForSuccess(ui, client, fullId, t, evalId2); code != 0 { + t.Fatalf("status code non zero saw %d", code) + } // Query again and check the result if code := cmd.Run([]string{"-address=" + url}); code != 0 { @@ -98,6 +110,9 @@ func TestStatusCommand_Run(t *testing.T) { if !strings.Contains(out, "Allocations") { t.Fatalf("should dump allocations") } + if !strings.Contains(out, "Created At") { + t.Fatal("should have created header") + } ui.OutputWriter.Reset() // Query jobs with prefix match @@ -134,7 +149,7 @@ func TestStatusCommand_Run(t *testing.T) { if strings.Contains(out, "Allocations") { t.Fatalf("should not dump allocations") } - if strings.Contains(out, evalId) { + if strings.Contains(out, evalId1) { t.Fatalf("should not contain full identifiers, got %s", out) } ui.OutputWriter.Reset() @@ -144,7 +159,7 @@ func TestStatusCommand_Run(t *testing.T) { t.Fatalf("expected exit 0, got: %d", code) } out = ui.OutputWriter.String() - if !strings.Contains(out, evalId) { + if !strings.Contains(out, evalId1) { t.Fatalf("should contain full identifiers, got %s", out) } } @@ -170,3 +185,9 @@ func TestStatusCommand_Fails(t *testing.T) { t.Fatalf("expected failed query error, got: %s", out) } } + +func waitForSuccess(ui cli.Ui, client *api.Client, length int, t *testing.T, evalId string) int { + mon := newMonitor(ui, client, length) + monErr := mon.monitor(evalId, false) + return monErr +} diff --git a/command/util_test.go b/command/util_test.go index 2eb2a743314b..7671d933c143 100644 --- a/command/util_test.go +++ b/command/util_test.go @@ -39,7 +39,7 @@ func testServer( } func testJob(jobID string) *api.Job { - task := api.NewTask("task1", "exec"). + task := api.NewTask("task1", "raw_exec"). SetConfig("command", "/bin/sleep"). Require(&api.Resources{ MemoryMB: 256, diff --git a/website/source/docs/commands/status.html.md.erb b/website/source/docs/commands/status.html.md.erb index 316ea308f3a3..f1c69235f753 100644 --- a/website/source/docs/commands/status.html.md.erb +++ b/website/source/docs/commands/status.html.md.erb @@ -80,8 +80,8 @@ Task Group Queued Starting Running Failed Complete Lost cache 0 0 1 0 0 0 Allocations -ID Eval ID Node ID Task Group Desired Status -24cfd201 81efc2fa 8d0331e9 cache run running +ID Eval ID Node ID Task Group Desired Status Created At +24cfd201 81efc2fa 8d0331e9 cache run running 08/08/16 21:03:19 CDT ``` Full status information of a job with placement failures: @@ -106,12 +106,12 @@ Task Group "cache": * Dimension "cpu exhausted" exhausted on 1 nodes Allocations -ID Eval ID Node ID Task Group Desired Status -0b8b9e37 8bf94335 8d0331e9 cache run running -b206088c 8bf94335 8d0331e9 cache run running -b82f58b6 8bf94335 8d0331e9 cache run running -ed3665f5 8bf94335 8d0331e9 cache run running -24cfd201 8bf94335 8d0331e9 cache run running +ID Eval ID Node ID Task Group Desired Status Created At +0b8b9e37 8bf94335 8d0331e9 cache run running 08/08/16 21:03:19 CDT +b206088c 8bf94335 8d0331e9 cache run running 08/08/16 21:03:18 CDT +b82f58b6 8bf94335 8d0331e9 cache run running 08/08/16 21:03:17 CDT +ed3665f5 8bf94335 8d0331e9 cache run running 08/08/16 21:03:21 CDT +24cfd201 8bf94335 8d0331e9 cache run running 08/08/16 21:03:19 CDT ``` Full status information showing evaluations with a placement failure. The in @@ -145,10 +145,10 @@ Task Group "cache": * Dimension "cpu exhausted" exhausted on 1 nodes Allocations -ID Eval ID Node ID Task Group Desired Status -0b8b9e37 8bf94335 8d0331e9 cache run running -b206088c 8bf94335 8d0331e9 cache run running -b82f58b6 8bf94335 8d0331e9 cache run running -ed3665f5 8bf94335 8d0331e9 cache run running -24cfd201 8bf94335 8d0331e9 cache run running +ID Eval ID Node ID Task Group Desired Status Created At +0b8b9e37 8bf94335 8d0331e9 cache run running 08/08/16 21:03:19 CDT +b206088c 8bf94335 8d0331e9 cache run running 08/08/16 21:03:19 CDT +b82f58b6 8bf94335 8d0331e9 cache run running 08/08/16 21:03:19 CDT +ed3665f5 8bf94335 8d0331e9 cache run running 08/08/16 21:03:19 CDT +24cfd201 8bf94335 8d0331e9 cache run running 08/08/16 21:03:19 CDT ``` diff --git a/website/source/docs/jobops/inspecting.html.md b/website/source/docs/jobops/inspecting.html.md index 30bed5ae1f49..9b18f2cfd980 100644 --- a/website/source/docs/jobops/inspecting.html.md +++ b/website/source/docs/jobops/inspecting.html.md @@ -39,14 +39,14 @@ Task Group "cache": * Dimension "cpu exhausted" exhausted on 1 nodes Allocations -ID Eval ID Node ID Task Group Desired Status -12681940 8e38e6cf 4beef22f cache run running -395c5882 8e38e6cf 4beef22f cache run running -4d7c6f84 8e38e6cf 4beef22f cache run running -843b07b8 8e38e6cf 4beef22f cache run running -a8bc6d3e 8e38e6cf 4beef22f cache run running -b0beb907 8e38e6cf 4beef22f cache run running -da21c1fd 8e38e6cf 4beef22f cache run running +ID Eval ID Node ID Task Group Desired Status Created At +12681940 8e38e6cf 4beef22f cache run running 08/08/16 21:03:19 CDT +395c5882 8e38e6cf 4beef22f cache run running 08/08/16 21:03:19 CDT +4d7c6f84 8e38e6cf 4beef22f cache run running 08/08/16 21:03:19 CDT +843b07b8 8e38e6cf 4beef22f cache run running 08/08/16 21:03:19 CDT +a8bc6d3e 8e38e6cf 4beef22f cache run running 08/08/16 21:03:19 CDT +b0beb907 8e38e6cf 4beef22f cache run running 08/08/16 21:03:19 CDT +da21c1fd 8e38e6cf 4beef22f cache run running 08/08/16 21:03:19 CDT ``` In the above example we see that the job has a "blocked" evaluation that is in diff --git a/website/source/intro/getting-started/cluster.html.md b/website/source/intro/getting-started/cluster.html.md index bfa0edcdb6a7..31535df93f02 100644 --- a/website/source/intro/getting-started/cluster.html.md +++ b/website/source/intro/getting-started/cluster.html.md @@ -185,10 +185,10 @@ Status = running Periodic = false Allocations -ID Eval ID Node ID Task Group Desired Status -501154ac 8e0a7cf9 c887deef cache run running -7e2b3900 8e0a7cf9 fca62612 cache run running -9c66fcaf 8e0a7cf9 c887deef cache run running +ID Eval ID Node ID Task Group Desired Status Created At +501154ac 8e0a7cf9 c887deef cache run running 08/08/16 21:03:19 CDT +7e2b3900 8e0a7cf9 fca62612 cache run running 08/08/16 21:03:19 CDT +9c66fcaf 8e0a7cf9 c887deef cache run running 08/08/16 21:03:19 CDT ``` We can see that all our tasks have been allocated and are running. diff --git a/website/source/intro/getting-started/jobs.html.md b/website/source/intro/getting-started/jobs.html.md index 86800b64b43d..df15dd161ded 100644 --- a/website/source/intro/getting-started/jobs.html.md +++ b/website/source/intro/getting-started/jobs.html.md @@ -75,8 +75,8 @@ Task Group Queued Starting Running Failed Complete Lost cache 0 0 1 0 0 0 Allocations -ID Eval ID Node ID Task Group Desired Status -dadcdb81 61b0b423 72687b1a cache run running +ID Eval ID Node ID Task Group Desired Status Created At +dadcdb81 61b0b423 72687b1a cache run running 06/23/16 01:41:13 UTC ``` Here we can see that the result of our evaluation was the creation of an