@@ -433,6 +433,16 @@ func (btc *BackupTargetController) reconcile(name string) (err error) {
433433 }
434434 }()
435435
436+ // clean up invalid backup volumes that are created during split-brain
437+ // https://github.com/longhorn/longhorn/issues/11154
438+ clusterVolumeBVMap , duplicatedBackupVolumeSet , err := btc .getClusterBVsDuplicatedBVs (backupTarget )
439+ if err != nil {
440+ return err
441+ }
442+ if err := btc .cleanupDuplicateBackupVolumeForBackupTarget (backupTarget , duplicatedBackupVolumeSet ); err != nil {
443+ return err
444+ }
445+
436446 if backupTarget .Spec .BackupTargetURL == "" {
437447 stopTimer (backupTarget .Name )
438448
@@ -463,7 +473,7 @@ func (btc *BackupTargetController) reconcile(name string) (err error) {
463473 longhorn .BackupTargetConditionTypeUnavailable , longhorn .ConditionStatusFalse ,
464474 "" , "" )
465475
466- if err = btc .syncBackupVolume (backupTarget , info .backupStoreBackupVolumeNames , syncTime , log ); err != nil {
476+ if err = btc .syncBackupVolume (backupTarget , info .backupStoreBackupVolumeNames , clusterVolumeBVMap , syncTime , log ); err != nil {
467477 return err
468478 }
469479
@@ -546,20 +556,54 @@ func (btc *BackupTargetController) getInfoFromBackupStore(backupTarget *longhorn
546556 return info , nil
547557}
548558
549- func (btc * BackupTargetController ) syncBackupVolume (backupTarget * longhorn.BackupTarget , backupStoreBackupVolumeNames []string , syncTime metav1.Time , log logrus.FieldLogger ) error {
550- backupStoreBackupVolumes := sets .New [string ](backupStoreBackupVolumeNames ... )
559+ func (btc * BackupTargetController ) getClusterBVsDuplicatedBVs (backupTarget * longhorn.BackupTarget ) (map [string ]* longhorn.BackupVolume , sets.Set [string ], error ) {
560+ log := getLoggerForBackupTarget (btc .logger , backupTarget )
561+ backupTargetName := backupTarget .Name
551562
552- // Get a list of all the backup volumes that exist as custom resources in the cluster
553- clusterBackupVolumes , err := btc .ds .ListBackupVolumesWithBackupTargetNameRO (backupTarget . Name )
563+ // Get a list of the backup volumes of the backup target that exist as custom resources in the cluster
564+ backupVolumeList , err := btc .ds .ListBackupVolumesWithBackupTargetNameRO (backupTargetName )
554565 if err != nil {
555- return err
566+ return nil , nil , err
556567 }
557568
558- clusterVolumeBVMap := make (map [string ]* longhorn.BackupVolume , len (clusterBackupVolumes ))
569+ duplicateBackupVolumeSet := sets .New [string ]()
570+ volumeBVMap := make (map [string ]* longhorn.BackupVolume , len (backupVolumeList ))
571+ for _ , bv := range backupVolumeList {
572+ if bv .Spec .BackupTargetName == "" {
573+ log .WithField ("backupVolume" , bv .Name ).Debug ("spec.backupTargetName is empty" )
574+ duplicateBackupVolumeSet .Insert (bv .Name )
575+ continue
576+ }
577+ if bv .Spec .VolumeName == "" {
578+ log .WithField ("backupVolume" , bv .Name ).Debug ("spec.volumeName is empty" )
579+ duplicateBackupVolumeSet .Insert (bv .Name )
580+ continue
581+ }
582+ if bv .Spec .BackupTargetName != backupTargetName {
583+ log .WithField ("backupVolume" , bv .Name ).Debugf ("spec.backupTargetName %v is different from label backup-target" , bv .Spec .BackupTargetName )
584+ duplicateBackupVolumeSet .Insert (bv .Name )
585+ continue
586+ }
587+ if existingBV , exists := volumeBVMap [bv .Spec .VolumeName ]; exists {
588+ if existingBV .CreationTimestamp .Before (& bv .CreationTimestamp ) {
589+ log .WithField ("backupVolume" , bv .Name ).Warnf ("Found duplicated BackupVolume with volume name %s" , bv .Spec .VolumeName )
590+ duplicateBackupVolumeSet .Insert (bv .Name )
591+ continue
592+ }
593+ log .WithField ("backupVolume" , existingBV .Name ).Warnf ("Found duplicated BackupVolume with volume name %s" , existingBV .Spec .VolumeName )
594+ duplicateBackupVolumeSet .Insert (existingBV .Name )
595+ }
596+ volumeBVMap [bv .Spec .VolumeName ] = bv
597+ }
598+
599+ return volumeBVMap , duplicateBackupVolumeSet , nil
600+ }
601+
602+ func (btc * BackupTargetController ) syncBackupVolume (backupTarget * longhorn.BackupTarget , backupStoreBackupVolumeNames []string , clusterVolumeBVMap map [string ]* longhorn.BackupVolume , syncTime metav1.Time , log logrus.FieldLogger ) error {
603+ backupStoreBackupVolumes := sets .New [string ](backupStoreBackupVolumeNames ... )
559604 clusterBackupVolumesSet := sets .New [string ]()
560- for _ , bv := range clusterBackupVolumes {
605+ for _ , bv := range clusterVolumeBVMap {
561606 clusterBackupVolumesSet .Insert (bv .Spec .VolumeName )
562- clusterVolumeBVMap [bv .Spec .VolumeName ] = bv
563607 }
564608
565609 // TODO: add a unit test
@@ -580,12 +624,20 @@ func (btc *BackupTargetController) syncBackupVolume(backupTarget *longhorn.Backu
580624
581625 // Update the BackupVolume CR spec.syncRequestAt to request the
582626 // backup_volume_controller to reconcile the BackupVolume CR
583- for backupVolumeName , backupVolume := range clusterBackupVolumes {
627+ multiError := util .NewMultiError ()
628+ for volumeName , backupVolume := range clusterVolumeBVMap {
629+ if ! backupStoreBackupVolumes .Has (volumeName ) {
630+ continue
631+ }
584632 backupVolume .Spec .SyncRequestedAt = syncTime
585- if _ , err = btc .ds .UpdateBackupVolume (backupVolume ); err != nil && ! apierrors .IsConflict (errors .Cause (err )) {
586- log .WithError (err ).Errorf ("Failed to update backup volume %s spec" , backupVolumeName )
633+ if _ , err := btc .ds .UpdateBackupVolume (backupVolume ); err != nil && ! apierrors .IsConflict (errors .Cause (err )) {
634+ log .WithError (err ).Errorf ("Failed to update backup volume %s" , backupVolume .Name )
635+ multiError .Append (util .NewMultiError (fmt .Sprintf ("%v: %v" , backupVolume .Name , err )))
587636 }
588637 }
638+ if len (multiError ) > 0 {
639+ return fmt .Errorf ("failed to update backup volumes: %v" , multiError .Join ())
640+ }
589641
590642 return nil
591643}
@@ -596,7 +648,7 @@ func (btc *BackupTargetController) pullBackupVolumeFromBackupTarget(backupTarget
596648 log .Infof ("Found %d backup volumes in the backup target that do not exist in the cluster and need to be pulled" , count )
597649 }
598650 for remoteVolumeName := range backupVolumesToPull {
599- backupVolumeName := types .GetBackupVolumeNameFromVolumeName (remoteVolumeName )
651+ backupVolumeName := types .GetBackupVolumeNameFromVolumeName (remoteVolumeName , backupTarget . Name )
600652 backupVolume := & longhorn.BackupVolume {
601653 ObjectMeta : metav1.ObjectMeta {
602654 Name : backupVolumeName ,
@@ -624,6 +676,7 @@ func (btc *BackupTargetController) cleanupBackupVolumeNotExistOnBackupTarget(clu
624676 log .Infof ("Found %d backup volumes in the backup target that do not exist in the cluster and need to be deleted from the cluster" , count )
625677 }
626678
679+ multiError := util .NewMultiError ()
627680 for volumeName := range backupVolumesToDelete {
628681 bv , exists := clusterVolumeBVMap [volumeName ]
629682 if ! exists {
@@ -633,14 +686,50 @@ func (btc *BackupTargetController) cleanupBackupVolumeNotExistOnBackupTarget(clu
633686
634687 backupVolumeName := bv .Name
635688 log .WithField ("backupVolume" , backupVolumeName ).Info ("Deleting BackupVolume not exist in backupstore" )
636- if err = datastore .AddBackupVolumeDeleteCustomResourceOnlyLabel (btc .ds , backupVolumeName ); err != nil {
637- return errors .Wrapf (err , "failed to add label delete-custom-resource-only to Backupvolume %s" , backupVolumeName )
689+ if err := btc .deleteBackupVolumeCROnly (backupVolumeName , log ); err != nil {
690+ if apierrors .IsNotFound (err ) {
691+ continue
692+ }
693+ multiError .Append (util .NewMultiError (fmt .Sprintf ("%v: %v" , backupVolumeName , err )))
638694 }
639- if err = btc .ds .DeleteBackupVolume (backupVolumeName ); err != nil {
640- return errors .Wrapf (err , "failed to delete backup volume %s from cluster" , backupVolumeName )
695+ }
696+
697+ if len (multiError ) > 0 {
698+ return fmt .Errorf ("failed to delete backup volumes from cluster: %v" , multiError .Join ())
699+ }
700+ return nil
701+ }
702+
703+ func (btc * BackupTargetController ) deleteBackupVolumeCROnly (backupVolumeName string , log logrus.FieldLogger ) error {
704+ if err := datastore .AddBackupVolumeDeleteCustomResourceOnlyLabel (btc .ds , backupVolumeName ); err != nil {
705+ return errors .Wrapf (err , "failed to add label delete-custom-resource-only to BackupVolume %s" , backupVolumeName )
706+ }
707+ if err := btc .ds .DeleteBackupVolume (backupVolumeName ); err != nil {
708+ return errors .Wrapf (err , "failed to delete BackupVolume %s" , backupVolumeName )
709+ }
710+ return nil
711+ }
712+
713+ func (btc * BackupTargetController ) cleanupDuplicateBackupVolumeForBackupTarget (backupTarget * longhorn.BackupTarget , duplicateBackupVolumesSet sets.Set [string ]) (err error ) {
714+ log := getLoggerForBackupTarget (btc .logger , backupTarget )
715+ if count := duplicateBackupVolumesSet .Len (); count > 0 {
716+ log .Infof ("Found %d duplicated backup volume CRs for the backup target and need to be deleted from the cluster" , count )
717+ }
718+
719+ multiError := util .NewMultiError ()
720+ for bvName := range duplicateBackupVolumesSet {
721+ log .WithField ("backupVolume" , bvName ).Info ("Deleting BackupVolume that has duplicate volume name in cluster" )
722+ if err := btc .deleteBackupVolumeCROnly (bvName , log ); err != nil {
723+ if apierrors .IsNotFound (err ) {
724+ continue
725+ }
726+ multiError .Append (util .NewMultiError (fmt .Sprintf ("%v: %v" , bvName , err )))
641727 }
642728 }
643729
730+ if len (multiError ) > 0 {
731+ return fmt .Errorf ("failed to delete backup volumes: %v" , multiError .Join ())
732+ }
644733 return nil
645734}
646735
0 commit comments