diff --git a/api/cloud-resources/v1beta1/awsnfsbackupschedule_types.go b/api/cloud-resources/v1beta1/awsnfsbackupschedule_types.go index 00fcb12c..5ecbf231 100644 --- a/api/cloud-resources/v1beta1/awsnfsbackupschedule_types.go +++ b/api/cloud-resources/v1beta1/awsnfsbackupschedule_types.go @@ -56,12 +56,32 @@ type AwsNfsBackupScheduleSpec struct { EndTime *metav1.Time `json:"endTime,omitempty"` // MaxRetentionDays specifies the maximum number of days to retain the backup - // If not provided, backup will be retained indefinitely + // If not provided, it will be defaulted to 375 days. // If the DeleteCascade is true for this schedule, // then all the backups will be deleted when the schedule is deleted irrespective of the MaxRetentionDay configuration. // +optional + // +kubebuilder:default=375 + // +kubebuilder:validation:Minimum=1 MaxRetentionDays int `json:"maxRetentionDays,omitempty"` + // MaxReadyBackups specifies the maximum number of backups in "Ready" state to be retained. + // If not provided, it will be defaulted to 100 active backups. + // If the DeleteCascade is true for this schedule, + // then all the backups will be deleted when the schedule is deleted irrespective of the MaxReadyBackups configuration. + // +optional + // +kubebuilder:default=100 + // +kubebuilder:validation:Minimum=1 + MaxReadyBackups int `json:"maxReadyBackups,omitempty"` + + // MaxFailedBackups specifies the maximum number of backups in "Failed" state to be retained. + // If not provided, it will be defaulted to 5 failed backups. + // If the DeleteCascade is true for this schedule, + // then all the backups will be deleted when the schedule is deleted irrespective of the MaxFailedBackups configuration. + // +optional + // +kubebuilder:default=5 + // +kubebuilder:validation:Minimum=1 + MaxFailedBackups int `json:"maxFailedBackups,omitempty"` + // Suspend specifies whether the schedule should be suspended // By default, suspend will be false // +kubebuilder:default=false @@ -211,6 +231,20 @@ func (sc *AwsNfsBackupSchedule) SetDeleteCascade(cascade bool) { sc.Spec.DeleteCascade = cascade } +func (sc *AwsNfsBackupSchedule) GetMaxReadyBackups() int { + return sc.Spec.MaxReadyBackups +} +func (sc *AwsNfsBackupSchedule) SetMaxReadyBackups(count int) { + sc.Spec.MaxReadyBackups = count +} + +func (sc *AwsNfsBackupSchedule) GetMaxFailedBackups() int { + return sc.Spec.MaxFailedBackups +} +func (sc *AwsNfsBackupSchedule) SetMaxFailedBackups(count int) { + sc.Spec.MaxFailedBackups = count +} + func (sc *AwsNfsBackupSchedule) GetNextRunTimes() []string { return sc.Status.NextRunTimes } diff --git a/api/cloud-resources/v1beta1/gcpnfsbackupschedule_types.go b/api/cloud-resources/v1beta1/gcpnfsbackupschedule_types.go index 170023f5..52bc5786 100644 --- a/api/cloud-resources/v1beta1/gcpnfsbackupschedule_types.go +++ b/api/cloud-resources/v1beta1/gcpnfsbackupschedule_types.go @@ -60,12 +60,32 @@ type GcpNfsBackupScheduleSpec struct { EndTime *metav1.Time `json:"endTime,omitempty"` // MaxRetentionDays specifies the maximum number of days to retain the backup - // If not provided, backup will be retained indefinitely + // If not provided, it will be defaulted to 375 days. // If the DeleteCascade is true for this schedule, // then all the backups will be deleted when the schedule is deleted irrespective of the MaxRetentionDay configuration. // +optional + // +kubebuilder:default=375 + // +kubebuilder:validation:Minimum=1 MaxRetentionDays int `json:"maxRetentionDays,omitempty"` + // MaxReadyBackups specifies the maximum number of backups in "Ready" state to be retained. + // If not provided, it will be defaulted to 100 active backups. + // If the DeleteCascade is true for this schedule, + // then all the backups will be deleted when the schedule is deleted irrespective of the MaxRetentionDay configuration. + // +optional + // +kubebuilder:default=100 + // +kubebuilder:validation:Minimum=1 + MaxReadyBackups int `json:"maxReadyBackups,omitempty"` + + // MaxFailedBackups specifies the maximum number of backups in "Failed" state to be retained. + // If not provided, it will be defaulted to 5 failed backups. + // If the DeleteCascade is true for this schedule, + // then all the backups will be deleted when the schedule is deleted irrespective of the MaxRetentionDay configuration. + // +optional + // +kubebuilder:default=5 + // +kubebuilder:validation:Minimum=1 + MaxFailedBackups int `json:"maxFailedBackups,omitempty"` + // Suspend specifies whether the schedule should be suspended // By default, suspend will be false // +kubebuilder:default=false @@ -215,6 +235,20 @@ func (sc *GcpNfsBackupSchedule) SetDeleteCascade(cascade bool) { sc.Spec.DeleteCascade = cascade } +func (sc *GcpNfsBackupSchedule) GetMaxReadyBackups() int { + return sc.Spec.MaxReadyBackups +} +func (sc *GcpNfsBackupSchedule) SetMaxReadyBackups(count int) { + sc.Spec.MaxReadyBackups = count +} + +func (sc *GcpNfsBackupSchedule) GetMaxFailedBackups() int { + return sc.Spec.MaxFailedBackups +} +func (sc *GcpNfsBackupSchedule) SetMaxFailedBackups(count int) { + sc.Spec.MaxFailedBackups = count +} + func (sc *GcpNfsBackupSchedule) GetNextRunTimes() []string { return sc.Status.NextRunTimes } diff --git a/api/cloud-resources/v1beta1/gcpnfsvolumebackup_types.go b/api/cloud-resources/v1beta1/gcpnfsvolumebackup_types.go index 4d0cc198..2d098279 100644 --- a/api/cloud-resources/v1beta1/gcpnfsvolumebackup_types.go +++ b/api/cloud-resources/v1beta1/gcpnfsvolumebackup_types.go @@ -124,12 +124,12 @@ type GcpNfsVolumeBackup struct { Status GcpNfsVolumeBackupStatus `json:"status,omitempty"` } -func (in *GcpNfsVolumeBackup) State() GcpNfsBackupState { - return in.Status.State +func (in *GcpNfsVolumeBackup) State() string { + return string(in.Status.State) } -func (in *GcpNfsVolumeBackup) SetState(v GcpNfsBackupState) { - in.Status.State = v +func (in *GcpNfsVolumeBackup) SetState(v string) { + in.Status.State = GcpNfsBackupState(v) } func (in *GcpNfsVolumeBackup) Conditions() *[]metav1.Condition { diff --git a/config/crd/bases/cloud-resources.kyma-project.io_awsnfsbackupschedules.yaml b/config/crd/bases/cloud-resources.kyma-project.io_awsnfsbackupschedules.yaml index c811f4b7..2baf6089 100644 --- a/config/crd/bases/cloud-resources.kyma-project.io_awsnfsbackupschedules.yaml +++ b/config/crd/bases/cloud-resources.kyma-project.io_awsnfsbackupschedules.yaml @@ -64,12 +64,32 @@ spec: If not provided, schedule will run indefinitely format: date-time type: string + maxActiveBackups: + default: 100 + description: |- + MaxActiveBackups specifies the maximum number of backups in "Active" state to be retained. + If not provided, it will be defaulted to 100 active backups. + If the DeleteCascade is true for this schedule, + then all the backups will be deleted when the schedule is deleted irrespective of the MaxRetentionDay configuration. + minimum: 1 + type: integer + maxFailedBackups: + default: 5 + description: |- + MaxFailedBackups specifies the maximum number of backups in "Failed" state to be retained. + If not provided, it will be defaulted to 5 failed backups. + If the DeleteCascade is true for this schedule, + then all the backups will be deleted when the schedule is deleted irrespective of the MaxRetentionDay configuration. + minimum: 1 + type: integer maxRetentionDays: + default: 375 description: |- MaxRetentionDays specifies the maximum number of days to retain the backup - If not provided, backup will be retained indefinitely + If not provided, it will be defaulted to 375 days. If the DeleteCascade is true for this schedule, then all the backups will be deleted when the schedule is deleted irrespective of the MaxRetentionDay configuration. + minimum: 1 type: integer nfsVolumeRef: description: NfsVolumeRef specifies the SourceRef resource that a backup has to be made of. diff --git a/config/crd/bases/cloud-resources.kyma-project.io_gcpnfsbackupschedules.yaml b/config/crd/bases/cloud-resources.kyma-project.io_gcpnfsbackupschedules.yaml index 9d389770..2c035e1b 100644 --- a/config/crd/bases/cloud-resources.kyma-project.io_gcpnfsbackupschedules.yaml +++ b/config/crd/bases/cloud-resources.kyma-project.io_gcpnfsbackupschedules.yaml @@ -67,12 +67,32 @@ spec: location: description: Location specifies the location where the backup has to be stored. type: string + maxActiveBackups: + default: 100 + description: |- + MaxActiveBackups specifies the maximum number of backups in "Active" state to be retained. + If not provided, it will be defaulted to 100 active backups. + If the DeleteCascade is true for this schedule, + then all the backups will be deleted when the schedule is deleted irrespective of the MaxRetentionDay configuration. + minimum: 1 + type: integer + maxFailedBackups: + default: 5 + description: |- + MaxFailedBackups specifies the maximum number of backups in "Failed" state to be retained. + If not provided, it will be defaulted to 5 failed backups. + If the DeleteCascade is true for this schedule, + then all the backups will be deleted when the schedule is deleted irrespective of the MaxRetentionDay configuration. + minimum: 1 + type: integer maxRetentionDays: + default: 375 description: |- MaxRetentionDays specifies the maximum number of days to retain the backup - If not provided, backup will be retained indefinitely + If not provided, it will be defaulted to 375 days. If the DeleteCascade is true for this schedule, then all the backups will be deleted when the schedule is deleted irrespective of the MaxRetentionDay configuration. + minimum: 1 type: integer nfsVolumeRef: description: NfsVolumeRef specifies the SourceRef resource that a backup has to be made of. diff --git a/config/dist/skr/crd/bases/providers/aws/cloud-resources.kyma-project.io_awsnfsbackupschedules.yaml b/config/dist/skr/crd/bases/providers/aws/cloud-resources.kyma-project.io_awsnfsbackupschedules.yaml index c811f4b7..2baf6089 100644 --- a/config/dist/skr/crd/bases/providers/aws/cloud-resources.kyma-project.io_awsnfsbackupschedules.yaml +++ b/config/dist/skr/crd/bases/providers/aws/cloud-resources.kyma-project.io_awsnfsbackupschedules.yaml @@ -64,12 +64,32 @@ spec: If not provided, schedule will run indefinitely format: date-time type: string + maxActiveBackups: + default: 100 + description: |- + MaxActiveBackups specifies the maximum number of backups in "Active" state to be retained. + If not provided, it will be defaulted to 100 active backups. + If the DeleteCascade is true for this schedule, + then all the backups will be deleted when the schedule is deleted irrespective of the MaxRetentionDay configuration. + minimum: 1 + type: integer + maxFailedBackups: + default: 5 + description: |- + MaxFailedBackups specifies the maximum number of backups in "Failed" state to be retained. + If not provided, it will be defaulted to 5 failed backups. + If the DeleteCascade is true for this schedule, + then all the backups will be deleted when the schedule is deleted irrespective of the MaxRetentionDay configuration. + minimum: 1 + type: integer maxRetentionDays: + default: 375 description: |- MaxRetentionDays specifies the maximum number of days to retain the backup - If not provided, backup will be retained indefinitely + If not provided, it will be defaulted to 375 days. If the DeleteCascade is true for this schedule, then all the backups will be deleted when the schedule is deleted irrespective of the MaxRetentionDay configuration. + minimum: 1 type: integer nfsVolumeRef: description: NfsVolumeRef specifies the SourceRef resource that a backup has to be made of. diff --git a/config/dist/skr/crd/bases/providers/gcp/cloud-resources.kyma-project.io_gcpnfsbackupschedules.yaml b/config/dist/skr/crd/bases/providers/gcp/cloud-resources.kyma-project.io_gcpnfsbackupschedules.yaml index 9d389770..2c035e1b 100644 --- a/config/dist/skr/crd/bases/providers/gcp/cloud-resources.kyma-project.io_gcpnfsbackupschedules.yaml +++ b/config/dist/skr/crd/bases/providers/gcp/cloud-resources.kyma-project.io_gcpnfsbackupschedules.yaml @@ -67,12 +67,32 @@ spec: location: description: Location specifies the location where the backup has to be stored. type: string + maxActiveBackups: + default: 100 + description: |- + MaxActiveBackups specifies the maximum number of backups in "Active" state to be retained. + If not provided, it will be defaulted to 100 active backups. + If the DeleteCascade is true for this schedule, + then all the backups will be deleted when the schedule is deleted irrespective of the MaxRetentionDay configuration. + minimum: 1 + type: integer + maxFailedBackups: + default: 5 + description: |- + MaxFailedBackups specifies the maximum number of backups in "Failed" state to be retained. + If not provided, it will be defaulted to 5 failed backups. + If the DeleteCascade is true for this schedule, + then all the backups will be deleted when the schedule is deleted irrespective of the MaxRetentionDay configuration. + minimum: 1 + type: integer maxRetentionDays: + default: 375 description: |- MaxRetentionDays specifies the maximum number of days to retain the backup - If not provided, backup will be retained indefinitely + If not provided, it will be defaulted to 375 days. If the DeleteCascade is true for this schedule, then all the backups will be deleted when the schedule is deleted irrespective of the MaxRetentionDay configuration. + minimum: 1 type: integer nfsVolumeRef: description: NfsVolumeRef specifies the SourceRef resource that a backup has to be made of. diff --git a/config/patchAfterMakeManifests.sh b/config/patchAfterMakeManifests.sh index f8f9a523..c40856ca 100755 --- a/config/patchAfterMakeManifests.sh +++ b/config/patchAfterMakeManifests.sh @@ -15,9 +15,9 @@ yq -i '.metadata.annotations."cloud-resources.kyma-project.io/version" = "v0.0.2 yq -i '.metadata.annotations."cloud-resources.kyma-project.io/version" = "v0.0.55"' $SCRIPT_DIR/crd/bases/cloud-resources.kyma-project.io_azureredisinstances.yaml yq -i '.metadata.annotations."cloud-resources.kyma-project.io/version" = "v0.0.4"' $SCRIPT_DIR/crd/bases/cloud-resources.kyma-project.io_gcpnfsvolumebackups.yaml yq -i '.metadata.annotations."cloud-resources.kyma-project.io/version" = "v0.0.3"' $SCRIPT_DIR/crd/bases/cloud-resources.kyma-project.io_gcpnfsvolumerestores.yaml -yq -i '.metadata.annotations."cloud-resources.kyma-project.io/version" = "v0.0.4"' $SCRIPT_DIR/crd/bases/cloud-resources.kyma-project.io_gcpnfsbackupschedules.yaml +yq -i '.metadata.annotations."cloud-resources.kyma-project.io/version" = "v0.0.5"' $SCRIPT_DIR/crd/bases/cloud-resources.kyma-project.io_gcpnfsbackupschedules.yaml yq -i '.metadata.annotations."cloud-resources.kyma-project.io/version" = "v0.0.3"' $SCRIPT_DIR/crd/bases/cloud-resources.kyma-project.io_gcpvpcpeerings.yaml yq -i '.metadata.annotations."cloud-resources.kyma-project.io/version" = "v0.0.3"' $SCRIPT_DIR/crd/bases/cloud-resources.kyma-project.io_awsvpcpeerings.yaml yq -i '.metadata.annotations."cloud-resources.kyma-project.io/version" = "v0.0.1"' $SCRIPT_DIR/crd/bases/cloud-resources.kyma-project.io_cloudresources.yaml -yq -i '.metadata.annotations."cloud-resources.kyma-project.io/version" = "v0.0.3"' $SCRIPT_DIR/crd/bases/cloud-resources.kyma-project.io_awsnfsbackupschedules.yaml +yq -i '.metadata.annotations."cloud-resources.kyma-project.io/version" = "v0.0.4"' $SCRIPT_DIR/crd/bases/cloud-resources.kyma-project.io_awsnfsbackupschedules.yaml yq -i '.metadata.annotations."cloud-resources.kyma-project.io/version" = "v0.0.1"' $SCRIPT_DIR/crd/bases/cloud-resources.kyma-project.io_azurerwxvolumebackups.yaml diff --git a/pkg/skr/backupschedule/backupschedule.go b/pkg/skr/backupschedule/backupschedule.go index d094de17..c552eb8f 100644 --- a/pkg/skr/backupschedule/backupschedule.go +++ b/pkg/skr/backupschedule/backupschedule.go @@ -29,6 +29,10 @@ type BackupScheduleSpec interface { SetSuspend(suspend bool) GetDeleteCascade() bool SetDeleteCascade(cascade bool) + GetMaxReadyBackups() int + SetMaxReadyBackups(count int) + GetMaxFailedBackups() int + SetMaxFailedBackups(count int) } type BackupScheduleStatus interface { diff --git a/pkg/skr/backupschedule/deleteBackups.go b/pkg/skr/backupschedule/deleteBackups.go index e3e4e98c..41db007d 100644 --- a/pkg/skr/backupschedule/deleteBackups.go +++ b/pkg/skr/backupschedule/deleteBackups.go @@ -3,6 +3,7 @@ package backupschedule import ( "context" "fmt" + "github.com/kyma-project/cloud-manager/api/cloud-resources/v1beta1" "time" "github.com/kyma-project/cloud-manager/pkg/composed" @@ -48,12 +49,20 @@ func deleteBackups(ctx context.Context, st composed.State) (error, context.Conte nextDeleteTimes := map[string]string{} var lastDeleted []corev1.ObjectReference - for _, backup := range state.Backups { + readyCount, failedCount := 0, 0 + for _, bk := range state.Backups { + backup, okay := bk.(composed.ObjWithConditionsAndState) + if !okay { + logger.WithValues("BackupSchedule", schedule.GetName()).Info(fmt.Sprintf("%t is not of type composed.ObjWithConditionsAndState", bk)) + continue + } //Check if the backup object should be deleted toRetain := time.Duration(schedule.GetMaxRetentionDays()) * 24 * time.Hour elapsed := time.Since(backup.GetCreationTimestamp().Time) - if elapsed > toRetain { + if elapsed > toRetain || + (backup.State() == v1beta1.StateReady && readyCount >= schedule.GetMaxReadyBackups()) || + (backup.State() == v1beta1.StateFailed && failedCount >= schedule.GetMaxFailedBackups()) { logger.WithValues("Backup", backup.GetName()).Info("Deleting backup object") err := state.Cluster().K8sClient().Delete(ctx, backup) if err != nil { @@ -64,6 +73,14 @@ func deleteBackups(ctx context.Context, st composed.State) (error, context.Conte Name: backup.GetName(), Namespace: backup.GetNamespace(), }) + } else { + //Increment counters + switch backup.State() { + case v1beta1.StateReady: + readyCount++ + case v1beta1.StateFailed: + failedCount++ + } } if len(nextDeleteTimes) < MaxSchedules { backupName := fmt.Sprintf("%s/%s", backup.GetNamespace(), backup.GetName()) diff --git a/pkg/skr/backupschedule/deleteBackups_test.go b/pkg/skr/backupschedule/deleteBackups_test.go index 327ebfcf..602a7aef 100644 --- a/pkg/skr/backupschedule/deleteBackups_test.go +++ b/pkg/skr/backupschedule/deleteBackups_test.go @@ -5,8 +5,10 @@ import ( "github.com/kyma-project/cloud-manager/api/cloud-resources/v1beta1" "github.com/kyma-project/cloud-manager/pkg/composed" "github.com/stretchr/testify/suite" + apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" "testing" "time" ) @@ -163,12 +165,14 @@ func (suite *deleteBackupsSuite) TestWhenNoMaxRetentionSet() { suite.Nil(fromK8s.Status.LastDeletedBackups) } -func (suite *deleteBackupsSuite) testDeleteBackup(createBackup2 bool) { +func (suite *deleteBackupsSuite) testDeleteBackup(backup1, backup2, backup client.Object, maxDays, maxReady, maxFailed int, b1Exists, b2Exists bool) { runTime := time.Now().UTC() obj := gcpNfsBackupSchedule.DeepCopy() - obj.Spec.MaxRetentionDays = 1 + obj.Spec.MaxRetentionDays = maxDays + obj.Spec.MaxReadyBackups = maxReady + obj.Spec.MaxFailedBackups = maxFailed factory, err := newTestStateFactoryWithObj(obj) suite.Nil(err) @@ -182,46 +186,86 @@ func (suite *deleteBackupsSuite) testDeleteBackup(createBackup2 bool) { state.nextRunTime = runTime //Create provider specific backup objects - err = factory.skrCluster.K8sClient().Create(ctx, gcpBackup1.DeepCopy()) + err = factory.skrCluster.K8sClient().Create(ctx, backup1) suite.Nil(err) + state.Backups = append(state.Backups, backup1) - if createBackup2 { - err = factory.skrCluster.K8sClient().Create(ctx, gcpBackup2.DeepCopy()) + if backup2 != nil { + err = factory.skrCluster.K8sClient().Create(ctx, backup2) suite.Nil(err) + state.Backups = append(state.Backups, backup2) } - state.Backups = append(state.Backups, gcpBackup1) - state.Backups = append(state.Backups, gcpBackup2) - //Invoke API under test err, _ = deleteBackups(ctx, state) //validate expected return values suite.Equal(composed.StopWithRequeue, err) + //Validate schedule data fromK8s := &v1beta1.GcpNfsBackupSchedule{} err = factory.skrCluster.K8sClient().Get(ctx, types.NamespacedName{Name: obj.Name, - Namespace: gcpNfsBackupSchedule.Namespace}, + Namespace: obj.Namespace}, fromK8s) suite.Nil(err) suite.NotNil(fromK8s.Status.LastDeleteRun) suite.Equal(runTime.Unix(), fromK8s.Status.LastDeleteRun.Time.Unix()) - backup := &v1beta1.GcpNfsVolumeBackup{} + //Validate backup1 err = factory.skrCluster.K8sClient().Get(ctx, - types.NamespacedName{Name: gcpBackup1.GetName(), - Namespace: gcpNfsBackupSchedule.Namespace}, + types.NamespacedName{Name: backup1.GetName(), + Namespace: obj.Namespace}, backup) - suite.Nil(err) + if b1Exists { + suite.Nil(err) + } else { + suite.True(apierrors.IsNotFound(err)) + } + + //Validate backup2 + if backup2 != nil { + err = factory.skrCluster.K8sClient().Get(ctx, + types.NamespacedName{Name: backup2.GetName(), + Namespace: obj.Namespace}, + backup) + if b2Exists { + suite.Nil(err) + } else { + suite.True(apierrors.IsNotFound(err)) + } + } } -func (suite *deleteBackupsSuite) TestDeleteGcpBackup() { - suite.testDeleteBackup(true) +func (suite *deleteBackupsSuite) TestMaxRetentionDays() { + backup1 := gcpBackup1.DeepCopy() + backup2 := gcpBackup2.DeepCopy() + backup := &v1beta1.GcpNfsVolumeBackup{} + suite.testDeleteBackup(backup1, backup2, backup, 1, 100, 5, true, false) +} + +func (suite *deleteBackupsSuite) TestMaxReadyBackups() { + backup1 := gcpBackup1.DeepCopy() + backup1.Status.State = v1beta1.StateReady + backup2 := gcpBackup2.DeepCopy() + backup2.Status.State = v1beta1.StateReady + backup := &v1beta1.GcpNfsVolumeBackup{} + suite.testDeleteBackup(backup1, backup2, backup, 375, 1, 5, true, false) +} + +func (suite *deleteBackupsSuite) TestMaxFailedBackups() { + backup1 := gcpBackup1.DeepCopy() + backup1.Status.State = v1beta1.StateFailed + backup2 := gcpBackup2.DeepCopy() + backup2.Status.State = v1beta1.StateFailed + backup := &v1beta1.GcpNfsVolumeBackup{} + suite.testDeleteBackup(backup1, backup2, backup, 375, 100, 1, true, false) } func (suite *deleteBackupsSuite) TestDeleteGcpBackupFailure() { - suite.testDeleteBackup(false) + backup1 := gcpBackup1.DeepCopy() + backup := &v1beta1.GcpNfsVolumeBackup{} + suite.testDeleteBackup(backup1, nil, backup, 1, 100, 5, true, false) } func TestDeleteBackupsSuite(t *testing.T) { diff --git a/pkg/skr/backupschedule/loadBackups.go b/pkg/skr/backupschedule/loadBackups.go index 33de1876..206a57d1 100644 --- a/pkg/skr/backupschedule/loadBackups.go +++ b/pkg/skr/backupschedule/loadBackups.go @@ -44,9 +44,9 @@ func loadBackups(ctx context.Context, st composed.State) (error, context.Context //convert list to a slice objects := state.backupImpl.toObjectSlice(list) - //sort the objects + //sort the objects in reverse chronological order. sort.Slice(objects, func(i, j int) bool { - return objects[i].GetCreationTimestamp().Time.Before(objects[j].GetCreationTimestamp().Time) + return objects[i].GetCreationTimestamp().Time.After(objects[j].GetCreationTimestamp().Time) }) //Store the objects in the State.