From 31a3c81c3bd78e3991e9ec0ab2045380d259f330 Mon Sep 17 00:00:00 2001 From: Preetha Appan Date: Mon, 19 Mar 2018 21:42:37 -0500 Subject: [PATCH] Show a section on upcoming delayed evaluations when applicable --- command/job_status.go | 55 ++++++++++++++++++++++++++++++++++++++++ nomad/structs/structs.go | 1 + 2 files changed, 56 insertions(+) diff --git a/command/job_status.go b/command/job_status.go index 55c84e493..154dd4dc2 100644 --- a/command/job_status.go +++ b/command/job_status.go @@ -371,6 +371,8 @@ func (c *JobStatusCommand) outputJobInfo(client *api.Client, job *api.Job) error c.outputFailedPlacements(latestFailedPlacement) } + c.outputReschedulingEvals(client, jobAllocs) + if latestDeployment != nil { c.Ui.Output(c.Colorize().Color("\n[bold]Latest Deployment[reset]")) c.Ui.Output(c.Colorize().Color(c.formatDeployment(latestDeployment))) @@ -536,6 +538,59 @@ func (c *JobStatusCommand) outputJobSummary(client *api.Client, job *api.Job) er return nil } +// outputReschedulingEvals displays eval IDs and time for any +// delayed evaluations by task group +func (c *JobStatusCommand) outputReschedulingEvals(client *api.Client, allocListStubs []*api.AllocationListStub) error { + // Get the most recent alloc ID by task group + + mostRecentAllocs := make(map[string]*api.AllocationListStub) + for _, alloc := range allocListStubs { + a, ok := mostRecentAllocs[alloc.TaskGroup] + if !ok || alloc.ModifyTime > a.ModifyTime { + mostRecentAllocs[alloc.TaskGroup] = alloc + } + } + + followUpEvalIds := make(map[string]string) + for tg, alloc := range mostRecentAllocs { + if alloc.FollowupEvalID != "" { + followUpEvalIds[tg] = alloc.FollowupEvalID + } + } + + if len(followUpEvalIds) == 0 { + return nil + } + // Print the reschedule info section + + var delayedEvalInfos []string + + taskGroups := make([]string, 0, len(followUpEvalIds)) + for taskGroup, _ := range followUpEvalIds { + taskGroups = append(taskGroups, taskGroup) + } + sort.Strings(taskGroups) + var evalDetails []string + for _, taskGroup := range taskGroups { + evalID := followUpEvalIds[taskGroup] + evaluation, _, err := client.Evaluations().Info(evalID, nil) + // Eval time is not critical output, + // so don't return it on errors, if its not set, or its already in the past + if err != nil || evaluation.WaitUntil.IsZero() || time.Now().After(evaluation.WaitUntil) { + continue + } + evalTime := prettyTimeDiff(evaluation.WaitUntil, time.Now()) + evalDetails = append(evalDetails, fmt.Sprintf("%s|%s|%s", taskGroup, evalID, evalTime)) + } + if len(evalDetails) > 0 { // Only show this section if there is pending evals + delayedEvalInfos = append(delayedEvalInfos, "Task Group|Eval ID|Eval Time") + delayedEvalInfos = append(delayedEvalInfos, evalDetails...) + c.Ui.Output(c.Colorize().Color("\n[bold]Upcoming Evaluations[reset]")) + c.Ui.Output(formatList(delayedEvalInfos)) + } + return nil +} + func (c *JobStatusCommand) outputFailedPlacements(failedEval *api.Evaluation) { if failedEval == nil || len(failedEval.FailedTGAllocs) == 0 { return diff --git a/nomad/structs/structs.go b/nomad/structs/structs.go index 6a4fbcf4b..10ec18197 100644 --- a/nomad/structs/structs.go +++ b/nomad/structs/structs.go @@ -5690,6 +5690,7 @@ func (a *Allocation) Stub() *AllocListStub { ClientDescription: a.ClientDescription, TaskStates: a.TaskStates, DeploymentStatus: a.DeploymentStatus, + FollowupEvalID: a.FollowupEvalID, CreateIndex: a.CreateIndex, ModifyIndex: a.ModifyIndex, CreateTime: a.CreateTime,