diff --git a/staging/operator-lifecycle-manager/pkg/controller/bundle/bundle_unpacker.go b/staging/operator-lifecycle-manager/pkg/controller/bundle/bundle_unpacker.go index 5042136bc9..d663e2fffd 100644 --- a/staging/operator-lifecycle-manager/pkg/controller/bundle/bundle_unpacker.go +++ b/staging/operator-lifecycle-manager/pkg/controller/bundle/bundle_unpacker.go @@ -886,6 +886,11 @@ func sortUnpackJobs(jobs []*batchv1.Job, maxRetainedJobs int) (latest *batchv1.J if failedI != failedJ { return !failedI // non-failed job goes first } + // If both jobs have no failed condition, condI and condJ will be nil + // fallback to sorting by CreationTimestamp + if condI == nil || condJ == nil { + return jobs[i].CreationTimestamp.After(jobs[j].CreationTimestamp.Time) + } return condI.LastTransitionTime.After(condJ.LastTransitionTime.Time) }) if jobs[0] == nil { diff --git a/staging/operator-lifecycle-manager/pkg/controller/bundle/bundle_unpacker_test.go b/staging/operator-lifecycle-manager/pkg/controller/bundle/bundle_unpacker_test.go index 2a55fcff83..779a05d6c5 100644 --- a/staging/operator-lifecycle-manager/pkg/controller/bundle/bundle_unpacker_test.go +++ b/staging/operator-lifecycle-manager/pkg/controller/bundle/bundle_unpacker_test.go @@ -1905,8 +1905,9 @@ func TestSortUnpackJobs(t *testing.T) { } return &batchv1.Job{ ObjectMeta: metav1.ObjectMeta{ - Name: name, - Labels: map[string]string{install.OLMManagedLabelKey: install.OLMManagedLabelValue, bundleUnpackRefLabel: "test"}, + Name: name, + Labels: map[string]string{install.OLMManagedLabelKey: install.OLMManagedLabelValue, bundleUnpackRefLabel: "test"}, + CreationTimestamp: metav1.Time{Time: time.Unix(ts, 0)}, }, Status: batchv1.JobStatus{ Conditions: conditions, @@ -1930,6 +1931,11 @@ func TestSortUnpackJobs(t *testing.T) { testJob("f-5", true, 5), } nonFailedJob := testJob("s-1", false, 1) + nonFailedJobs := []*batchv1.Job{ + testJob("nf-1", false, 1), + testJob("nf-2", false, 2), + testJob("nf-3", false, 3), + } for _, tc := range []struct { name string jobs []*batchv1.Job @@ -2007,6 +2013,15 @@ func TestSortUnpackJobs(t *testing.T) { nonFailedJob, }, expectedLatest: nonFailedJob, + }, { + name: "multiple non-failed jobs sorted by creation time", + maxRetained: 3, + jobs: []*batchv1.Job{ + nonFailedJobs[0], + nonFailedJobs[2], + nonFailedJobs[1], + }, + expectedLatest: nonFailedJobs[2], // latest creation time should be first }, } { latest, toDelete := sortUnpackJobs(tc.jobs, tc.maxRetained) diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/bundle/bundle_unpacker.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/bundle/bundle_unpacker.go index 5042136bc9..d663e2fffd 100644 --- a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/bundle/bundle_unpacker.go +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/bundle/bundle_unpacker.go @@ -886,6 +886,11 @@ func sortUnpackJobs(jobs []*batchv1.Job, maxRetainedJobs int) (latest *batchv1.J if failedI != failedJ { return !failedI // non-failed job goes first } + // If both jobs have no failed condition, condI and condJ will be nil + // fallback to sorting by CreationTimestamp + if condI == nil || condJ == nil { + return jobs[i].CreationTimestamp.After(jobs[j].CreationTimestamp.Time) + } return condI.LastTransitionTime.After(condJ.LastTransitionTime.Time) }) if jobs[0] == nil {