Add back code and tests

Signed-off-by: Carlisia <carlisiac@vmware.com>
pull/1390/head
Carlisia 2019-04-23 16:19:00 -07:00
parent c59d03dfb1
commit 38ccb40ca1
No known key found for this signature in database
GPG Key ID: EE2E6F4D2C4B7117
6 changed files with 330 additions and 172 deletions

View File

@ -37,9 +37,97 @@ const (
storageAccountConfigKey = "storageAccount" storageAccountConfigKey = "storageAccount"
) )
type containerGetter interface {
getContainer(bucket string) (container, error)
}
type azureContainerGetter struct {
blobService *storage.BlobStorageClient
}
func (cg *azureContainerGetter) getContainer(bucket string) (container, error) {
container := cg.blobService.GetContainerReference(bucket)
if container == nil {
return nil, errors.Errorf("unable to get container reference for bucket %v", bucket)
}
return &azureContainer{
container: container,
}, nil
}
type container interface {
ListBlobs(params storage.ListBlobsParameters) (storage.BlobListResponse, error)
}
type azureContainer struct {
container *storage.Container
}
func (c *azureContainer) ListBlobs(params storage.ListBlobsParameters) (storage.BlobListResponse, error) {
return c.container.ListBlobs(params)
}
type blobGetter interface {
getBlob(bucket, key string) (blob, error)
}
type azureBlobGetter struct {
blobService *storage.BlobStorageClient
}
func (bg *azureBlobGetter) getBlob(bucket, key string) (blob, error) {
container := bg.blobService.GetContainerReference(bucket)
if container == nil {
return nil, errors.Errorf("unable to get container reference for bucket %v", bucket)
}
blob := container.GetBlobReference(key)
if blob == nil {
return nil, errors.Errorf("unable to get blob reference for key %v", key)
}
return &azureBlob{
blob: blob,
}, nil
}
type blob interface {
CreateBlockBlobFromReader(blob io.Reader, options *storage.PutBlobOptions) error
Exists() (bool, error)
Get(options *storage.GetBlobOptions) (io.ReadCloser, error)
Delete(options *storage.DeleteBlobOptions) error
GetSASURI(options *storage.BlobSASOptions) (string, error)
}
type azureBlob struct {
blob *storage.Blob
}
func (b *azureBlob) CreateBlockBlobFromReader(blob io.Reader, options *storage.PutBlobOptions) error {
return b.blob.CreateBlockBlobFromReader(blob, options)
}
func (b *azureBlob) Exists() (bool, error) {
return b.blob.Exists()
}
func (b *azureBlob) Get(options *storage.GetBlobOptions) (io.ReadCloser, error) {
return b.blob.Get(options)
}
func (b *azureBlob) Delete(options *storage.DeleteBlobOptions) error {
return b.blob.Delete(options)
}
func (b *azureBlob) GetSASURI(options *storage.BlobSASOptions) (string, error) {
return b.blob.GetSASURI(*options)
}
type ObjectStore struct { type ObjectStore struct {
blobClient *storage.BlobStorageClient containerGetter containerGetter
log logrus.FieldLogger blobGetter blobGetter
log logrus.FieldLogger
} }
func NewObjectStore(logger logrus.FieldLogger) *ObjectStore { func NewObjectStore(logger logrus.FieldLogger) *ObjectStore {
@ -122,18 +210,18 @@ func (o *ObjectStore) Init(config map[string]string) error {
} }
blobClient := storageClient.GetBlobService() blobClient := storageClient.GetBlobService()
o.blobClient = &blobClient o.containerGetter = &azureContainerGetter{
blobService: &blobClient,
}
o.blobGetter = &azureBlobGetter{
blobService: &blobClient,
}
return nil return nil
} }
func (o *ObjectStore) PutObject(bucket, key string, body io.Reader) error { func (o *ObjectStore) PutObject(bucket, key string, body io.Reader) error {
container, err := getContainerReference(o.blobClient, bucket) blob, err := o.blobGetter.getBlob(bucket, key)
if err != nil {
return err
}
blob, err := getBlobReference(container, key)
if err != nil { if err != nil {
return err return err
} }
@ -142,12 +230,7 @@ func (o *ObjectStore) PutObject(bucket, key string, body io.Reader) error {
} }
func (o *ObjectStore) ObjectExists(bucket, key string) (bool, error) { func (o *ObjectStore) ObjectExists(bucket, key string) (bool, error) {
container, err := getContainerReference(o.blobClient, bucket) blob, err := o.blobGetter.getBlob(bucket, key)
if err != nil {
return false, err
}
blob, err := getBlobReference(container, key)
if err != nil { if err != nil {
return false, err return false, err
} }
@ -161,12 +244,7 @@ func (o *ObjectStore) ObjectExists(bucket, key string) (bool, error) {
} }
func (o *ObjectStore) GetObject(bucket, key string) (io.ReadCloser, error) { func (o *ObjectStore) GetObject(bucket, key string) (io.ReadCloser, error) {
container, err := getContainerReference(o.blobClient, bucket) blob, err := o.blobGetter.getBlob(bucket, key)
if err != nil {
return nil, err
}
blob, err := getBlobReference(container, key)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -180,7 +258,7 @@ func (o *ObjectStore) GetObject(bucket, key string) (io.ReadCloser, error) {
} }
func (o *ObjectStore) ListCommonPrefixes(bucket, prefix, delimiter string) ([]string, error) { func (o *ObjectStore) ListCommonPrefixes(bucket, prefix, delimiter string) ([]string, error) {
container, err := getContainerReference(o.blobClient, bucket) container, err := o.containerGetter.getContainer(bucket)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -199,7 +277,7 @@ func (o *ObjectStore) ListCommonPrefixes(bucket, prefix, delimiter string) ([]st
} }
func (o *ObjectStore) ListObjects(bucket, prefix string) ([]string, error) { func (o *ObjectStore) ListObjects(bucket, prefix string) ([]string, error) {
container, err := getContainerReference(o.blobClient, bucket) container, err := o.containerGetter.getContainer(bucket)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -222,12 +300,7 @@ func (o *ObjectStore) ListObjects(bucket, prefix string) ([]string, error) {
} }
func (o *ObjectStore) DeleteObject(bucket string, key string) error { func (o *ObjectStore) DeleteObject(bucket string, key string) error {
container, err := getContainerReference(o.blobClient, bucket) blob, err := o.blobGetter.getBlob(bucket, key)
if err != nil {
return err
}
blob, err := getBlobReference(container, key)
if err != nil { if err != nil {
return err return err
} }
@ -236,12 +309,7 @@ func (o *ObjectStore) DeleteObject(bucket string, key string) error {
} }
func (o *ObjectStore) CreateSignedURL(bucket, key string, ttl time.Duration) (string, error) { func (o *ObjectStore) CreateSignedURL(bucket, key string, ttl time.Duration) (string, error) {
container, err := getContainerReference(o.blobClient, bucket) blob, err := o.blobGetter.getBlob(bucket, key)
if err != nil {
return "", err
}
blob, err := getBlobReference(container, key)
if err != nil { if err != nil {
return "", err return "", err
} }
@ -255,23 +323,5 @@ func (o *ObjectStore) CreateSignedURL(bucket, key string, ttl time.Duration) (st
}, },
} }
return blob.GetSASURI(opts) return blob.GetSASURI(&opts)
}
func getContainerReference(blobClient *storage.BlobStorageClient, bucket string) (*storage.Container, error) {
container := blobClient.GetContainerReference(bucket)
if container == nil {
return nil, errors.Errorf("unable to get container reference for bucket %v", bucket)
}
return container, nil
}
func getBlobReference(container *storage.Container, key string) (*storage.Blob, error) {
blob := container.GetBlobReference(key)
if blob == nil {
return nil, errors.Errorf("unable to get blob reference for key %v", key)
}
return blob, nil
} }

View File

@ -17,68 +17,16 @@ limitations under the License.
package azure package azure
import ( import (
"io"
"testing" "testing"
"github.com/Azure/azure-sdk-for-go/storage"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock" "github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
) )
// type mockBlobGetter struct {
// mock.Mock
// }
// func (m *mockBlobGetter) getBlob(bucket string, key string) (blob, error) {
// args := m.Called(bucket, key)
// return args.Get(0).(blob), args.Error(1)
// }
// type mockBlob struct {
// mock.Mock
// }
// func (m *mockBlob) CreateBlockBlobFromReader(blob io.Reader, options *storage.PutBlobOptions) error {
// args := m.Called(blob, options)
// return args.Error(0)
// }
// func (m *mockBlob) Exists() (bool, error) {
// args := m.Called()
// return args.Bool(0), args.Error(1)
// }
// func (m *mockBlob) Get(options *storage.GetBlobOptions) (io.ReadCloser, error) {
// args := m.Called(options)
// return args.Get(0).(io.ReadCloser), args.Error(1)
// }
// func (m *mockBlob) Delete(options *storage.DeleteBlobOptions) error {
// args := m.Called(options)
// return args.Error(0)
// }
// func (m *mockBlob) GetSASURI(expiry time.Time, permissions string) (string, error) {
// args := m.Called(expiry, permissions)
// return args.String(0), args.Error(1)
// }
// type mockContainerGetter struct {
// mock.Mock
// }
// func (m *mockContainerGetter) getContainer(bucket string) (container, error) {
// args := m.Called(bucket)
// return args.Get(0).(container), args.Error(1)
// }
// type mockContainer struct {
// mock.Mock
// }
// func (m *mockContainer) ListBlobs(params storage.ListBlobsParameters) (storage.BlobListResponse, error) {
// args := m.Called(params)
// return args.Get(0).(storage.BlobListResponse), args.Error(1)
// }
func TestObjectExists(t *testing.T) { func TestObjectExists(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
@ -116,69 +64,89 @@ func TestObjectExists(t *testing.T) {
}, },
} }
// for _, tc := range tests {
// t.Run(tc.name, func(t *testing.T) {
// blobGetter := new(mockBlobGetter)
// defer blobGetter.AssertExpectations(t)
// o := &objectStore{
// blobGetter: blobGetter,
// }
// bucket := "b"
// key := "k"
// blob := new(mockBlob)
// defer blob.AssertExpectations(t)
// blobGetter.On("getBlob", bucket, key).Return(blob, tc.getBlobError)
// blob.On("Exists").Return(tc.exists, tc.errorResponse)
// exists, err := o.ObjectExists(bucket, key)
// if tc.expectedError != "" {
// assert.EqualError(t, err, tc.expectedError)
// return
// }
// require.NoError(t, err)
// assert.Equal(t, tc.expectedExists, exists)
// })
// }
for _, tc := range tests { for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
// o := NewObjectStore(velerotest.NewLogger()) blobGetter := new(mockBlobGetter)
defer blobGetter.AssertExpectations(t)
// bucket := "b" o := &ObjectStore{
// key := "k" blobGetter: blobGetter,
}
// // container := new(mockContainer) bucket := "b"
// // container.On("getContainerReference", nil, bucket) key := "k"
// blob := new(mockBlob) blob := new(mockBlob)
// defer blob.AssertExpectations(t) defer blob.AssertExpectations(t)
// // blob.On("getBlobReference", container, key).Return(blob, tc.getBlobError) blobGetter.On("getBlob", bucket, key).Return(blob, tc.getBlobError)
// blob.On("Exists").Return(tc.exists, tc.errorResponse)
// exists, err := o.ObjectExists(bucket, key) blob.On("Exists").Return(tc.exists, tc.errorResponse)
// if tc.expectedError != "" { exists, err := o.ObjectExists(bucket, key)
// assert.EqualError(t, err, tc.expectedError)
// return
// }
// require.NoError(t, err)
// assert.Equal(t, tc.expectedExists, exists) if tc.expectedError != "" {
assert.EqualError(t, err, tc.expectedError)
return
}
require.NoError(t, err)
assert.Equal(t, tc.expectedExists, exists)
}) })
} }
} }
type mockBlobGetter struct {
mock.Mock
}
func (m *mockBlobGetter) getBlob(bucket string, key string) (blob, error) {
args := m.Called(bucket, key)
return args.Get(0).(blob), args.Error(1)
}
type mockBlob struct { type mockBlob struct {
mock.Mock mock.Mock
} }
func (m *mockBlob) CreateBlockBlobFromReader(blob io.Reader, options *storage.PutBlobOptions) error {
args := m.Called(blob, options)
return args.Error(0)
}
func (m *mockBlob) Exists() (bool, error) { func (m *mockBlob) Exists() (bool, error) {
args := m.Called() args := m.Called()
return args.Bool(0), args.Error(1) return args.Bool(0), args.Error(1)
} }
func (m *mockBlob) Get(options *storage.GetBlobOptions) (io.ReadCloser, error) {
args := m.Called(options)
return args.Get(0).(io.ReadCloser), args.Error(1)
}
func (m *mockBlob) Delete(options *storage.DeleteBlobOptions) error {
args := m.Called(options)
return args.Error(0)
}
func (m *mockBlob) GetSASURI(options *storage.BlobSASOptions) (string, error) {
args := m.Called(options)
return args.String(0), args.Error(1)
}
type mockContainerGetter struct {
mock.Mock
}
func (m *mockContainerGetter) getContainer(bucket string) (container, error) {
args := m.Called(bucket)
return args.Get(0).(container), args.Error(1)
}
type mockContainer struct {
mock.Mock
}
func (m *mockContainer) ListBlobs(params storage.ListBlobsParameters) (storage.BlobListResponse, error) {
args := m.Called(params)
return args.Get(0).(storage.BlobListResponse), args.Error(1)
}

View File

@ -158,19 +158,22 @@ func (c *backupController) processBackup(key string) error {
log.Debug("Running processBackup") log.Debug("Running processBackup")
ns, name, err := cache.SplitMetaNamespaceKey(key) ns, name, err := cache.SplitMetaNamespaceKey(key)
if err != nil { if err != nil {
return errors.Wrap(err, "error splitting queue key") log.WithError(err).Errorf("error splitting key")
return nil
} }
log.Debug("Getting backup") log.Debug("Getting backup")
original, err := c.lister.Backups(ns).Get(name) original, err := c.lister.Backups(ns).Get(name)
if apierrors.IsNotFound(err) { if apierrors.IsNotFound(err) {
log.Debug("backup not found") log.Debugf("backup %s not found", name)
return nil return nil
} }
if err != nil { if err != nil {
return errors.Wrap(err, "error getting backup") return errors.Wrap(err, "error getting backup")
} }
fmt.Println("original name is.....---- ", original.Name)
// Double-check we have the correct phase. In the unlikely event that multiple controller // Double-check we have the correct phase. In the unlikely event that multiple controller
// instances are running, it's possible for controller A to succeed in changing the phase to // instances are running, it's possible for controller A to succeed in changing the phase to
// InProgress, while controller B's attempt to patch the phase fails. When controller B // InProgress, while controller B's attempt to patch the phase fails. When controller B
@ -196,6 +199,9 @@ func (c *backupController) processBackup(key string) error {
request.Status.StartTimestamp.Time = c.clock.Now() request.Status.StartTimestamp.Time = c.clock.Now()
} }
fmt.Println("request.Backup.Name name is.....---- ", request.Backup.Name)
fmt.Println("original name is.....---- ", original.Name)
// update status // update status
updatedBackup, err := patchBackup(original, request.Backup, c.client) updatedBackup, err := patchBackup(original, request.Backup, c.client)
if err != nil { if err != nil {
@ -284,11 +290,12 @@ func (c *backupController) prepareBackupRequest(backup *velerov1api.Backup) *pkg
} }
request.Labels[velerov1api.StorageLocationLabel] = request.Spec.StorageLocation request.Labels[velerov1api.StorageLocationLabel] = request.Spec.StorageLocation
// validate the included/excluded resources and namespaces // validate the included/excluded resources
for _, err := range collections.ValidateIncludesExcludes(request.Spec.IncludedResources, request.Spec.ExcludedResources) { for _, err := range collections.ValidateIncludesExcludes(request.Spec.IncludedResources, request.Spec.ExcludedResources) {
request.Status.ValidationErrors = append(request.Status.ValidationErrors, fmt.Sprintf("Invalid included/excluded resource lists: %v", err)) request.Status.ValidationErrors = append(request.Status.ValidationErrors, fmt.Sprintf("Invalid included/excluded resource lists: %v", err))
} }
// validate the included/excluded namespaces
for _, err := range collections.ValidateIncludesExcludes(request.Spec.IncludedNamespaces, request.Spec.ExcludedNamespaces) { for _, err := range collections.ValidateIncludesExcludes(request.Spec.IncludedNamespaces, request.Spec.ExcludedNamespaces) {
request.Status.ValidationErrors = append(request.Status.ValidationErrors, fmt.Sprintf("Invalid included/excluded namespace lists: %v", err)) request.Status.ValidationErrors = append(request.Status.ValidationErrors, fmt.Sprintf("Invalid included/excluded namespace lists: %v", err))
} }
@ -410,6 +417,8 @@ func (c *backupController) validateAndGetSnapshotLocations(backup *velerov1api.B
} }
func (c *backupController) runBackup(backup *pkgbackup.Request) error { func (c *backupController) runBackup(backup *pkgbackup.Request) error {
fmt.Println("runbackup name is.....---- ", backup.Name)
log := c.logger.WithField("backup", kubeutil.NamespaceAndName(backup)) log := c.logger.WithField("backup", kubeutil.NamespaceAndName(backup))
log.Info("Starting backup") log.Info("Starting backup")
@ -451,6 +460,12 @@ func (c *backupController) runBackup(backup *pkgbackup.Request) error {
} }
var errs []error var errs []error
errs = append(errs, validateUniqueness(backupStore, backup.StorageLocation.Spec.StorageType.ObjectStorage.Bucket, backup.Name)...)
if len(errs) > 0 {
backup.Status.Phase = velerov1api.BackupPhaseFailed
backup.Status.CompletionTimestamp.Time = c.clock.Now()
return kerrors.NewAggregate(errs)
}
// Do the actual backup // Do the actual backup
if err := c.backupper.Backup(log, backup, backupFile, actions, pluginManager); err != nil { if err := c.backupper.Backup(log, backup, backupFile, actions, pluginManager); err != nil {
@ -483,6 +498,18 @@ func (c *backupController) runBackup(backup *pkgbackup.Request) error {
return kerrors.NewAggregate(errs) return kerrors.NewAggregate(errs)
} }
func validateUniqueness(backupStore persistence.BackupStore, bucket, name string) []error {
var errs []error
exists, err := backupStore.BackupExists(bucket, name)
if err != nil {
errs = append(errs, errors.Errorf("Error checking if backup already exists in object storage: %v", err))
}
if exists {
errs = append(errs, errors.Errorf("Backup already exists in object storage"))
}
return errs
}
func recordBackupMetrics(backup *velerov1api.Backup, backupFile *os.File, serverMetrics *metrics.ServerMetrics) error { func recordBackupMetrics(backup *velerov1api.Backup, backupFile *os.File, serverMetrics *metrics.ServerMetrics) error {
backupScheduleName := backup.GetLabels()[velerov1api.ScheduleNameLabel] backupScheduleName := backup.GetLabels()[velerov1api.ScheduleNameLabel]

View File

@ -56,23 +56,24 @@ func (b *fakeBackupper) Backup(logger logrus.FieldLogger, backup *pkgbackup.Requ
return args.Error(0) return args.Error(0)
} }
func TestProcessBackupNonProcessedItems(t *testing.T) { func TestProcessBackupProcessing(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
key string key string
backup *v1.Backup backup *v1.Backup
expectedErr string expectedErr string
}{ }{
// processed successfully
{ {
name: "bad key returns error", name: "bad key does not return error",
key: "bad/key/here", key: "bad/key/here",
expectedErr: "error splitting queue key: unexpected key format: \"bad/key/here\"",
}, },
{ {
name: "backup not found in lister returns error", name: "backup not found in lister does not return error",
key: "nonexistent/backup", key: "nonexistent/backup",
expectedErr: "error getting backup: backup.velero.io \"backup\" not found",
}, },
// skipped
{ {
name: "FailedValidation backup is not processed", name: "FailedValidation backup is not processed",
key: "velero/backup-1", key: "velero/backup-1",
@ -255,18 +256,21 @@ func TestDefaultBackupTTL(t *testing.T) {
} }
func TestProcessBackupCompletions(t *testing.T) { func TestProcessBackupCompletions(t *testing.T) {
defaultBackupLocation := velerotest.NewTestBackupStorageLocation().WithName("loc-1").BackupStorageLocation defaultBackupLocation := velerotest.NewTestBackupStorageLocation().WithName("loc-1").WithObjectStorage("store-1").BackupStorageLocation
now, err := time.Parse(time.RFC1123Z, time.RFC1123Z) now, err := time.Parse(time.RFC1123Z, time.RFC1123Z)
require.NoError(t, err) require.NoError(t, err)
now = now.Local() now = now.Local()
tests := []struct { tests := []struct {
name string name string
backup *v1.Backup backup *v1.Backup
backupLocation *v1.BackupStorageLocation backupLocation *v1.BackupStorageLocation
expectedResult *v1.Backup expectedResult *v1.Backup
backupExists bool
existenceCheckError error
}{ }{
// Completed
{ {
name: "backup with no backup location gets the default", name: "backup with no backup location gets the default",
backup: velerotest.NewTestBackup().WithName("backup-1").Backup, backup: velerotest.NewTestBackup().WithName("backup-1").Backup,
@ -294,7 +298,7 @@ func TestProcessBackupCompletions(t *testing.T) {
{ {
name: "backup with a specific backup location keeps it", name: "backup with a specific backup location keeps it",
backup: velerotest.NewTestBackup().WithName("backup-1").WithStorageLocation("alt-loc").Backup, backup: velerotest.NewTestBackup().WithName("backup-1").WithStorageLocation("alt-loc").Backup,
backupLocation: velerotest.NewTestBackupStorageLocation().WithName("alt-loc").BackupStorageLocation, backupLocation: velerotest.NewTestBackupStorageLocation().WithName("alt-loc").WithObjectStorage("store-1").BackupStorageLocation,
expectedResult: &v1.Backup{ expectedResult: &v1.Backup{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Namespace: v1.DefaultNamespace, Namespace: v1.DefaultNamespace,
@ -340,6 +344,83 @@ func TestProcessBackupCompletions(t *testing.T) {
}, },
}, },
}, },
{
name: "backup with existing backup will fail",
backupExists: false,
backup: velerotest.NewTestBackup().WithName("backup-1").Backup,
backupLocation: defaultBackupLocation,
expectedResult: &v1.Backup{
ObjectMeta: metav1.ObjectMeta{
Namespace: v1.DefaultNamespace,
Name: "backup-1",
Labels: map[string]string{
"velero.io/storage-location": "loc-1",
},
},
Spec: v1.BackupSpec{
StorageLocation: defaultBackupLocation.Name,
},
Status: v1.BackupStatus{
Phase: v1.BackupPhaseCompleted,
Version: 1,
StartTimestamp: metav1.NewTime(now),
CompletionTimestamp: metav1.NewTime(now),
Expiration: metav1.NewTime(now),
},
},
},
// Failed
{
name: "backup with existing backup will fail",
backupExists: true,
backup: velerotest.NewTestBackup().WithName("backup-1").Backup,
backupLocation: defaultBackupLocation,
expectedResult: &v1.Backup{
ObjectMeta: metav1.ObjectMeta{
Namespace: v1.DefaultNamespace,
Name: "backup-1",
Labels: map[string]string{
"velero.io/storage-location": "loc-1",
},
},
Spec: v1.BackupSpec{
StorageLocation: defaultBackupLocation.Name,
},
Status: v1.BackupStatus{
Phase: v1.BackupPhaseFailed,
Version: 1,
StartTimestamp: metav1.NewTime(now),
CompletionTimestamp: metav1.NewTime(now),
Expiration: metav1.NewTime(now),
},
},
},
{
name: "error when checking if backup exists will cause backup to fail",
backup: velerotest.NewTestBackup().WithName("backup-1").Backup,
existenceCheckError: errors.New("Backup already exists in object storage"),
backupLocation: defaultBackupLocation,
expectedResult: &v1.Backup{
ObjectMeta: metav1.ObjectMeta{
Namespace: v1.DefaultNamespace,
Name: "backup-1",
Labels: map[string]string{
"velero.io/storage-location": "loc-1",
},
},
Spec: v1.BackupSpec{
StorageLocation: defaultBackupLocation.Name,
},
Status: v1.BackupStatus{
Phase: v1.BackupPhaseFailed,
Version: 1,
StartTimestamp: metav1.NewTime(now),
CompletionTimestamp: metav1.NewTime(now),
Expiration: metav1.NewTime(now),
},
},
},
} }
for _, test := range tests { for _, test := range tests {
@ -380,6 +461,7 @@ func TestProcessBackupCompletions(t *testing.T) {
completionTimestampIsPresent := func(buf *bytes.Buffer) bool { completionTimestampIsPresent := func(buf *bytes.Buffer) bool {
return strings.Contains(buf.String(), `"completionTimestamp": "2006-01-02T22:04:05Z"`) return strings.Contains(buf.String(), `"completionTimestamp": "2006-01-02T22:04:05Z"`)
} }
backupStore.On("BackupExists", test.backupLocation.Spec.StorageType.ObjectStorage.Bucket, test.backup.Name).Return(test.backupExists, test.existenceCheckError)
backupStore.On("PutBackup", test.backup.Name, mock.MatchedBy(completionTimestampIsPresent), mock.Anything, mock.Anything, mock.Anything).Return(nil) backupStore.On("PutBackup", test.backup.Name, mock.MatchedBy(completionTimestampIsPresent), mock.Anything, mock.Anything, mock.Anything).Return(nil)
// add the test's backup to the informer/lister store // add the test's backup to the informer/lister store
@ -406,6 +488,8 @@ func TestProcessBackupCompletions(t *testing.T) {
res, err := clientset.VeleroV1().Backups(test.backup.Namespace).Get(test.backup.Name, metav1.GetOptions{}) res, err := clientset.VeleroV1().Backups(test.backup.Namespace).Get(test.backup.Name, metav1.GetOptions{})
require.NoError(t, err) require.NoError(t, err)
// failed tests for failed backup should have a phase of failed
assert.Equal(t, test.expectedResult, res) assert.Equal(t, test.expectedResult, res)
}) })
} }

View File

@ -63,6 +63,27 @@ func (_m *BackupStore) GetBackupContents(name string) (io.ReadCloser, error) {
return r0, r1 return r0, r1
} }
// BackupExists provides a mock function with given fields: bucket, backupName
func (_m *BackupStore) BackupExists(bucket string, backupName string) (bool, error) {
ret := _m.Called(bucket, backupName)
var r0 bool
if rf, ok := ret.Get(0).(func(string, string) bool); ok {
r0 = rf(bucket, backupName)
} else {
r0 = ret.Get(0).(bool)
}
var r1 error
if rf, ok := ret.Get(1).(func(string, string) error); ok {
r1 = rf(bucket, backupName)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// GetBackupMetadata provides a mock function with given fields: name // GetBackupMetadata provides a mock function with given fields: name
func (_m *BackupStore) GetBackupMetadata(name string) (*v1.Backup, error) { func (_m *BackupStore) GetBackupMetadata(name string) (*v1.Backup, error) {
ret := _m.Called(name) ret := _m.Called(name)

View File

@ -47,6 +47,10 @@ type BackupStore interface {
GetBackupMetadata(name string) (*velerov1api.Backup, error) GetBackupMetadata(name string) (*velerov1api.Backup, error)
GetBackupVolumeSnapshots(name string) ([]*volume.Snapshot, error) GetBackupVolumeSnapshots(name string) ([]*volume.Snapshot, error)
GetBackupContents(name string) (io.ReadCloser, error) GetBackupContents(name string) (io.ReadCloser, error)
// BackupExists checks if the backup metadata file exists in object storage.
BackupExists(bucket, backupName string) (bool, error)
DeleteBackup(name string) error DeleteBackup(name string) error
PutRestoreLog(backup, restore string, log io.Reader) error PutRestoreLog(backup, restore string, log io.Reader) error
@ -288,6 +292,10 @@ func (s *objectBackupStore) GetBackupContents(name string) (io.ReadCloser, error
return s.objectStore.GetObject(s.bucket, s.layout.getBackupContentsKey(name)) return s.objectStore.GetObject(s.bucket, s.layout.getBackupContentsKey(name))
} }
func (s *objectBackupStore) BackupExists(bucket, backupName string) (bool, error) {
return s.objectStore.ObjectExists(bucket, s.layout.getBackupMetadataKey(backupName))
}
func (s *objectBackupStore) DeleteBackup(name string) error { func (s *objectBackupStore) DeleteBackup(name string) error {
objects, err := s.objectStore.ListObjects(s.bucket, s.layout.getBackupDir(name)) objects, err := s.objectStore.ListObjects(s.bucket, s.layout.getBackupDir(name))
if err != nil { if err != nil {