2017-08-02 17:27:17 +00:00
/ *
2019-03-20 19:32:48 +00:00
Copyright 2017 the Velero contributors .
2017-08-02 17:27:17 +00:00
Licensed under the Apache License , Version 2.0 ( the "License" ) ;
you may not use this file except in compliance with the License .
You may obtain a copy of the License at
http : //www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing , software
distributed under the License is distributed on an "AS IS" BASIS ,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
See the License for the specific language governing permissions and
limitations under the License .
* /
package controller
import (
2018-07-10 22:17:53 +00:00
"bytes"
2018-09-26 22:18:45 +00:00
"fmt"
2017-08-02 17:27:17 +00:00
"io"
2018-09-26 22:18:45 +00:00
"sort"
2018-07-10 22:17:53 +00:00
"strings"
2017-08-02 17:27:17 +00:00
"testing"
"time"
2018-09-25 14:51:28 +00:00
"github.com/pkg/errors"
2018-08-20 23:29:54 +00:00
"github.com/sirupsen/logrus"
2018-09-26 22:18:45 +00:00
"github.com/stretchr/testify/assert"
2018-08-20 23:29:54 +00:00
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
2018-06-20 18:08:07 +00:00
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2017-08-02 17:27:17 +00:00
"k8s.io/apimachinery/pkg/util/clock"
2019-01-25 03:33:07 +00:00
v1 "github.com/heptio/velero/pkg/apis/velero/v1"
pkgbackup "github.com/heptio/velero/pkg/backup"
"github.com/heptio/velero/pkg/generated/clientset/versioned/fake"
informers "github.com/heptio/velero/pkg/generated/informers/externalversions"
"github.com/heptio/velero/pkg/metrics"
"github.com/heptio/velero/pkg/persistence"
persistencemocks "github.com/heptio/velero/pkg/persistence/mocks"
2019-03-15 18:32:11 +00:00
"github.com/heptio/velero/pkg/plugin/clientmgmt"
2019-01-25 03:33:07 +00:00
pluginmocks "github.com/heptio/velero/pkg/plugin/mocks"
2019-03-14 20:35:06 +00:00
"github.com/heptio/velero/pkg/plugin/velero"
2019-01-25 03:33:07 +00:00
"github.com/heptio/velero/pkg/util/logging"
velerotest "github.com/heptio/velero/pkg/util/test"
2017-08-02 17:27:17 +00:00
)
type fakeBackupper struct {
mock . Mock
}
2019-03-27 18:22:04 +00:00
func ( b * fakeBackupper ) Backup ( logger logrus . FieldLogger , backup * pkgbackup . Request , backupFile io . Writer , actions [ ] velero . BackupItemAction , volumeSnapshotterGetter pkgbackup . VolumeSnapshotterGetter ) error {
args := b . Called ( logger , backup , backupFile , actions , volumeSnapshotterGetter )
2017-08-02 17:27:17 +00:00
return args . Error ( 0 )
}
2019-04-23 23:19:00 +00:00
func TestProcessBackupProcessing ( t * testing . T ) {
2017-08-02 17:27:17 +00:00
tests := [ ] struct {
2018-09-26 22:18:45 +00:00
name string
key string
backup * v1 . Backup
expectedErr string
2017-08-02 17:27:17 +00:00
} {
2019-04-23 23:19:00 +00:00
// processed successfully
2017-08-02 17:27:17 +00:00
{
2019-04-23 23:19:00 +00:00
name : "bad key does not return error" ,
key : "bad/key/here" ,
2017-08-02 17:27:17 +00:00
} ,
{
2019-04-23 23:19:00 +00:00
name : "backup not found in lister does not return error" ,
key : "nonexistent/backup" ,
2017-08-02 17:27:17 +00:00
} ,
2019-04-23 23:19:00 +00:00
// skipped
2017-08-02 17:27:17 +00:00
{
2018-09-26 22:18:45 +00:00
name : "FailedValidation backup is not processed" ,
2019-01-25 03:33:07 +00:00
key : "velero/backup-1" ,
backup : velerotest . NewTestBackup ( ) . WithName ( "backup-1" ) . WithPhase ( v1 . BackupPhaseFailedValidation ) . Backup ,
2017-08-02 17:27:17 +00:00
} ,
{
2018-09-26 22:18:45 +00:00
name : "InProgress backup is not processed" ,
2019-01-25 03:33:07 +00:00
key : "velero/backup-1" ,
backup : velerotest . NewTestBackup ( ) . WithName ( "backup-1" ) . WithPhase ( v1 . BackupPhaseInProgress ) . Backup ,
2017-08-02 17:27:17 +00:00
} ,
{
2018-09-26 22:18:45 +00:00
name : "Completed backup is not processed" ,
2019-01-25 03:33:07 +00:00
key : "velero/backup-1" ,
backup : velerotest . NewTestBackup ( ) . WithName ( "backup-1" ) . WithPhase ( v1 . BackupPhaseCompleted ) . Backup ,
2017-08-02 17:27:17 +00:00
} ,
{
2018-09-26 22:18:45 +00:00
name : "Failed backup is not processed" ,
2019-01-25 03:33:07 +00:00
key : "velero/backup-1" ,
backup : velerotest . NewTestBackup ( ) . WithName ( "backup-1" ) . WithPhase ( v1 . BackupPhaseFailed ) . Backup ,
2017-08-09 22:52:27 +00:00
} ,
2018-09-26 22:18:45 +00:00
}
for _ , test := range tests {
t . Run ( test . name , func ( t * testing . T ) {
var (
sharedInformers = informers . NewSharedInformerFactory ( fake . NewSimpleClientset ( ) , 0 )
logger = logging . DefaultLogger ( logrus . DebugLevel )
)
c := & backupController {
genericController : newGenericController ( "backup-test" , logger ) ,
2019-01-25 03:33:07 +00:00
lister : sharedInformers . Velero ( ) . V1 ( ) . Backups ( ) . Lister ( ) ,
2018-09-26 22:18:45 +00:00
}
if test . backup != nil {
2019-01-25 03:33:07 +00:00
require . NoError ( t , sharedInformers . Velero ( ) . V1 ( ) . Backups ( ) . Informer ( ) . GetStore ( ) . Add ( test . backup ) )
2018-09-26 22:18:45 +00:00
}
err := c . processBackup ( test . key )
if test . expectedErr != "" {
require . Error ( t , err )
assert . Equal ( t , test . expectedErr , err . Error ( ) )
} else {
assert . Nil ( t , err )
}
// Any backup that would actually proceed to validation will cause a segfault because this
// test hasn't set up the necessary controller dependencies for validation/etc. So the lack
// of segfaults during test execution here imply that backups are not being processed, which
// is what we expect.
} )
}
}
func TestProcessBackupValidationFailures ( t * testing . T ) {
2019-01-25 03:33:07 +00:00
defaultBackupLocation := velerotest . NewTestBackupStorageLocation ( ) . WithName ( "loc-1" ) . BackupStorageLocation
2018-09-26 22:18:45 +00:00
tests := [ ] struct {
name string
backup * v1 . Backup
backupLocation * v1 . BackupStorageLocation
expectedErrs [ ] string
} {
2018-08-16 22:41:59 +00:00
{
2018-09-26 22:18:45 +00:00
name : "invalid included/excluded resources fails validation" ,
2019-01-25 03:33:07 +00:00
backup : velerotest . NewTestBackup ( ) . WithName ( "backup-1" ) . WithIncludedResources ( "foo" ) . WithExcludedResources ( "foo" ) . Backup ,
2018-09-26 22:18:45 +00:00
backupLocation : defaultBackupLocation ,
expectedErrs : [ ] string { "Invalid included/excluded resource lists: excludes list cannot contain an item in the includes list: foo" } ,
2018-08-16 22:41:59 +00:00
} ,
{
2018-09-26 22:18:45 +00:00
name : "invalid included/excluded namespaces fails validation" ,
2019-01-25 03:33:07 +00:00
backup : velerotest . NewTestBackup ( ) . WithName ( "backup-1" ) . WithIncludedNamespaces ( "foo" ) . WithExcludedNamespaces ( "foo" ) . Backup ,
2018-09-26 22:18:45 +00:00
backupLocation : defaultBackupLocation ,
expectedErrs : [ ] string { "Invalid included/excluded namespace lists: excludes list cannot contain an item in the includes list: foo" } ,
2018-08-16 22:41:59 +00:00
} ,
{
2018-09-26 22:18:45 +00:00
name : "non-existent backup location fails validation" ,
2019-01-25 03:33:07 +00:00
backup : velerotest . NewTestBackup ( ) . WithName ( "backup-1" ) . WithStorageLocation ( "nonexistent" ) . Backup ,
expectedErrs : [ ] string { "a BackupStorageLocation CRD with the name specified in the backup spec needs to be created before this backup can be executed. Error: backupstoragelocation.velero.io \"nonexistent\" not found" } ,
2018-08-16 22:41:59 +00:00
} ,
2017-08-02 17:27:17 +00:00
}
for _ , test := range tests {
t . Run ( test . name , func ( t * testing . T ) {
2017-09-14 21:27:31 +00:00
var (
2018-09-26 22:18:45 +00:00
clientset = fake . NewSimpleClientset ( test . backup )
sharedInformers = informers . NewSharedInformerFactory ( clientset , 0 )
2018-05-13 13:28:09 +00:00
logger = logging . DefaultLogger ( logrus . DebugLevel )
2017-09-14 21:27:31 +00:00
)
2018-08-20 23:29:54 +00:00
2018-09-26 22:18:45 +00:00
c := & backupController {
2018-10-26 15:32:46 +00:00
genericController : newGenericController ( "backup-test" , logger ) ,
2019-01-25 03:33:07 +00:00
client : clientset . VeleroV1 ( ) ,
lister : sharedInformers . Velero ( ) . V1 ( ) . Backups ( ) . Lister ( ) ,
backupLocationLister : sharedInformers . Velero ( ) . V1 ( ) . BackupStorageLocations ( ) . Lister ( ) ,
snapshotLocationLister : sharedInformers . Velero ( ) . V1 ( ) . VolumeSnapshotLocations ( ) . Lister ( ) ,
2018-10-26 15:32:46 +00:00
defaultBackupLocation : defaultBackupLocation . Name ,
2019-04-04 21:59:13 +00:00
clock : & clock . RealClock { } ,
2018-09-26 22:18:45 +00:00
}
2017-08-02 17:27:17 +00:00
2018-09-26 22:18:45 +00:00
require . NotNil ( t , test . backup )
2019-01-25 03:33:07 +00:00
require . NoError ( t , sharedInformers . Velero ( ) . V1 ( ) . Backups ( ) . Informer ( ) . GetStore ( ) . Add ( test . backup ) )
2017-08-02 17:27:17 +00:00
2018-09-26 22:18:45 +00:00
if test . backupLocation != nil {
2019-01-25 03:33:07 +00:00
_ , err := clientset . VeleroV1 ( ) . BackupStorageLocations ( test . backupLocation . Namespace ) . Create ( test . backupLocation )
2018-09-26 22:18:45 +00:00
require . NoError ( t , err )
2018-06-20 18:08:07 +00:00
2019-01-25 03:33:07 +00:00
require . NoError ( t , sharedInformers . Velero ( ) . V1 ( ) . BackupStorageLocations ( ) . Informer ( ) . GetStore ( ) . Add ( test . backupLocation ) )
2018-05-13 13:28:09 +00:00
}
2018-09-26 22:18:45 +00:00
require . NoError ( t , c . processBackup ( fmt . Sprintf ( "%s/%s" , test . backup . Namespace , test . backup . Name ) ) )
2017-08-02 17:27:17 +00:00
2019-01-25 03:33:07 +00:00
res , err := clientset . VeleroV1 ( ) . Backups ( test . backup . Namespace ) . Get ( test . backup . Name , metav1 . GetOptions { } )
2018-09-26 22:18:45 +00:00
require . NoError ( t , err )
2018-07-10 22:17:53 +00:00
2018-09-26 22:18:45 +00:00
assert . Equal ( t , v1 . BackupPhaseFailedValidation , res . Status . Phase )
assert . Equal ( t , test . expectedErrs , res . Status . ValidationErrors )
2017-08-02 17:27:17 +00:00
2018-09-26 22:18:45 +00:00
// Any backup that would actually proceed to processing will cause a segfault because this
// test hasn't set up the necessary controller dependencies for running backups. So the lack
// of segfaults during test execution here imply that backups are not being processed, which
// is what we expect.
} )
}
}
2017-12-11 22:10:52 +00:00
2019-04-04 21:59:13 +00:00
func TestDefaultBackupTTL ( t * testing . T ) {
var (
defaultBackupTTL = metav1 . Duration { Duration : 24 * 30 * time . Hour }
)
now , err := time . Parse ( time . RFC1123Z , time . RFC1123Z )
require . NoError ( t , err )
now = now . Local ( )
tests := [ ] struct {
name string
backup * v1 . Backup
backupLocation * v1 . BackupStorageLocation
expectedTTL metav1 . Duration
expectedExpiration metav1 . Time
} {
{
name : "backup with no TTL specified" ,
backup : velerotest . NewTestBackup ( ) . WithName ( "backup-1" ) . Backup ,
expectedTTL : defaultBackupTTL ,
expectedExpiration : metav1 . NewTime ( now . Add ( defaultBackupTTL . Duration ) ) ,
} ,
{
name : "backup with TTL specified" ,
backup : velerotest . NewTestBackup ( ) . WithName ( "backup-1" ) . WithTTL ( 1 * time . Hour ) . Backup ,
expectedTTL : metav1 . Duration { Duration : 1 * time . Hour } ,
expectedExpiration : metav1 . NewTime ( now . Add ( 1 * time . Hour ) ) ,
} ,
}
for _ , test := range tests {
var (
clientset = fake . NewSimpleClientset ( test . backup )
logger = logging . DefaultLogger ( logrus . DebugLevel )
sharedInformers = informers . NewSharedInformerFactory ( clientset , 0 )
)
t . Run ( test . name , func ( t * testing . T ) {
c := & backupController {
genericController : newGenericController ( "backup-test" , logger ) ,
backupLocationLister : sharedInformers . Velero ( ) . V1 ( ) . BackupStorageLocations ( ) . Lister ( ) ,
snapshotLocationLister : sharedInformers . Velero ( ) . V1 ( ) . VolumeSnapshotLocations ( ) . Lister ( ) ,
defaultBackupTTL : defaultBackupTTL . Duration ,
clock : clock . NewFakeClock ( now ) ,
}
res := c . prepareBackupRequest ( test . backup )
assert . NotNil ( t , res )
assert . Equal ( t , test . expectedTTL , res . Spec . TTL )
assert . Equal ( t , test . expectedExpiration , res . Status . Expiration )
} )
}
}
2018-09-26 22:18:45 +00:00
func TestProcessBackupCompletions ( t * testing . T ) {
2019-04-23 23:19:00 +00:00
defaultBackupLocation := velerotest . NewTestBackupStorageLocation ( ) . WithName ( "loc-1" ) . WithObjectStorage ( "store-1" ) . BackupStorageLocation
2017-12-11 22:10:52 +00:00
2018-09-26 22:18:45 +00:00
now , err := time . Parse ( time . RFC1123Z , time . RFC1123Z )
require . NoError ( t , err )
now = now . Local ( )
2017-12-11 22:10:52 +00:00
2018-09-26 22:18:45 +00:00
tests := [ ] struct {
2019-04-23 23:19:00 +00:00
name string
backup * v1 . Backup
backupLocation * v1 . BackupStorageLocation
expectedResult * v1 . Backup
backupExists bool
existenceCheckError error
2018-09-26 22:18:45 +00:00
} {
2019-04-23 23:19:00 +00:00
// Completed
2018-09-26 22:18:45 +00:00
{
name : "backup with no backup location gets the default" ,
2019-01-25 03:33:07 +00:00
backup : velerotest . NewTestBackup ( ) . WithName ( "backup-1" ) . Backup ,
2018-09-26 22:18:45 +00:00
backupLocation : defaultBackupLocation ,
expectedResult : & v1 . Backup {
ObjectMeta : metav1 . ObjectMeta {
Namespace : v1 . DefaultNamespace ,
Name : "backup-1" ,
Labels : map [ string ] string {
2019-01-25 03:33:07 +00:00
"velero.io/storage-location" : "loc-1" ,
2018-09-26 22:18:45 +00:00
} ,
} ,
Spec : v1 . BackupSpec {
StorageLocation : defaultBackupLocation . Name ,
} ,
Status : v1 . BackupStatus {
Phase : v1 . BackupPhaseCompleted ,
Version : 1 ,
StartTimestamp : metav1 . NewTime ( now ) ,
CompletionTimestamp : metav1 . NewTime ( now ) ,
2019-04-04 21:59:13 +00:00
Expiration : metav1 . NewTime ( now ) ,
2018-09-26 22:18:45 +00:00
} ,
} ,
} ,
{
name : "backup with a specific backup location keeps it" ,
2019-01-25 03:33:07 +00:00
backup : velerotest . NewTestBackup ( ) . WithName ( "backup-1" ) . WithStorageLocation ( "alt-loc" ) . Backup ,
2019-04-23 23:19:00 +00:00
backupLocation : velerotest . NewTestBackupStorageLocation ( ) . WithName ( "alt-loc" ) . WithObjectStorage ( "store-1" ) . BackupStorageLocation ,
2018-09-26 22:18:45 +00:00
expectedResult : & v1 . Backup {
ObjectMeta : metav1 . ObjectMeta {
Namespace : v1 . DefaultNamespace ,
Name : "backup-1" ,
Labels : map [ string ] string {
2019-01-25 03:33:07 +00:00
"velero.io/storage-location" : "alt-loc" ,
2018-09-26 22:18:45 +00:00
} ,
} ,
Spec : v1 . BackupSpec {
StorageLocation : "alt-loc" ,
} ,
Status : v1 . BackupStatus {
Phase : v1 . BackupPhaseCompleted ,
Version : 1 ,
StartTimestamp : metav1 . NewTime ( now ) ,
CompletionTimestamp : metav1 . NewTime ( now ) ,
2019-04-04 21:59:13 +00:00
Expiration : metav1 . NewTime ( now ) ,
2018-09-26 22:18:45 +00:00
} ,
} ,
} ,
{
name : "backup with a TTL has expiration set" ,
2019-01-25 03:33:07 +00:00
backup : velerotest . NewTestBackup ( ) . WithName ( "backup-1" ) . WithTTL ( 10 * time . Minute ) . Backup ,
2018-09-26 22:18:45 +00:00
backupLocation : defaultBackupLocation ,
expectedResult : & v1 . Backup {
ObjectMeta : metav1 . ObjectMeta {
Namespace : v1 . DefaultNamespace ,
Name : "backup-1" ,
Labels : map [ string ] string {
2019-01-25 03:33:07 +00:00
"velero.io/storage-location" : "loc-1" ,
2018-09-26 22:18:45 +00:00
} ,
} ,
Spec : v1 . BackupSpec {
TTL : metav1 . Duration { Duration : 10 * time . Minute } ,
StorageLocation : defaultBackupLocation . Name ,
} ,
Status : v1 . BackupStatus {
Phase : v1 . BackupPhaseCompleted ,
Version : 1 ,
Expiration : metav1 . NewTime ( now . Add ( 10 * time . Minute ) ) ,
StartTimestamp : metav1 . NewTime ( now ) ,
CompletionTimestamp : metav1 . NewTime ( now ) ,
} ,
} ,
} ,
2019-04-23 23:19:00 +00:00
{
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 ) ,
} ,
} ,
} ,
2018-09-26 22:18:45 +00:00
}
2017-12-11 22:10:52 +00:00
2018-09-26 22:18:45 +00:00
for _ , test := range tests {
t . Run ( test . name , func ( t * testing . T ) {
var (
clientset = fake . NewSimpleClientset ( test . backup )
sharedInformers = informers . NewSharedInformerFactory ( clientset , 0 )
logger = logging . DefaultLogger ( logrus . DebugLevel )
pluginManager = new ( pluginmocks . Manager )
backupStore = new ( persistencemocks . BackupStore )
backupper = new ( fakeBackupper )
)
2018-06-20 18:08:07 +00:00
2018-09-26 22:18:45 +00:00
c := & backupController {
2018-10-26 15:32:46 +00:00
genericController : newGenericController ( "backup-test" , logger ) ,
2019-01-25 03:33:07 +00:00
client : clientset . VeleroV1 ( ) ,
lister : sharedInformers . Velero ( ) . V1 ( ) . Backups ( ) . Lister ( ) ,
backupLocationLister : sharedInformers . Velero ( ) . V1 ( ) . BackupStorageLocations ( ) . Lister ( ) ,
snapshotLocationLister : sharedInformers . Velero ( ) . V1 ( ) . VolumeSnapshotLocations ( ) . Lister ( ) ,
2018-10-26 15:32:46 +00:00
defaultBackupLocation : defaultBackupLocation . Name ,
backupTracker : NewBackupTracker ( ) ,
metrics : metrics . NewServerMetrics ( ) ,
clock : clock . NewFakeClock ( now ) ,
2019-03-15 18:32:11 +00:00
newPluginManager : func ( logrus . FieldLogger ) clientmgmt . Manager { return pluginManager } ,
2018-09-26 22:18:45 +00:00
newBackupStore : func ( * v1 . BackupStorageLocation , persistence . ObjectStoreGetter , logrus . FieldLogger ) ( persistence . BackupStore , error ) {
return backupStore , nil
} ,
backupper : backupper ,
}
2017-08-02 17:27:17 +00:00
2018-09-26 22:18:45 +00:00
pluginManager . On ( "GetBackupItemActions" ) . Return ( nil , nil )
pluginManager . On ( "CleanupClients" ) . Return ( nil )
2017-08-02 17:27:17 +00:00
2019-03-14 20:35:06 +00:00
backupper . On ( "Backup" , mock . Anything , mock . Anything , mock . Anything , [ ] velero . BackupItemAction ( nil ) , pluginManager ) . Return ( nil )
2017-08-02 17:27:17 +00:00
2018-09-26 22:18:45 +00:00
// Ensure we have a CompletionTimestamp when uploading.
// Failures will display the bytes in buf.
completionTimestampIsPresent := func ( buf * bytes . Buffer ) bool {
return strings . Contains ( buf . String ( ) , ` "completionTimestamp": "2006-01-02T22:04:05Z" ` )
2017-08-02 17:27:17 +00:00
}
2019-04-23 23:19:00 +00:00
backupStore . On ( "BackupExists" , test . backupLocation . Spec . StorageType . ObjectStorage . Bucket , test . backup . Name ) . Return ( test . backupExists , test . existenceCheckError )
2018-10-12 17:55:02 +00:00
backupStore . On ( "PutBackup" , test . backup . Name , mock . MatchedBy ( completionTimestampIsPresent ) , mock . Anything , mock . Anything , mock . Anything ) . Return ( nil )
2017-08-02 17:27:17 +00:00
2018-09-26 22:18:45 +00:00
// add the test's backup to the informer/lister store
require . NotNil ( t , test . backup )
2019-01-25 03:33:07 +00:00
require . NoError ( t , sharedInformers . Velero ( ) . V1 ( ) . Backups ( ) . Informer ( ) . GetStore ( ) . Add ( test . backup ) )
2017-12-11 22:10:52 +00:00
2018-09-26 22:18:45 +00:00
// add the default backup storage location to the clientset and the informer/lister store
2019-01-25 03:33:07 +00:00
_ , err := clientset . VeleroV1 ( ) . BackupStorageLocations ( defaultBackupLocation . Namespace ) . Create ( defaultBackupLocation )
2018-09-26 22:18:45 +00:00
require . NoError ( t , err )
2017-12-11 22:10:52 +00:00
2019-01-25 03:33:07 +00:00
require . NoError ( t , sharedInformers . Velero ( ) . V1 ( ) . BackupStorageLocations ( ) . Informer ( ) . GetStore ( ) . Add ( defaultBackupLocation ) )
2017-12-11 22:10:52 +00:00
2018-09-26 22:18:45 +00:00
// add the test's backup storage location to the clientset and the informer/lister store
// if it's different than the default
if test . backupLocation != nil && test . backupLocation != defaultBackupLocation {
2019-01-25 03:33:07 +00:00
_ , err := clientset . VeleroV1 ( ) . BackupStorageLocations ( test . backupLocation . Namespace ) . Create ( test . backupLocation )
2018-09-26 22:18:45 +00:00
require . NoError ( t , err )
2017-12-11 22:10:52 +00:00
2019-01-25 03:33:07 +00:00
require . NoError ( t , sharedInformers . Velero ( ) . V1 ( ) . BackupStorageLocations ( ) . Informer ( ) . GetStore ( ) . Add ( test . backupLocation ) )
2017-08-02 17:27:17 +00:00
}
2018-09-26 22:18:45 +00:00
require . NoError ( t , c . processBackup ( fmt . Sprintf ( "%s/%s" , test . backup . Namespace , test . backup . Name ) ) )
2017-12-11 22:10:52 +00:00
2019-01-25 03:33:07 +00:00
res , err := clientset . VeleroV1 ( ) . Backups ( test . backup . Namespace ) . Get ( test . backup . Name , metav1 . GetOptions { } )
2018-09-26 22:18:45 +00:00
require . NoError ( t , err )
2017-12-11 22:10:52 +00:00
2019-04-23 23:19:00 +00:00
// failed tests for failed backup should have a phase of failed
2018-09-26 22:18:45 +00:00
assert . Equal ( t , test . expectedResult , res )
2017-08-02 17:27:17 +00:00
} )
}
}
2018-09-25 14:51:28 +00:00
2018-09-26 22:18:45 +00:00
func TestValidateAndGetSnapshotLocations ( t * testing . T ) {
2018-09-25 14:51:28 +00:00
tests := [ ] struct {
name string
2019-01-25 03:33:07 +00:00
backup * velerotest . TestBackup
locations [ ] * velerotest . TestVolumeSnapshotLocation
2018-10-26 15:32:46 +00:00
defaultLocations map [ string ] string
2018-09-25 14:51:28 +00:00
expectedVolumeSnapshotLocationNames [ ] string // adding these in the expected order will allow to test with better msgs in case of a test failure
expectedErrors string
expectedSuccess bool
} {
{
2018-10-26 15:32:46 +00:00
name : "location name does not correspond to any existing location" ,
2019-01-25 03:33:07 +00:00
backup : velerotest . NewTestBackup ( ) . WithName ( "backup1" ) . WithPhase ( v1 . BackupPhaseNew ) . WithVolumeSnapshotLocations ( "random-name" ) ,
locations : [ ] * velerotest . TestVolumeSnapshotLocation {
velerotest . NewTestVolumeSnapshotLocation ( ) . WithProvider ( "aws" ) . WithName ( "aws-us-east-1" ) ,
velerotest . NewTestVolumeSnapshotLocation ( ) . WithProvider ( "aws" ) . WithName ( "aws-us-west-1" ) ,
velerotest . NewTestVolumeSnapshotLocation ( ) . WithProvider ( "fake-provider" ) . WithName ( "some-name" ) ,
2018-10-26 15:32:46 +00:00
} ,
2019-01-25 03:33:07 +00:00
expectedErrors : "a VolumeSnapshotLocation CRD for the location random-name with the name specified in the backup spec needs to be created before this snapshot can be executed. Error: volumesnapshotlocation.velero.io \"random-name\" not found" , expectedSuccess : false ,
2018-09-25 14:51:28 +00:00
} ,
{
2018-10-26 15:32:46 +00:00
name : "duplicate locationName per provider: should filter out dups" ,
2019-01-25 03:33:07 +00:00
backup : velerotest . NewTestBackup ( ) . WithName ( "backup1" ) . WithPhase ( v1 . BackupPhaseNew ) . WithVolumeSnapshotLocations ( "aws-us-west-1" , "aws-us-west-1" ) ,
locations : [ ] * velerotest . TestVolumeSnapshotLocation {
velerotest . NewTestVolumeSnapshotLocation ( ) . WithProvider ( "aws" ) . WithName ( "aws-us-east-1" ) ,
velerotest . NewTestVolumeSnapshotLocation ( ) . WithProvider ( "aws" ) . WithName ( "aws-us-west-1" ) ,
2018-10-26 15:32:46 +00:00
} ,
expectedVolumeSnapshotLocationNames : [ ] string { "aws-us-west-1" } ,
2018-09-25 14:51:28 +00:00
expectedSuccess : true ,
} ,
{
2018-10-26 15:32:46 +00:00
name : "multiple non-dupe location names per provider should error" ,
2019-01-25 03:33:07 +00:00
backup : velerotest . NewTestBackup ( ) . WithName ( "backup1" ) . WithVolumeSnapshotLocations ( "aws-us-east-1" , "aws-us-west-1" ) ,
locations : [ ] * velerotest . TestVolumeSnapshotLocation {
velerotest . NewTestVolumeSnapshotLocation ( ) . WithProvider ( "aws" ) . WithName ( "aws-us-east-1" ) ,
velerotest . NewTestVolumeSnapshotLocation ( ) . WithProvider ( "aws" ) . WithName ( "aws-us-west-1" ) ,
velerotest . NewTestVolumeSnapshotLocation ( ) . WithProvider ( "fake-provider" ) . WithName ( "some-name" ) ,
2018-10-26 15:32:46 +00:00
} ,
expectedErrors : "more than one VolumeSnapshotLocation name specified for provider aws: aws-us-west-1; unexpected name was aws-us-east-1" ,
2018-09-25 14:51:28 +00:00
expectedSuccess : false ,
} ,
{
2018-10-26 15:32:46 +00:00
name : "no location name for the provider exists, only one VSL for the provider: use it" ,
2019-01-25 03:33:07 +00:00
backup : velerotest . NewTestBackup ( ) . WithName ( "backup1" ) . WithPhase ( v1 . BackupPhaseNew ) ,
locations : [ ] * velerotest . TestVolumeSnapshotLocation {
velerotest . NewTestVolumeSnapshotLocation ( ) . WithProvider ( "aws" ) . WithName ( "aws-us-east-1" ) ,
2018-10-26 15:32:46 +00:00
} ,
expectedVolumeSnapshotLocationNames : [ ] string { "aws-us-east-1" } ,
expectedSuccess : true ,
} ,
{
name : "no location name for the provider exists, no default, more than one VSL for the provider: error" ,
2019-01-25 03:33:07 +00:00
backup : velerotest . NewTestBackup ( ) . WithName ( "backup1" ) . WithPhase ( v1 . BackupPhaseNew ) ,
locations : [ ] * velerotest . TestVolumeSnapshotLocation {
velerotest . NewTestVolumeSnapshotLocation ( ) . WithProvider ( "aws" ) . WithName ( "aws-us-east-1" ) ,
velerotest . NewTestVolumeSnapshotLocation ( ) . WithProvider ( "aws" ) . WithName ( "aws-us-west-1" ) ,
2018-10-26 15:32:46 +00:00
} ,
expectedErrors : "provider aws has more than one possible volume snapshot location, and none were specified explicitly or as a default" ,
} ,
{
name : "no location name for the provider exists, more than one VSL for the provider: the provider's default should be added" ,
2019-01-25 03:33:07 +00:00
backup : velerotest . NewTestBackup ( ) . WithName ( "backup1" ) . WithPhase ( v1 . BackupPhaseNew ) ,
2018-10-26 15:32:46 +00:00
defaultLocations : map [ string ] string { "aws" : "aws-us-east-1" } ,
2019-01-25 03:33:07 +00:00
locations : [ ] * velerotest . TestVolumeSnapshotLocation {
velerotest . NewTestVolumeSnapshotLocation ( ) . WithName ( "aws-us-east-1" ) . WithProvider ( "aws" ) ,
velerotest . NewTestVolumeSnapshotLocation ( ) . WithName ( "aws-us-west-1" ) . WithProvider ( "aws" ) ,
2018-10-26 15:32:46 +00:00
} ,
expectedVolumeSnapshotLocationNames : [ ] string { "aws-us-east-1" } ,
2018-09-25 14:51:28 +00:00
expectedSuccess : true ,
} ,
{
name : "no existing location name and no default location name given" ,
2019-01-25 03:33:07 +00:00
backup : velerotest . NewTestBackup ( ) . WithName ( "backup1" ) . WithPhase ( v1 . BackupPhaseNew ) ,
2018-09-25 14:51:28 +00:00
expectedSuccess : true ,
} ,
{
2018-10-26 15:32:46 +00:00
name : "multiple location names for a provider, default location name for another provider" ,
2019-01-25 03:33:07 +00:00
backup : velerotest . NewTestBackup ( ) . WithName ( "backup1" ) . WithVolumeSnapshotLocations ( "aws-us-west-1" , "aws-us-west-1" ) ,
2018-10-26 15:32:46 +00:00
defaultLocations : map [ string ] string { "fake-provider" : "some-name" } ,
2019-01-25 03:33:07 +00:00
locations : [ ] * velerotest . TestVolumeSnapshotLocation {
velerotest . NewTestVolumeSnapshotLocation ( ) . WithProvider ( "aws" ) . WithName ( "aws-us-west-1" ) ,
velerotest . NewTestVolumeSnapshotLocation ( ) . WithProvider ( "fake-provider" ) . WithName ( "some-name" ) ,
2018-10-26 15:32:46 +00:00
} ,
expectedVolumeSnapshotLocationNames : [ ] string { "aws-us-west-1" , "some-name" } ,
2018-09-25 14:51:28 +00:00
expectedSuccess : true ,
} ,
}
for _ , test := range tests {
t . Run ( test . name , func ( t * testing . T ) {
var (
client = fake . NewSimpleClientset ( )
sharedInformers = informers . NewSharedInformerFactory ( client , 0 )
)
c := & backupController {
2019-01-25 03:33:07 +00:00
snapshotLocationLister : sharedInformers . Velero ( ) . V1 ( ) . VolumeSnapshotLocations ( ) . Lister ( ) ,
2018-09-26 22:18:45 +00:00
defaultSnapshotLocations : test . defaultLocations ,
2018-09-25 14:51:28 +00:00
}
// set up a Backup object to represent what we expect to be passed to backupper.Backup()
backup := test . backup . DeepCopy ( )
backup . Spec . VolumeSnapshotLocations = test . backup . Spec . VolumeSnapshotLocations
for _ , location := range test . locations {
2019-01-25 03:33:07 +00:00
require . NoError ( t , sharedInformers . Velero ( ) . V1 ( ) . VolumeSnapshotLocations ( ) . Informer ( ) . GetStore ( ) . Add ( location . VolumeSnapshotLocation ) )
2018-09-25 14:51:28 +00:00
}
2018-09-26 22:18:45 +00:00
providerLocations , errs := c . validateAndGetSnapshotLocations ( backup )
2018-09-25 14:51:28 +00:00
if test . expectedSuccess {
for _ , err := range errs {
2018-09-26 22:18:45 +00:00
require . NoError ( t , errors . New ( err ) , "validateAndGetSnapshotLocations unexpected error: %v" , err )
2018-09-25 14:51:28 +00:00
}
2018-09-26 22:18:45 +00:00
var locations [ ] string
for _ , loc := range providerLocations {
locations = append ( locations , loc . Name )
}
sort . Strings ( test . expectedVolumeSnapshotLocationNames )
sort . Strings ( locations )
require . Equal ( t , test . expectedVolumeSnapshotLocationNames , locations )
2018-09-25 14:51:28 +00:00
} else {
if len ( errs ) == 0 {
2018-09-26 22:18:45 +00:00
require . Error ( t , nil , "validateAndGetSnapshotLocations expected error" )
2018-09-25 14:51:28 +00:00
}
require . Contains ( t , errs , test . expectedErrors )
}
} )
}
}