@@ -24,13 +24,17 @@ import (
2424type VerificationFunction func (client.Client , string ) error
2525
2626type BackupRestoreCase struct {
27- Namespace string
28- Name string
29- BackupRestoreType lib.BackupRestoreType
30- PreBackupVerify VerificationFunction
31- PostRestoreVerify VerificationFunction
32- SkipVerifyLogs bool // TODO remove
33- BackupTimeout time.Duration
27+ Namespace string
28+ Name string
29+ BackupRestoreType lib.BackupRestoreType
30+ PreBackupVerify VerificationFunction
31+ PostRestoreVerify VerificationFunction
32+ SkipVerifyLogs bool // TODO remove
33+ BackupTimeout time.Duration
34+ ExcludedResources []string // Resources to exclude from backup spec
35+ RestoreHooks * velero.RestoreHooks // Pre/post restore hooks (optional)
36+ IncludedResources []string // Resources to include in restore (optional)
37+ RestoreExcludedResources []string // Resources to exclude from restore (optional)
3438}
3539
3640type ApplicationBackupRestoreCase struct {
@@ -56,6 +60,18 @@ func todoListReady(preBackupState bool, twoVol bool, database string) Verificati
5660 })
5761}
5862
63+ func parksAppReady (preBackupState bool , twoVol bool , DCReadyCheck bool ) VerificationFunction {
64+ return VerificationFunction (func (ocClient client.Client , namespace string ) error {
65+ log .Printf ("checking parksapp for the NAMESPACE: %s" , namespace )
66+ if DCReadyCheck {
67+ gomega .Eventually (lib .IsDCReady (ocClient , namespace , "restify" ), time .Minute * 10 , time .Second * 10 ).Should (gomega .BeTrue ())
68+ }
69+ gomega .Eventually (lib .AreApplicationPodsRunning (kubernetesClientForSuiteRun , namespace ), time .Minute * 9 , time .Second * 5 ).Should (gomega .BeTrue ())
70+ err := lib .VerifyBackupRestoreData (runTimeClientForSuiteRun , kubernetesClientForSuiteRun , kubeConfig , artifact_dir , namespace , "restify" , "restify" , "restify" , preBackupState , twoVol )
71+ return err
72+ })
73+ }
74+
5975func waitOADPReadiness (backupRestoreType lib.BackupRestoreType ) {
6076 err := dpaCR .CreateOrUpdate (dpaCR .Build (backupRestoreType ))
6177 gomega .Expect (err ).NotTo (gomega .HaveOccurred ())
@@ -170,6 +186,7 @@ func runApplicationBackupAndRestore(brCase ApplicationBackupRestoreCase, updateL
170186 }
171187
172188 // Wait for namespace to be deleted
189+ log .Printf ("Waiting for namespace %s to be deleted" , brCase .Namespace )
173190 gomega .Eventually (lib .IsNamespaceDeleted (kubernetesClientForSuiteRun , brCase .Namespace ), time .Minute * 4 , time .Second * 5 ).Should (gomega .BeTrue ())
174191
175192 updateLastInstallTime ()
@@ -198,7 +215,12 @@ func runBackup(brCase BackupRestoreCase, backupName string) bool {
198215
199216 // create backup
200217 log .Printf ("Creating backup %s for case %s" , backupName , brCase .Name )
201- err = lib .CreateBackupForNamespaces (dpaCR .Client , namespace , backupName , []string {brCase .Namespace }, brCase .BackupRestoreType == lib .KOPIA , brCase .BackupRestoreType == lib .CSIDataMover )
218+ if len (brCase .ExcludedResources ) > 0 {
219+ log .Printf ("Creating backup with excluded resources: %v" , brCase .ExcludedResources )
220+ err = lib .CreateCustomBackupForNamespaces (dpaCR .Client , namespace , backupName , []string {brCase .Namespace }, nil , brCase .ExcludedResources , brCase .BackupRestoreType == lib .KOPIA , brCase .BackupRestoreType == lib .CSIDataMover )
221+ } else {
222+ err = lib .CreateBackupForNamespaces (dpaCR .Client , namespace , backupName , []string {brCase .Namespace }, brCase .BackupRestoreType == lib .KOPIA , brCase .BackupRestoreType == lib .CSIDataMover )
223+ }
202224 gomega .Expect (err ).ToNot (gomega .HaveOccurred ())
203225
204226 // wait for backup to not be running
@@ -226,7 +248,24 @@ func runBackup(brCase BackupRestoreCase, backupName string) bool {
226248
227249func runRestore (brCase BackupRestoreCase , backupName , restoreName string , nsRequiresResticDCWorkaround bool ) {
228250 log .Printf ("Creating restore %s for case %s" , restoreName , brCase .Name )
229- err := lib .CreateRestoreFromBackup (dpaCR .Client , namespace , backupName , restoreName )
251+ var err error
252+
253+ // Use custom restore if hooks or resource filters are specified
254+ if brCase .RestoreHooks != nil || len (brCase .IncludedResources ) > 0 || len (brCase .RestoreExcludedResources ) > 0 {
255+ log .Printf ("Creating custom restore with hooks and/or resource filters" )
256+ if brCase .RestoreHooks != nil {
257+ log .Printf ("Restore hooks configured: %d resource hook(s)" , len (brCase .RestoreHooks .Resources ))
258+ }
259+ if len (brCase .IncludedResources ) > 0 {
260+ log .Printf ("Included resources: %v" , brCase .IncludedResources )
261+ }
262+ if len (brCase .RestoreExcludedResources ) > 0 {
263+ log .Printf ("Excluded resources: %v" , brCase .RestoreExcludedResources )
264+ }
265+ err = lib .CreateCustomRestoreFromBackup (dpaCR .Client , namespace , backupName , restoreName , brCase .IncludedResources , brCase .RestoreExcludedResources , brCase .RestoreHooks )
266+ } else {
267+ err = lib .CreateRestoreFromBackup (dpaCR .Client , namespace , backupName , restoreName )
268+ }
230269 gomega .Expect (err ).ToNot (gomega .HaveOccurred ())
231270 gomega .Eventually (lib .IsRestoreDone (dpaCR .Client , namespace , restoreName ), time .Minute * 60 , time .Second * 10 ).Should (gomega .BeTrue ())
232271 // TODO only log on fail?
@@ -329,22 +368,25 @@ var _ = ginkgo.Describe("Backup and restore tests", ginkgo.Ordered, func() {
329368 // using kopia to collect more info (DaemonSet)
330369 waitOADPReadiness (lib .KOPIA )
331370
332- log .Printf ("Creating real DataProtectionTest before must-gather" )
333- bsls , err := dpaCR .ListBSLs ()
334- gomega .Expect (err ).ToNot (gomega .HaveOccurred ())
335-
336- bslName := bsls .Items [0 ].Name
337- err = lib .CreateUploadTestOnlyDPT (dpaCR .Client , dpaCR .Namespace , bslName )
338- gomega .Expect (err ).ToNot (gomega .HaveOccurred ())
339-
371+ //DPT Test and MustGather should be paired together
340372 log .Printf ("skipMustGather: %v" , skipMustGather )
341373 if ! skipMustGather {
374+ log .Printf ("Creating real DataProtectionTest before must-gather" )
375+ bsls , err := dpaCR .ListBSLs ()
376+ gomega .Expect (err ).ToNot (gomega .HaveOccurred ())
377+
378+ bslName := bsls .Items [0 ].Name
379+ err = lib .CreateUploadTestOnlyDPT (dpaCR .Client , dpaCR .Namespace , bslName )
380+ gomega .Expect (err ).ToNot (gomega .HaveOccurred ())
381+
342382 log .Printf ("Running OADP must-gather" )
343383 err = lib .RunMustGather (artifact_dir , dpaCR .Client )
344384 gomega .Expect (err ).ToNot (gomega .HaveOccurred ())
385+ } else {
386+ log .Printf ("Skipping MustGather and DataProtectionTest" )
345387 }
346388
347- err = dpaCR .Delete ()
389+ err : = dpaCR .Delete ()
348390 gomega .Expect (err ).ToNot (gomega .HaveOccurred ())
349391 })
350392
@@ -455,6 +497,46 @@ var _ = ginkgo.Describe("Backup and restore tests", ginkgo.Ordered, func() {
455497 BackupTimeout : 20 * time .Minute ,
456498 },
457499 }, nil ),
500+ ginkgo .Entry ("Parks application Native-Snapshots" , ginkgo .FlakeAttempts (flakeAttempts ), ginkgo .Label ("aws" , "azure" , "gcp" ), ApplicationBackupRestoreCase {
501+ ApplicationTemplate : "./sample-applications/parks-app/manifest.yaml" ,
502+ BackupRestoreCase : BackupRestoreCase {
503+ Namespace : "parks-app" ,
504+ Name : "mongo-parksapp-native-snapshots-e2e" ,
505+ BackupRestoreType : lib .NativeSnapshots ,
506+ PreBackupVerify : parksAppReady (true , false , true ),
507+ PostRestoreVerify : parksAppReady (false , false , false ),
508+ BackupTimeout : 20 * time .Minute ,
509+ ExcludedResources : []string {"jobs.batch" , "events" , "events.events.k8s.io" , "buildconfigs.build.openshift.io" , "builds.build.openshift.io" },
510+ RestoreHooks : & velero.RestoreHooks {
511+ Resources : []velero.RestoreResourceHookSpec {
512+ {
513+ Name : "wait for app to be ready" ,
514+ IncludedNamespaces : []string {"parks-app" },
515+ LabelSelector : & metav1.LabelSelector {
516+ MatchLabels : map [string ]string {
517+ "app" : "restify" ,
518+ },
519+ },
520+ PostHooks : []velero.RestoreResourceHook {
521+ {
522+ Exec : & velero.ExecRestoreHook {
523+ Container : "restify" ,
524+ Command : []string {
525+ "/bin/sh" ,
526+ "-c" ,
527+ "sleep 10\n curl -f http://restify:8080/status || echo \" App not ready yet\" " ,
528+ },
529+ ExecTimeout : metav1.Duration {Duration : 1 * time .Minute },
530+ WaitTimeout : metav1.Duration {Duration : 5 * time .Minute },
531+ OnError : velero .HookErrorModeFail ,
532+ },
533+ },
534+ },
535+ },
536+ },
537+ },
538+ },
539+ }, nil ),
458540 )
459541})
460542
0 commit comments