From b71a37dbfcbc227f2c126575efe28a38845ac0ae Mon Sep 17 00:00:00 2001 From: Nolan Brubaker Date: Tue, 10 Jul 2018 18:17:53 -0400 Subject: [PATCH] Record backup completion time before uploading Signed-off-by: Nolan Brubaker --- pkg/apis/ark/v1/backup.go | 1 + pkg/controller/backup_controller.go | 5 ++++- pkg/controller/backup_controller_test.go | 12 +++++++++++- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/pkg/apis/ark/v1/backup.go b/pkg/apis/ark/v1/backup.go index 786808aef..041d3b5b1 100644 --- a/pkg/apis/ark/v1/backup.go +++ b/pkg/apis/ark/v1/backup.go @@ -179,6 +179,7 @@ type BackupStatus struct { // CompletionTimestamp records the time a backup was completed. // Completion time is recorded even on failed backups. + // Completion time is recorded before uploading the backup object. // The server's time is used for CompletionTimestamps CompletionTimestamp metav1.Time `json:"completionTimestamp"` } diff --git a/pkg/controller/backup_controller.go b/pkg/controller/backup_controller.go index 8d563d4c5..6cc1a558d 100644 --- a/pkg/controller/backup_controller.go +++ b/pkg/controller/backup_controller.go @@ -370,6 +370,10 @@ func (controller *backupController) runBackup(backup *api.Backup, bucket string) backup.Status.Phase = api.BackupPhaseCompleted } + // Mark completion timestamp before serializing and uploading. + // Otherwise, the JSON file in object storage has a CompletionTimestamp of 'null'. + backup.Status.CompletionTimestamp.Time = controller.clock.Now() + backupJSON := new(bytes.Buffer) if err := encode.EncodeTo(backup, "json", backupJSON); err != nil { errs = append(errs, errors.Wrap(err, "error encoding backup")) @@ -393,7 +397,6 @@ func (controller *backupController) runBackup(backup *api.Backup, bucket string) backupScheduleName := backup.GetLabels()["ark-schedule"] controller.metrics.SetBackupTarballSizeBytesGauge(backupScheduleName, backupSizeBytes) - backup.Status.CompletionTimestamp.Time = controller.clock.Now() backupDuration := backup.Status.CompletionTimestamp.Time.Sub(backup.Status.StartTimestamp.Time) backupDurationSeconds := float64(backupDuration / time.Second) controller.metrics.RegisterBackupDuration(backupScheduleName, backupDurationSeconds) diff --git a/pkg/controller/backup_controller_test.go b/pkg/controller/backup_controller_test.go index 03df45b8a..94230fafd 100644 --- a/pkg/controller/backup_controller_test.go +++ b/pkg/controller/backup_controller_test.go @@ -17,8 +17,10 @@ limitations under the License. package controller import ( + "bytes" "encoding/json" "io" + "strings" "testing" "time" @@ -201,7 +203,15 @@ func TestProcessBackup(t *testing.T) { backup.Status.Version = 1 backupper.On("Backup", backup, mock.Anything, mock.Anything, mock.Anything).Return(nil) - cloudBackups.On("UploadBackup", "bucket", backup.Name, mock.Anything, mock.Anything, mock.Anything).Return(nil) + // Ensure we have a CompletionTimestamp when uploading. + // Failures will display the bytes in buf. + completionTimestampIsPresent := func(buf *bytes.Buffer) bool { + json := buf.String() + timeString := `"completionTimestamp": "2006-01-02T15:04:05Z"` + + return strings.Contains(json, timeString) + } + cloudBackups.On("UploadBackup", "bucket", backup.Name, mock.MatchedBy(completionTimestampIsPresent), mock.Anything, mock.Anything).Return(nil) pluginManager.On("GetBackupItemActions", backup.Name).Return(nil, nil) pluginManager.On("CloseBackupItemActions", backup.Name).Return(nil)