From 40bc21fa8f46967fa513f6fffa78c814cea28ea5 Mon Sep 17 00:00:00 2001 From: Cameron Davison Date: Thu, 4 Aug 2016 20:36:22 -0500 Subject: [PATCH] add time flag to add created column to allocation --- command/status.go | 22 ++++++++++++++++++-- command/status_test.go | 47 +++++++++++++++++++++++++++++++++++++----- command/util_test.go | 2 +- commands.go | 2 ++ 4 files changed, 65 insertions(+), 8 deletions(-) diff --git a/command/status.go b/command/status.go index 734c8591f..b82a17877 100644 --- a/command/status.go +++ b/command/status.go @@ -23,6 +23,7 @@ type StatusCommand struct { length int evals bool verbose bool + time bool } func (c *StatusCommand) Help() string { @@ -45,6 +46,9 @@ Status Options: -evals Display the evaluations associated with the job. + -time + Display allocation creation time. + -verbose Display full information. ` @@ -63,6 +67,7 @@ func (c *StatusCommand) Run(args []string) int { flags.BoolVar(&short, "short", false, "") flags.BoolVar(&c.evals, "evals", false, "") flags.BoolVar(&c.verbose, "verbose", false, "") + flags.BoolVar(&c.time, "time", false, "") if err := flags.Parse(args); err != nil { return 1 @@ -302,6 +307,9 @@ func (c *StatusCommand) outputJobInfo(client *api.Client, job *api.Job) error { if len(jobAllocs) > 0 { allocs = make([]string, len(jobAllocs)+1) allocs[0] = "ID|Eval ID|Node ID|Task Group|Desired|Status" + if c.time { + allocs[0] += "|Created" + } for i, alloc := range jobAllocs { allocs[i+1] = fmt.Sprintf("%s|%s|%s|%s|%s|%s", limit(alloc.ID, c.length), @@ -310,6 +318,10 @@ func (c *StatusCommand) outputJobInfo(client *api.Client, job *api.Job) error { alloc.TaskGroup, alloc.DesiredStatus, alloc.ClientStatus) + if c.time { + allocs[i+1] += fmt.Sprintf("|%s", + c.formatUnixNanoTime(alloc.CreateTime)) + } } c.Ui.Output(formatList(allocs)) @@ -346,6 +358,12 @@ func (c *StatusCommand) outputFailedPlacements(failedEval *api.Evaluation) { } } +// formatUnixNanoTime is a helper for formatting time for output. +func (c *StatusCommand) formatUnixNanoTime(nano int64) string { + t := time.Unix(0, nano) + return formatTime(t) +} + // convertApiJob is used to take a *api.Job and convert it to an *struct.Job. // This function is just a hammer and probably needs to be revisited. func convertApiJob(in *api.Job) (*structs.Job, error) { @@ -363,7 +381,7 @@ func convertApiJob(in *api.Job) (*structs.Job, error) { } // list general information about a list of jobs -func createStatusListOutput(jobs []*structs.JobListStub) ([]string) { +func createStatusListOutput(jobs []*api.JobListStub) string { out := make([]string, len(jobs)+1) out[0] = "ID|Type|Priority|Status" for i, job := range jobs { @@ -374,4 +392,4 @@ func createStatusListOutput(jobs []*structs.JobListStub) ([]string) { job.Status) } return formatList(out) -} \ No newline at end of file +} diff --git a/command/status_test.go b/command/status_test.go index 270d91357..87cf98b89 100644 --- a/command/status_test.go +++ b/command/status_test.go @@ -5,6 +5,8 @@ import ( "testing" "github.com/mitchellh/cli" + "github.com/hashicorp/nomad/testutil" + "github.com/hashicorp/nomad/api" ) func TestStatusCommand_Implements(t *testing.T) { @@ -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,25 @@ func TestStatusCommand_Run(t *testing.T) { if !strings.Contains(out, "Allocations") { t.Fatalf("should dump allocations") } + if strings.Contains(out, "Created") { + t.Fatal("should not have created header") + } + ui.OutputWriter.Reset() + + // Query a single job in time mode + if code := cmd.Run([]string{"-address=" + url, "-time", "job1_sfx"}); code != 0 { + t.Fatalf("expected exit 0, got: %d", code) + } + out = ui.OutputWriter.String() + if strings.Contains(out, "job2_sfx") || !strings.Contains(out, "job1_sfx") { + t.Fatalf("expected only job1_sfx, got: %s", out) + } + if !strings.Contains(out, "Allocations") { + t.Fatal("should dump allocations") + } + if !strings.Contains(out, "Created") { + t.Fatal("should have created header") + } ui.OutputWriter.Reset() // Query jobs with prefix match @@ -134,7 +165,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 +175,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 +201,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 +} \ No newline at end of file diff --git a/command/util_test.go b/command/util_test.go index 2eb2a7433..7671d933c 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/commands.go b/commands.go index 372ed5375..acef7f16c 100644 --- a/commands.go +++ b/commands.go @@ -94,11 +94,13 @@ func Commands(metaPtr *command.Meta) map[string]cli.CommandFactory { Meta: meta, }, nil }, + "plan": func() (cli.Command, error) { return &command.PlanCommand{ Meta: meta, }, nil }, + "run": func() (cli.Command, error) { return &command.RunCommand{ Meta: meta,