Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds modify time to cli output #3449

Merged
merged 2 commits into from
Oct 28, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion command/alloc_status.go
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,16 @@ func (c *AllocStatusCommand) Run(args []string) int {
}

func formatAllocBasicInfo(alloc *api.Allocation, client *api.Client, uuidLength int, verbose bool) (string, error) {
var formattedCreateTime, formattedModifyTime string

if verbose {
formattedCreateTime = formatUnixNanoTime(alloc.CreateTime)
formattedModifyTime = formatUnixNanoTime(alloc.ModifyTime)
} else {
formattedCreateTime = prettyTimeDiff(time.Unix(0, alloc.CreateTime), time.Now())
formattedModifyTime = prettyTimeDiff(time.Unix(0, alloc.ModifyTime), time.Now())
}

basic := []string{
fmt.Sprintf("ID|%s", limit(alloc.ID, uuidLength)),
fmt.Sprintf("Eval ID|%s", limit(alloc.EvalID, uuidLength)),
Expand All @@ -225,7 +235,8 @@ func formatAllocBasicInfo(alloc *api.Allocation, client *api.Client, uuidLength
fmt.Sprintf("Client Description|%s", alloc.ClientDescription),
fmt.Sprintf("Desired Status|%s", alloc.DesiredStatus),
fmt.Sprintf("Desired Description|%s", alloc.DesiredDescription),
fmt.Sprintf("Created At|%s", formatUnixNanoTime(alloc.CreateTime)),
fmt.Sprintf("Created|%s", formattedCreateTime),
fmt.Sprintf("Modified|%s", formattedModifyTime),
}

if alloc.DeploymentID != "" {
Expand Down
17 changes: 11 additions & 6 deletions command/alloc_status_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,9 +128,14 @@ func TestAllocStatusCommand_Run(t *testing.T) {
t.Fatalf("expected exit 0, got: %d", code)
}
out := ui.OutputWriter.String()
if !strings.Contains(out, "Created At") {
t.Fatalf("expected to have 'Created At' but saw: %s", out)
if !strings.Contains(out, "Created") {
t.Fatalf("expected to have 'Created' but saw: %s", out)
}

if !strings.Contains(out, "Modified") {
t.Fatalf("expected to have 'Modified' but saw: %s", out)
}

ui.OutputWriter.Reset()

if code := cmd.Run([]string{"-address=" + url, "-verbose", allocId1}); code != 0 {
Expand All @@ -140,8 +145,8 @@ func TestAllocStatusCommand_Run(t *testing.T) {
if !strings.Contains(out, allocId1) {
t.Fatal("expected to find alloc id in output")
}
if !strings.Contains(out, "Created At") {
t.Fatalf("expected to have 'Created At' but saw: %s", out)
if !strings.Contains(out, "Created") {
t.Fatalf("expected to have 'Created' but saw: %s", out)
}
ui.OutputWriter.Reset()

Expand All @@ -150,8 +155,8 @@ func TestAllocStatusCommand_Run(t *testing.T) {
t.Fatalf("expected exit 0, got: %d", code)
}
out = ui.OutputWriter.String()
if !strings.Contains(out, "Created At") {
t.Fatalf("expected to have 'Created At' but saw: %s", out)
if !strings.Contains(out, "Created") {
t.Fatalf("expected to have 'Created' but saw: %s", out)
}
ui.OutputWriter.Reset()

Expand Down
110 changes: 110 additions & 0 deletions command/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,116 @@ func formatTimeDifference(first, second time.Time, d time.Duration) string {
return second.Truncate(d).Sub(first.Truncate(d)).String()
}

// fmtInt formats v into the tail of buf.
// It returns the index where the output begins.
func fmtInt(buf []byte, v uint64) int {
w := len(buf)
for v > 0 {
w--
buf[w] = byte(v%10) + '0'
v /= 10
}
return w
}

// prettyTimeDiff prints a human readable time difference.
// It uses abbreviated forms for each period - s for seconds, m for minutes, h for hours,
// d for days, mo for months, and y for years. Time difference is rounded to the nearest second,
// and the top two least granular periods are returned. For example, if the time difference
// is 10 months, 12 days, 3 hours and 2 seconds, the string "10mo12d" is returned. Zero values return the empty string
func prettyTimeDiff(first, second time.Time) string {
// handle zero values
if first.Second() == 0 {
return ""
}
// round to the nearest second
first = first.Round(time.Second)
second = second.Round(time.Second)

// calculate time difference in seconds
d := second.Sub(first)
u := uint64(d.Seconds())

var buf [32]byte
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I used a buffer for this similar to Duration.String() to prevent unnecessary allocations as we build up the output string.

w := len(buf)
secs := u % 60

// track indexes of various periods
var indexes []int

if secs > 0 {
w--
buf[w] = 's'
// u is now seconds
w = fmtInt(buf[:w], secs)
indexes = append(indexes, w)
}
u /= 60
// u is now minutes
if u > 0 {
mins := u % 60
if mins > 0 {
w--
buf[w] = 'm'
w = fmtInt(buf[:w], mins)
indexes = append(indexes, w)
}
u /= 60
// u is now hours
if u > 0 {
hrs := u % 24
if hrs > 0 {
w--
buf[w] = 'h'
w = fmtInt(buf[:w], hrs)
indexes = append(indexes, w)
}
u /= 24
}
// u is now days
if u > 0 {
days := u % 30
if days > 0 {
w--
buf[w] = 'd'
w = fmtInt(buf[:w], days)
indexes = append(indexes, w)
}
u /= 30
}
// u is now months
if u > 0 {
months := u % 12
if months > 0 {
w--
buf[w] = 'o'
w--
buf[w] = 'm'
w = fmtInt(buf[:w], months)
indexes = append(indexes, w)
}
u /= 12
}
// u is now years
if u > 0 {
w--
buf[w] = 'y'
w = fmtInt(buf[:w], u)
indexes = append(indexes, w)
}
}
start := w
end := len(buf)

// truncate to the first two periods
num_periods := len(indexes)
if num_periods > 2 {
end = indexes[num_periods-3]
}
return string(buf[start:end]) + " ago"

}

// getLocalNodeID returns the node ID of the local Nomad Client and an error if
// it couldn't be determined or the Agent is not running in Client mode.
func getLocalNodeID(client *api.Client) (string, error) {
Expand Down
32 changes: 32 additions & 0 deletions command/helpers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -294,3 +294,35 @@ func TestJobGetter_HTTPServer(t *testing.T) {
t.Fatalf("Unexpected file")
}
}

func TestPrettyTimeDiff(t *testing.T) {
test_cases := []struct {
d time.Duration
exp string
}{
{-740 * time.Second, "12m20s ago"},
{-12 * time.Minute, "12m ago"},
{-60 * time.Minute, "1h ago"},
{-80 * time.Minute, "1h20m ago"},
{-6 * time.Hour, "6h ago"},
{-22165 * time.Second, "6h9m ago"},
{-100 * time.Hour, "4d4h ago"},
{-438000 * time.Minute, "10mo4d ago"},
{-20460 * time.Hour, "2y4mo ago"},
}
for _, tc := range test_cases {
t2 := time.Now().Add(tc.d)
out := prettyTimeDiff(t2, time.Now())
if out != tc.exp {
t.Fatalf("expected :%v but got :%v", tc.exp, out)
}
}

var t1 time.Time
out := prettyTimeDiff(t1, time.Now())

if out != "" {
t.Fatalf("Expected empty output but got:%v", out)
}

}
16 changes: 10 additions & 6 deletions command/job_status.go
Original file line number Diff line number Diff line change
Expand Up @@ -406,29 +406,33 @@ func formatAllocListStubs(stubs []*api.AllocationListStub, verbose bool, uuidLen

allocs := make([]string, len(stubs)+1)
if verbose {
allocs[0] = "ID|Eval ID|Node ID|Task Group|Version|Desired|Status|Created At"
allocs[0] = "ID|Eval ID|Node ID|Task Group|Version|Desired|Status|Created|Modified"
for i, alloc := range stubs {
allocs[i+1] = fmt.Sprintf("%s|%s|%s|%s|%d|%s|%s|%s",
allocs[i+1] = fmt.Sprintf("%s|%s|%s|%s|%d|%s|%s|%s|%s",
limit(alloc.ID, uuidLength),
limit(alloc.EvalID, uuidLength),
limit(alloc.NodeID, uuidLength),
alloc.TaskGroup,
alloc.JobVersion,
alloc.DesiredStatus,
alloc.ClientStatus,
formatUnixNanoTime(alloc.CreateTime))
formatUnixNanoTime(alloc.CreateTime),
formatUnixNanoTime(alloc.ModifyTime))
}
} else {
allocs[0] = "ID|Node ID|Task Group|Version|Desired|Status|Created At"
allocs[0] = "ID|Node ID|Task Group|Version|Desired|Status|Created|Modified"
for i, alloc := range stubs {
allocs[i+1] = fmt.Sprintf("%s|%s|%s|%d|%s|%s|%s",
createTimePretty := prettyTimeDiff(time.Unix(0, alloc.CreateTime), time.Now())
modTimePretty := prettyTimeDiff(time.Unix(0, alloc.ModifyTime), time.Now())
allocs[i+1] = fmt.Sprintf("%s|%s|%s|%d|%s|%s|%s|%s",
limit(alloc.ID, uuidLength),
limit(alloc.NodeID, uuidLength),
alloc.TaskGroup,
alloc.JobVersion,
alloc.DesiredStatus,
alloc.ClientStatus,
formatUnixNanoTime(alloc.CreateTime))
createTimePretty,
modTimePretty)
}
}

Expand Down
13 changes: 12 additions & 1 deletion command/job_status_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,9 +113,12 @@ func TestJobStatusCommand_Run(t *testing.T) {
if !strings.Contains(out, "Allocations") {
t.Fatalf("should dump allocations")
}
if !strings.Contains(out, "Created At") {
if !strings.Contains(out, "Created") {
t.Fatal("should have created header")
}
if !strings.Contains(out, "Modified") {
t.Fatal("should have modified header")
}
ui.ErrorWriter.Reset()
ui.OutputWriter.Reset()

Expand All @@ -138,6 +141,14 @@ func TestJobStatusCommand_Run(t *testing.T) {
if !strings.Contains(out, "job1_sfx") || strings.Contains(out, "job2_sfx") {
t.Fatalf("expected only job1_sfx, got: %s", out)
}

if !strings.Contains(out, "Created") {
t.Fatal("should have created header")
}

if !strings.Contains(out, "Modified") {
t.Fatal("should have modified header")
}
ui.OutputWriter.Reset()

// Query in short view mode
Expand Down