diff --git a/command/status.go b/command/status.go index 75e2161d6..5fc9a15c2 100644 --- a/command/status.go +++ b/command/status.go @@ -151,56 +151,97 @@ func (c *StatusCommand) Run(args []string) int { c.Ui.Output(formatKV(basic)) - if !periodic && !short { - var evals, allocs []string + // Exit early + if short { + return 0 + } - // Query the evaluations - jobEvals, _, err := client.Jobs().Evaluations(job.ID, nil) - if err != nil { - c.Ui.Error(fmt.Sprintf("Error querying job evaluations: %s", err)) + // Print periodic job information + if periodic { + if err := c.outputPeriodicInfo(client, job); err != nil { + c.Ui.Error(err.Error()) return 1 } - // Query the allocations - jobAllocs, _, err := client.Jobs().Allocations(job.ID, nil) - if err != nil { - c.Ui.Error(fmt.Sprintf("Error querying job allocations: %s", err)) - return 1 - } + return 0 + } - // Format the evals - evals = make([]string, len(jobEvals)+1) - evals[0] = "ID|Priority|TriggeredBy|Status" - for i, eval := range jobEvals { - evals[i+1] = fmt.Sprintf("%s|%d|%s|%s", - eval.ID, - eval.Priority, - eval.TriggeredBy, - eval.Status) - } - - // Format the allocs - allocs = make([]string, len(jobAllocs)+1) - allocs[0] = "ID|EvalID|NodeID|TaskGroup|Desired|Status" - for i, alloc := range jobAllocs { - allocs[i+1] = fmt.Sprintf("%s|%s|%s|%s|%s|%s", - alloc.ID, - alloc.EvalID, - alloc.NodeID, - alloc.TaskGroup, - alloc.DesiredStatus, - alloc.ClientStatus) - } - - c.Ui.Output("\n==> Evaluations") - c.Ui.Output(formatList(evals)) - c.Ui.Output("\n==> Allocations") - c.Ui.Output(formatList(allocs)) + if err := c.outputJobInfo(client, job); err != nil { + c.Ui.Error(err.Error()) + return 1 } return 0 } +func (c *StatusCommand) outputPeriodicInfo(client *api.Client, job *api.Job) error { + // Generate the prefix that matches launched jobs from the periodic job. + prefix := fmt.Sprintf("%s%s", job.ID, structs.PeriodicLaunchSuffix) + jobs, _, err := client.Jobs().PrefixList(prefix) + if err != nil { + return fmt.Errorf("Error querying job: %s", err) + } + + 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("\nPreviously launched jobs\n%s", formatList(out))) + return nil +} + +func (c *StatusCommand) outputJobInfo(client *api.Client, job *api.Job) error { + var evals, allocs []string + + // Query the evaluations + jobEvals, _, err := client.Jobs().Evaluations(job.ID, nil) + if err != nil { + return fmt.Errorf("Error querying job evaluations: %s", err) + } + + // Query the allocations + jobAllocs, _, err := client.Jobs().Allocations(job.ID, nil) + if err != nil { + return fmt.Errorf("Error querying job allocations: %s", err) + } + + // Format the evals + evals = make([]string, len(jobEvals)+1) + evals[0] = "ID|Priority|TriggeredBy|Status" + for i, eval := range jobEvals { + evals[i+1] = fmt.Sprintf("%s|%d|%s|%s", + eval.ID, + eval.Priority, + eval.TriggeredBy, + eval.Status) + } + + // Format the allocs + allocs = make([]string, len(jobAllocs)+1) + allocs[0] = "ID|EvalID|NodeID|TaskGroup|Desired|Status" + for i, alloc := range jobAllocs { + allocs[i+1] = fmt.Sprintf("%s|%s|%s|%s|%s|%s", + alloc.ID, + alloc.EvalID, + alloc.NodeID, + alloc.TaskGroup, + alloc.DesiredStatus, + alloc.ClientStatus) + } + + c.Ui.Output("\n==> Evaluations") + c.Ui.Output(formatList(evals)) + c.Ui.Output("\n==> Allocations") + c.Ui.Output(formatList(allocs)) + return nil +} + // 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) { diff --git a/nomad/periodic.go b/nomad/periodic.go index 51132c41f..a35ce0d56 100644 --- a/nomad/periodic.go +++ b/nomad/periodic.go @@ -12,12 +12,6 @@ import ( "github.com/hashicorp/nomad/nomad/structs" ) -const ( - // The string appended to the periodic jobs ID when launching derived - // instances of it. - JobLaunchSuffix = "/periodic-" -) - // PeriodicDispatch is used to track and launch periodic jobs. It maintains the // set of periodic jobs and creates derived jobs and evaluations per // instantiation which is determined by the periodic spec. @@ -418,18 +412,18 @@ func (p *PeriodicDispatch) deriveJob(periodicJob *structs.Job, time time.Time) ( // deriveJobID returns a job ID based on the parent periodic job and the launch // time. func (p *PeriodicDispatch) derivedJobID(periodicJob *structs.Job, time time.Time) string { - return fmt.Sprintf("%s%s%d", periodicJob.ID, JobLaunchSuffix, time.Unix()) + return fmt.Sprintf("%s%s%d", periodicJob.ID, structs.PeriodicLaunchSuffix, time.Unix()) } // LaunchTime returns the launch time of the job. This is only valid for // jobs created by PeriodicDispatch and will otherwise return an error. func (p *PeriodicDispatch) LaunchTime(jobID string) (time.Time, error) { - index := strings.LastIndex(jobID, JobLaunchSuffix) + index := strings.LastIndex(jobID, structs.PeriodicLaunchSuffix) if index == -1 { return time.Time{}, fmt.Errorf("couldn't parse launch time from eval: %v", jobID) } - launch, err := strconv.Atoi(jobID[index+len(JobLaunchSuffix):]) + launch, err := strconv.Atoi(jobID[index+len(structs.PeriodicLaunchSuffix):]) if err != nil { return time.Time{}, fmt.Errorf("couldn't parse launch time from eval: %v", jobID) } diff --git a/nomad/structs/structs.go b/nomad/structs/structs.go index eb7acaf83..dc90430d0 100644 --- a/nomad/structs/structs.go +++ b/nomad/structs/structs.go @@ -1023,6 +1023,12 @@ func (p *PeriodicConfig) Next(fromTime time.Time) time.Time { return time.Time{} } +const ( + // PeriodicLaunchSuffix is the string appended to the periodic jobs ID + // when launching derived instances of it. + PeriodicLaunchSuffix = "/periodic-" +) + // PeriodicLaunch tracks the last launch time of a periodic job. type PeriodicLaunch struct { ID string // ID of the periodic job.