Change:
Suspend is a GA feature and it is big component of Kueue. It would be nice to display if jobs are suspended when doing . A new column that displays if the job is suspended would be helpful. Improve UX around suspend. Its a bit difficult to know why the job has not created pods unless you know about the suspend field.
/sig cli /wg batch /good-first-issue /help-wanted
This request has been marked as suitable for new contributors. Please ensure that the issue body includes answers to the following questions: Why are we solving this issue? To address this issue, are there any code changes? If there are code changes, what needs to be done in the code and what places can the assignee treat as reference points? Does this issue have zero to low barrier of entry? How can the assignee reach out to you for help? For more details on the requirements of such an issue, please see and ensure that they are met. If this request no longer meets these requirements, the label can be removed by commenting with the command. <detailsIn response to : /sig cli /wg batch /good-first-issue /help-wanted Instructions for interacting with me using PR comments are available . If you have questions or suggestions related to my behavior, please file an issue against the repository. </details
/cc Just something I noticed as I was testing some job in JobSet. It would be nice to see which jobs are suspended when doing . Hope its not a controversial change.
cc who worked on
Not controversial at all IMO /triage accepted
/assign
Any suggestions on where to place this column? I'm thinking between completions and durations. Or, should this be displayed only when the output is set to wide?
I would put it in the default view as well. Probably before completions
Addressed in the PR:

Discussion:
jobColumnDefinitions := []metav1.TableColumnDefinition{ {Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]}, <ins> {Name: "Status", Type: "string", Description: "Status of the job."}, </ins> {Name: "Completions", Type: "string", Description: batchv1.JobStatus{}.SwaggerDoc()["succeeded"]}, {Name: "Duration", Type: "string", Description: "Time required to complete the job."}, {Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},

return false } <ins> func hasJobCondition(conditions []batch.JobCondition, conditionType batch.JobConditionType) bool { for _, condition := range conditions { if condition.Type == conditionType { return condition.Status == api.ConditionTrue } } return false } </ins> func printPodTemplate(obj *api.PodTemplate, options printers.GenerateOptions) ([]metav1.TableRow, error) { row := metav1.TableRow{ Object: runtime.RawExtension{Object: obj},

default: jobDuration = duration.HumanDuration(obj.Status.CompletionTime.Sub(obj.Status.StartTime.Time)) } <ins> var status string if hasJobCondition(obj.Status.Conditions, batch.JobComplete) { status = "Complete" } else if hasJobCondition(obj.Status.Conditions, batch.JobFailed) { status = "Failed" } else if obj.ObjectMeta.DeletionTimestamp != nil { status = "Terminating" } else if hasJobCondition(obj.Status.Conditions, batch.JobSuspended) { status = "Suspended" } else if hasJobCondition(obj.Status.Conditions, batch.JobFailureTarget) { status = "FailureTarget" } else { status = "Running" } </ins> <del> row.Cells = append(row.Cells, obj.Name, completions, jobDuration, translateTimestampSince(obj.CreationTimestamp)) </del> <ins> row.Cells = append(row.Cells, obj.Name, status, completions, jobDuration, translateTimestampSince(obj.CreationTimestamp)) </ins> if options.Wide { names, images := layoutContainerCells(obj.Spec.Template.Spec.Containers) row.Cells = append(row.Cells, names, images, metav1.FormatLabelSelector(obj.Spec.Selector))

}, }, options: printers.GenerateOptions{}, <del> // Columns: Name, Completions, Duration, Age expected: []metav1.TableRow{{Cells: []interface{}{"job1", "1/2", "", "0s"}}}, </del> <ins> // Columns: Name, Status, Completions, Duration, Age expected: []metav1.TableRow{{Cells: []interface{}{"job1", "Running", "1/2", "", "0s"}}}, </ins> }, // Generate table rows for Job with generate options "Wide". {

}, }, options: printers.GenerateOptions{Wide: true}, <del> // Columns: Name, Completions, Duration, Age, Containers, Images, Selectors </del> <ins> // Columns: Name, Status, Completions, Duration, Age, Containers, Images, Selectors </ins> expected: []metav1.TableRow{ { <del> Cells: []interface{}{"job1", "1/2", "", "0s", "fake-job-container1,fake-job-container2", "fake-job-image1,fake-job-image2", "job-label=job-label-value"}, </del> <ins> Cells: []interface{}{"job1", "Running", "1/2", "", "0s", "fake-job-container1,fake-job-container2", "fake-job-image1,fake-job-image2", "job-label=job-label-value"}, </ins> }, }, },

}, }, options: printers.GenerateOptions{}, <del> // Columns: Name, Completions, Duration, Age expected: []metav1.TableRow{{Cells: []interface{}{"job2", "0/1", "", "10y"}}}, </del> <ins> // Columns: Name, Status, Completions, Duration, Age expected: []metav1.TableRow{{Cells: []interface{}{"job2", "Running", "0/1", "", "10y"}}}, </ins> }, // Job with duration. {

}, }, options: printers.GenerateOptions{}, <del> // Columns: Name, Completions, Duration, Age expected: []metav1.TableRow{{Cells: []interface{}{"job3", "0/1", "30m", "10y"}}}, </del> <ins> // Columns: Name, Status, Completions, Duration, Age expected: []metav1.TableRow{{Cells: []interface{}{"job3", "Running", "0/1", "30m", "10y"}}}, </ins> }, { job: batch.Job{

}, }, options: printers.GenerateOptions{}, <del> // Columns: Name, Completions, Duration, Age expected: []metav1.TableRow{{Cells: []interface{}{"job4", "0/1", "20m", "10y"}}}, </del> <ins> // Columns: Name, Status, Completions, Duration, Age expected: []metav1.TableRow{{Cells: []interface{}{"job4", "Running", "0/1", "20m", "10y"}}}, }, { job: batch.Job{ ObjectMeta: metav1.ObjectMeta{ Name:              "job5", CreationTimestamp: metav1.Time{Time: time.Now().Add(1.9e9)}, }, Spec: batch.JobSpec{ Completions: nil, }, Status: batch.JobStatus{ Succeeded: 0, Conditions: []batch.JobCondition{ { Type:   batch.JobComplete, Status: api.ConditionTrue, }, }, }, }, options: printers.GenerateOptions{}, // Columns: Name, Status, Completions, Duration, Age expected: []metav1.TableRow{{Cells: []interface{}{"job5", "Complete", "0/1", "", "0s"}}}, }, { job: batch.Job{ ObjectMeta: metav1.ObjectMeta{ Name:              "job6", CreationTimestamp: metav1.Time{Time: time.Now().Add(1.9e9)}, }, Spec: batch.JobSpec{ Completions: nil, }, Status: batch.JobStatus{ Succeeded: 0, Conditions: []batch.JobCondition{ { Type:   batch.JobFailed, Status: api.ConditionTrue, }, }, }, }, options: printers.GenerateOptions{}, // Columns: Name, Status, Completions, Duration, Age expected: []metav1.TableRow{{Cells: []interface{}{"job6", "Failed", "0/1", "", "0s"}}}, }, { job: batch.Job{ ObjectMeta: metav1.ObjectMeta{ Name:              "job7", CreationTimestamp: metav1.Time{Time: time.Now().Add(1.9e9)}, }, Spec: batch.JobSpec{ Completions: nil, }, Status: batch.JobStatus{ Succeeded: 0, Conditions: []batch.JobCondition{ { Type:   batch.JobSuspended, Status: api.ConditionTrue, }, }, }, }, options: printers.GenerateOptions{}, // Columns: Name, Status, Completions, Duration, Age expected: []metav1.TableRow{{Cells: []interface{}{"job7", "Suspended", "0/1", "", "0s"}}}, }, { job: batch.Job{ ObjectMeta: metav1.ObjectMeta{ Name:              "job8", CreationTimestamp: metav1.Time{Time: time.Now().Add(1.9e9)}, }, Spec: batch.JobSpec{ Completions: nil, }, Status: batch.JobStatus{ Succeeded: 0, Conditions: []batch.JobCondition{ { Type:   batch.JobFailureTarget, Status: api.ConditionTrue, }, }, }, }, options: printers.GenerateOptions{}, // Columns: Name, Status, Completions, Duration, Age expected: []metav1.TableRow{{Cells: []interface{}{"job8", "FailureTarget", "0/1", "", "0s"}}}, }, { job: batch.Job{ ObjectMeta: metav1.ObjectMeta{ Name:              "job9", CreationTimestamp: metav1.Time{Time: time.Now().Add(1.9e9)}, DeletionTimestamp: &metav1.Time{Time: time.Now().Add(1.9e9)}, }, Spec: batch.JobSpec{ Completions: nil, }, }, options: printers.GenerateOptions{}, // Columns: Name, Status, Completions, Duration, Age expected: []metav1.TableRow{{Cells: []interface{}{"job9", "Terminating", "0/1", "", "0s"}}}, </ins> }, }

}, } <del> // Columns: Name, Completions, Duration, Age </del> <ins> // Columns: Name, Status, Completions, Duration, Age </ins> expectedRows := []metav1.TableRow{ <del> {Cells: []interface{}{"job1", "1/2", "", "0s"}}, {Cells: []interface{}{"job2", "2/2", "20m", "0s"}}, </del> <ins> {Cells: []interface{}{"job1", "Running", "1/2", "", "0s"}}, {Cells: []interface{}{"job2", "Running", "2/2", "20m", "0s"}}, </ins> } rows, err := printJobList(&jobList, printers.GenerateOptions{})