@@ -5,17 +5,17 @@ import (
5
5
"fmt"
6
6
"time"
7
7
8
+ "github.com/percona/percona-backup-mongodb/pbm"
9
+ pbmLog "github.com/percona/percona-backup-mongodb/pbm/log"
8
10
"github.com/percona/percona-backup-mongodb/pbm/storage"
9
11
"github.com/percona/percona-backup-mongodb/pbm/storage/azure"
10
12
"github.com/percona/percona-backup-mongodb/pbm/storage/s3"
11
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
12
-
13
- "github.com/percona/percona-backup-mongodb/pbm"
14
- "go.mongodb.org/mongo-driver/bson/primitive"
15
-
16
13
"github.com/pkg/errors"
14
+ "go.mongodb.org/mongo-driver/bson"
15
+ "go.mongodb.org/mongo-driver/bson/primitive"
17
16
corev1 "k8s.io/api/core/v1"
18
17
k8serrors "k8s.io/apimachinery/pkg/api/errors"
18
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
19
19
"k8s.io/apimachinery/pkg/runtime"
20
20
"k8s.io/apimachinery/pkg/types"
21
21
"k8s.io/client-go/util/retry"
@@ -317,53 +317,7 @@ func (r *ReconcilePerconaServerMongoDBBackup) checkFinalizers(ctx context.Contex
317
317
for _ , f := range cr .GetFinalizers () {
318
318
switch f {
319
319
case "delete-backup" :
320
- if len (cr .Status .PBMname ) == 0 {
321
- continue
322
- }
323
- metaNotFound := false
324
- if b .pbm != nil {
325
- _ , err := b .pbm .C .GetBackupMeta (cr .Status .PBMname )
326
- if err != nil {
327
- if ! errors .Is (err , pbm .ErrNotFound ) {
328
- return errors .Wrap (err , "get backup meta" )
329
- }
330
- metaNotFound = true
331
- }
332
- }
333
- if b .pbm == nil || metaNotFound {
334
- dummyPBM := new (pbm.PBM ) // We need this only for the DeleteBackupFiles method, which doesn't use method receiver at all
335
- stg , err := r .getPBMStorage (ctx , cr )
336
- if err != nil {
337
- return errors .Wrap (err , "get storage" )
338
- }
339
- if err := dummyPBM .DeleteBackupFiles (getPBMBackupMeta (cr ), stg ); err != nil {
340
- log .Error (err , "failed to run finalizer with dummy pbm" , "finalizer" , f )
341
- finalizers = append (finalizers , f )
342
- }
343
- continue
344
- }
345
-
346
- if cluster == nil {
347
- return errors .Errorf ("PerconaServerMongoDB %s is not found" , cr .Spec .GetClusterName ())
348
- }
349
-
350
- var storage psmdbv1.BackupStorageSpec
351
- switch {
352
- case cr .Status .S3 != nil :
353
- storage .Type = psmdbv1 .BackupStorageS3
354
- storage .S3 = * cr .Status .S3
355
- case cr .Status .Azure != nil :
356
- storage .Type = psmdbv1 .BackupStorageAzure
357
- storage .Azure = * cr .Status .Azure
358
- }
359
-
360
- err := b .pbm .SetConfig (ctx , r .client , cluster , storage )
361
- if err != nil {
362
- return errors .Wrapf (err , "set backup config with storage %s" , cr .Spec .StorageName )
363
- }
364
- e := b .pbm .C .Logger ().NewEvent (string (pbm .CmdDeleteBackup ), "" , "" , primitive.Timestamp {})
365
- err = b .pbm .C .DeleteBackup (cr .Status .PBMname , e )
366
- if err != nil {
320
+ if err := r .deleteBackupFinalizer (ctx , cr , cluster , b ); err != nil {
367
321
log .Error (err , "failed to run finalizer" , "finalizer" , f )
368
322
finalizers = append (finalizers , f )
369
323
}
@@ -377,6 +331,108 @@ func (r *ReconcilePerconaServerMongoDBBackup) checkFinalizers(ctx context.Contex
377
331
return err
378
332
}
379
333
334
+ func (r * ReconcilePerconaServerMongoDBBackup ) deleteBackupFinalizer (ctx context.Context , cr * psmdbv1.PerconaServerMongoDBBackup , cluster * psmdbv1.PerconaServerMongoDB , b * Backup ) error {
335
+ if len (cr .Status .PBMname ) == 0 {
336
+ return nil
337
+ }
338
+
339
+ var meta * pbm.BackupMeta
340
+ var err error
341
+
342
+ if b .pbm != nil {
343
+ meta , err = b .pbm .C .GetBackupMeta (cr .Status .PBMname )
344
+ if err != nil {
345
+ if ! errors .Is (err , pbm .ErrNotFound ) {
346
+ return errors .Wrap (err , "get backup meta" )
347
+ }
348
+ meta = nil
349
+ }
350
+ }
351
+ if b .pbm == nil || meta == nil {
352
+ dummyPBM := new (pbm.PBM ) // We need this only for the DeleteBackupFiles method, which doesn't use method receiver at all
353
+ stg , err := r .getPBMStorage (ctx , cr )
354
+ if err != nil {
355
+ return errors .Wrap (err , "get storage" )
356
+ }
357
+ if err := dummyPBM .DeleteBackupFiles (getPBMBackupMeta (cr ), stg ); err != nil {
358
+ return errors .Wrap (err , "failed to delete backup files with dummy PBM" )
359
+ }
360
+ return nil
361
+ }
362
+
363
+ if cluster == nil {
364
+ return errors .Errorf ("PerconaServerMongoDB %s is not found" , cr .Spec .GetClusterName ())
365
+ }
366
+
367
+ var storage psmdbv1.BackupStorageSpec
368
+ switch {
369
+ case cr .Status .S3 != nil :
370
+ storage .Type = psmdbv1 .BackupStorageS3
371
+ storage .S3 = * cr .Status .S3
372
+ case cr .Status .Azure != nil :
373
+ storage .Type = psmdbv1 .BackupStorageAzure
374
+ storage .Azure = * cr .Status .Azure
375
+ }
376
+
377
+ err = b .pbm .SetConfig (ctx , r .client , cluster , storage )
378
+ if err != nil {
379
+ return errors .Wrapf (err , "set backup config with storage %s" , cr .Spec .StorageName )
380
+ }
381
+ e := b .pbm .C .Logger ().NewEvent (string (pbm .CmdDeleteBackup ), "" , "" , primitive.Timestamp {})
382
+ // We should delete PITR oplog chunks until `LastWriteTS` of the backup,
383
+ // as it's not possible to delete backup if it is a base for the PITR timeline
384
+ err = r .deletePITR (ctx , b , meta .LastWriteTS , e )
385
+ if err != nil {
386
+ return errors .Wrap (err , "failed to delete PITR" )
387
+ }
388
+ err = b .pbm .C .DeleteBackup (cr .Status .PBMname , e )
389
+ if err != nil {
390
+ return errors .Wrap (err , "failed to delete backup" )
391
+ }
392
+ return nil
393
+ }
394
+
395
+ // deletePITR deletes PITR oplog chunks whose StartTS is less or equal to the `until` timestamp. Deletes all chunks if `until` is 0.
396
+ func (r * ReconcilePerconaServerMongoDBBackup ) deletePITR (ctx context.Context , b * Backup , until primitive.Timestamp , e * pbmLog.Event ) error {
397
+ log := logf .FromContext (ctx )
398
+
399
+ stg , err := b .pbm .C .GetStorage (e )
400
+ if err != nil {
401
+ return errors .Wrap (err , "get storage" )
402
+ }
403
+
404
+ chunks , err := b .pbm .C .PITRGetChunksSlice ("" , primitive.Timestamp {}, until )
405
+ if err != nil {
406
+ return errors .Wrap (err , "get pitr chunks" )
407
+ }
408
+ if len (chunks ) == 0 {
409
+ log .Info ("nothing to delete" )
410
+ }
411
+
412
+ for _ , chnk := range chunks {
413
+ err = stg .Delete (chnk .FName )
414
+ if err != nil && err != storage .ErrNotExist {
415
+ return errors .Wrapf (err , "delete pitr chunk '%s' (%v) from storage" , chnk .FName , chnk )
416
+ }
417
+
418
+ _ , err = b .pbm .C .Conn .Database (pbm .DB ).Collection (pbm .PITRChunksCollection ).DeleteOne (
419
+ ctx ,
420
+ bson.D {
421
+ {Key : "rs" , Value : chnk .RS },
422
+ {Key : "start_ts" , Value : chnk .StartTS },
423
+ {Key : "end_ts" , Value : chnk .EndTS },
424
+ },
425
+ )
426
+
427
+ if err != nil {
428
+ return errors .Wrap (err , "delete pitr chunk metadata" )
429
+ }
430
+
431
+ log .Info ("deleted " + chnk .FName )
432
+ }
433
+ return nil
434
+ }
435
+
380
436
func (r * ReconcilePerconaServerMongoDBBackup ) updateStatus (ctx context.Context , cr * psmdbv1.PerconaServerMongoDBBackup ) error {
381
437
err := retry .RetryOnConflict (retry .DefaultRetry , func () error {
382
438
c := & psmdbv1.PerconaServerMongoDBBackup {}
0 commit comments