diff --git a/go.mod b/go.mod index 7e230256..5b4f19f6 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( github.com/RoaringBitmap/roaring v1.2.3 github.com/golang/protobuf v1.5.3 github.com/gorilla/mux v1.8.0 - github.com/longhorn/backupstore v0.0.0-20231227154627-8a80904e9077 + github.com/longhorn/backupstore v0.0.0-20240207023845-915898cee71c github.com/longhorn/longhorn-engine v1.6.0-dev-20231217.0.20231226052201-1c1b8312a30d github.com/longhorn/sparse-tools v0.0.0-20240104131008-60efffb16224 github.com/pkg/errors v0.9.1 diff --git a/go.sum b/go.sum index 40d1ca3d..9b66a364 100644 --- a/go.sum +++ b/go.sum @@ -60,6 +60,8 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/longhorn/backupstore v0.0.0-20231227154627-8a80904e9077 h1:bc7BEw4hELRU4qmg7tIdbq67BI5qr7Ya4a0K4VRzeWk= github.com/longhorn/backupstore v0.0.0-20231227154627-8a80904e9077/go.mod h1:4cbJWtlrD2cGTQxQLtdlPTYopiJiusXH7CpOBrn/s3k= +github.com/longhorn/backupstore v0.0.0-20240207023845-915898cee71c h1:Pr08Ip8fo9lZhKGBTjyyeeXos6AIu/twkiDzhUe0Hx8= +github.com/longhorn/backupstore v0.0.0-20240207023845-915898cee71c/go.mod h1:4cbJWtlrD2cGTQxQLtdlPTYopiJiusXH7CpOBrn/s3k= github.com/longhorn/longhorn-engine v1.6.0-dev-20231217.0.20231226052201-1c1b8312a30d h1:3i+f6P78QYV78nuAV8m/kHNcXRgdVrMoGlUkrbcOEz4= github.com/longhorn/longhorn-engine v1.6.0-dev-20231217.0.20231226052201-1c1b8312a30d/go.mod h1:Jkxyj5RT2fk6L/KuPkWMmB0cRhVDjHa799uIXFt3Bfw= github.com/longhorn/sparse-tools v0.0.0-20230408015858-c849def39d3c h1:EAE/cBOWZUL9CDiI4xbOr1IudQUa2e6u/pdScytEcvo= diff --git a/vendor/github.com/longhorn/backupstore/backupstore.go b/vendor/github.com/longhorn/backupstore/backupstore.go index 174b037c..9e79e8c8 100644 --- a/vendor/github.com/longhorn/backupstore/backupstore.go +++ b/vendor/github.com/longhorn/backupstore/backupstore.go @@ -22,7 +22,7 @@ type Volume struct { BackingImageChecksum string `json:",string"` CompressionMethod string `json:",string"` StorageClassName string `json:",string"` - BackendStoreDriver string `json:",string"` + DataEngine string `json:",string"` } type Snapshot struct { diff --git a/vendor/github.com/longhorn/backupstore/config.go b/vendor/github.com/longhorn/backupstore/config.go index 3694922f..a996ba0d 100644 --- a/vendor/github.com/longhorn/backupstore/config.go +++ b/vendor/github.com/longhorn/backupstore/config.go @@ -6,6 +6,7 @@ import ( "encoding/json" "fmt" "path/filepath" + "runtime" "strings" "time" @@ -139,6 +140,27 @@ func volumeExists(driver BackupStoreDriver, volumeName string) bool { return driver.FileExists(getVolumeFilePath(volumeName)) } +// volumeFolderExists checks if volume folder exists on backupstore +// by listing all the backup volume name based on the folders on the backupstore +// since s3 does not support checking folder exist. +func volumeFolderExists(driver BackupStoreDriver, volumeName string) (bool, error) { + jobQueues := workerpool.New(runtime.NumCPU() * 16) + defer jobQueues.StopWait() + + volumeNames, err := getVolumeNames(jobQueues, driver) + if err != nil { + return false, err + } + + for _, name := range volumeNames { + if volumeName == name { + return true, nil + } + } + + return false, nil +} + func getVolumePath(volumeName string) string { checksum := util.GetChecksum([]byte(volumeName)) volumeLayer1 := checksum[0:VOLUME_SEPARATE_LAYER1] @@ -269,8 +291,8 @@ func loadVolume(driver BackupStoreDriver, volumeName string) (*Volume, error) { log.Infof("Falling back compression method to %v for volume %v", LEGACY_COMPRESSION_METHOD, v.Name) v.CompressionMethod = LEGACY_COMPRESSION_METHOD } - if v.BackendStoreDriver == "" { - v.BackendStoreDriver = string(BackendStoreDriverV1) + if v.DataEngine == "" { + v.DataEngine = string(DataEngineV1) } return v, nil } diff --git a/vendor/github.com/longhorn/backupstore/deltablock.go b/vendor/github.com/longhorn/backupstore/deltablock.go index c9f4d5d6..73851e53 100644 --- a/vendor/github.com/longhorn/backupstore/deltablock.go +++ b/vendor/github.com/longhorn/backupstore/deltablock.go @@ -168,7 +168,7 @@ func CreateDeltaBlockBackup(backupName string, config *DeltaBackupConfig) (isInc } config.Volume.CompressionMethod = volume.CompressionMethod - config.Volume.BackendStoreDriver = volume.BackendStoreDriver + config.Volume.DataEngine = volume.DataEngine if err := deltaOps.OpenSnapshot(snapshot.Name, volume.Name); err != nil { return false, err @@ -553,7 +553,7 @@ func performBackup(bsDriver BackupStoreDriver, config *DeltaBackupConfig, delta volume.BackingImageChecksum = config.Volume.BackingImageChecksum volume.CompressionMethod = config.Volume.CompressionMethod volume.StorageClassName = config.Volume.StorageClassName - volume.BackendStoreDriver = config.Volume.BackendStoreDriver + volume.DataEngine = config.Volume.DataEngine if err := saveVolume(bsDriver, volume); err != nil { return progress.progress, "", err @@ -607,7 +607,7 @@ func mergeSnapshotMap(deltaBackup, lastBackup *Backup) *Backup { } // RestoreDeltaBlockBackup restores a delta block backup for the given configuration -func RestoreDeltaBlockBackup(config *DeltaRestoreConfig) error { +func RestoreDeltaBlockBackup(ctx context.Context, config *DeltaRestoreConfig) error { if config == nil { return fmt.Errorf("invalid empty config for restore") } @@ -686,7 +686,8 @@ func RestoreDeltaBlockBackup(config *DeltaRestoreConfig) error { if err := lock.Lock(); err != nil { return err } - go func() { + + go func(ctx context.Context) { var err error currentProgress := 0 @@ -713,9 +714,6 @@ func RestoreDeltaBlockBackup(config *DeltaRestoreConfig) error { } } - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - blockChan, errChan := populateBlocksForFullRestore(bsDriver, backup) errorChans := []<-chan error{errChan} @@ -731,7 +729,7 @@ func RestoreDeltaBlockBackup(config *DeltaRestoreConfig) error { return } currentProgress = PROGRESS_PERCENTAGE_BACKUP_TOTAL - }() + }(ctx) return nil } @@ -754,7 +752,7 @@ func restoreBlockToFile(bsDriver BackupStoreDriver, volumeName string, volDev *o return err } -func RestoreDeltaBlockBackupIncrementally(config *DeltaRestoreConfig) error { +func RestoreDeltaBlockBackupIncrementally(ctx context.Context, config *DeltaRestoreConfig) error { if config == nil { return fmt.Errorf("invalid empty config for restore") } @@ -866,7 +864,7 @@ func RestoreDeltaBlockBackupIncrementally(config *DeltaRestoreConfig) error { } } - if err := performIncrementalRestore(bsDriver, config, srcVolumeName, volDevName, lastBackup, backup); err != nil { + if err := performIncrementalRestore(ctx, bsDriver, config, srcVolumeName, volDevName, lastBackup, backup); err != nil { deltaOps.UpdateRestoreStatus(volDevName, 0, err) return } @@ -998,11 +996,10 @@ func restoreBlocks(ctx context.Context, bsDriver BackupStoreDriver, deltaOps Del for { select { case <-ctx.Done(): - logrus.Infof("Closing goroutine for restoring blocks for volume %v", volumeName) + err = fmt.Errorf(types.ErrorMsgRestoreCancelled+" since server stop for volume %v", volumeName) return case <-deltaOps.GetStopChan(): - logrus.Infof("Closing goroutine for restoring blocks for %v since received stop signal", volumeName) - err = fmt.Errorf("restoration is cancelled since received stop signal") + err = fmt.Errorf(types.ErrorMsgRestoreCancelled+" since received stop signal for volume %v", volumeName) return case block, open := <-in: if !open { @@ -1020,7 +1017,7 @@ func restoreBlocks(ctx context.Context, bsDriver BackupStoreDriver, deltaOps Del return errChan } -func performIncrementalRestore(bsDriver BackupStoreDriver, config *DeltaRestoreConfig, +func performIncrementalRestore(ctx context.Context, bsDriver BackupStoreDriver, config *DeltaRestoreConfig, srcVolumeName, volDevName string, lastBackup *Backup, backup *Backup) error { var err error concurrentLimit := config.ConcurrentLimit @@ -1029,9 +1026,6 @@ func performIncrementalRestore(bsDriver BackupStoreDriver, config *DeltaRestoreC totalBlockCounts: int64(len(backup.Blocks) + len(lastBackup.Blocks)), } - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - blockChan, errChan := populateBlocksForIncrementalRestore(bsDriver, lastBackup, backup) errorChans := []<-chan error{errChan} @@ -1057,6 +1051,17 @@ func DeleteBackupVolume(volumeName string, destURL string) error { if err != nil { return err } + + backupVolumeFolderExists, err := volumeFolderExists(bsDriver, volumeName) + if err != nil { + return err + } + + // No need to lock and remove volume if it does not exist. + if !backupVolumeFolderExists { + return nil + } + lock, err := New(bsDriver, volumeName, DELETION_LOCK) if err != nil { return err diff --git a/vendor/github.com/longhorn/backupstore/inspect.go b/vendor/github.com/longhorn/backupstore/inspect.go index 4bddac84..590709aa 100644 --- a/vendor/github.com/longhorn/backupstore/inspect.go +++ b/vendor/github.com/longhorn/backupstore/inspect.go @@ -76,7 +76,7 @@ func fillVolumeInfo(volume *Volume) *VolumeInfo { BackingImageName: volume.BackingImageName, BackingImageChecksum: volume.BackingImageChecksum, StorageClassname: volume.StorageClassName, - BackendStoreDriver: volume.BackendStoreDriver, + DataEngine: volume.DataEngine, } } diff --git a/vendor/github.com/longhorn/backupstore/list.go b/vendor/github.com/longhorn/backupstore/list.go index 10ba2928..c61967fc 100644 --- a/vendor/github.com/longhorn/backupstore/list.go +++ b/vendor/github.com/longhorn/backupstore/list.go @@ -28,7 +28,7 @@ type VolumeInfo struct { BackingImageName string BackingImageChecksum string StorageClassname string - BackendStoreDriver string + DataEngine string } type BackupInfo struct { diff --git a/vendor/github.com/longhorn/backupstore/types.go b/vendor/github.com/longhorn/backupstore/types.go index 023f48d2..1751804d 100644 --- a/vendor/github.com/longhorn/backupstore/types.go +++ b/vendor/github.com/longhorn/backupstore/types.go @@ -13,9 +13,9 @@ const ( PROGRESS_PERCENTAGE_BACKUP_TOTAL = 100 ) -type BackendStoreDriver string +type DataEngine string const ( - BackendStoreDriverV1 = BackendStoreDriver("v1") - BackendStoreDriverV2 = BackendStoreDriver("v2") + DataEngineV1 = DataEngine("v1") + DataEngineV2 = DataEngine("v2") ) diff --git a/vendor/github.com/longhorn/backupstore/types/types.go b/vendor/github.com/longhorn/backupstore/types/types.go index 1495a549..bc626cc5 100644 --- a/vendor/github.com/longhorn/backupstore/types/types.go +++ b/vendor/github.com/longhorn/backupstore/types/types.go @@ -3,9 +3,11 @@ package types type ProgressState string const ( + ProgressStateUndefined = ProgressState("") ProgressStateInProgress = ProgressState("in_progress") ProgressStateComplete = ProgressState("complete") ProgressStateError = ProgressState("error") + ProgressStateCanceled = ProgressState("canceled") ) const ( @@ -51,5 +53,15 @@ type JobResult struct { } const ( + // This is used for all the BackingImages since they all share the same block pool. + // For lock mechanism, please refer to: https://github.com/longhorn/longhorn/blob/master/enhancements/20200701-backupstore-file-locks.md#proposal + // Currently the lock file is stored in each BackupVolume folder. + // For BackingImage Lock it is also stored there with the folder name "BACKINGIMAGE" defined here. + // To prevent Longhorn from accidently considering it as another normal BackupVolume, + // we use upppercase here so it will be filtered out when listing. BackupBackingImageLockName = "BACKINGIMAGE" ) + +const ( + ErrorMsgRestoreCancelled = "backup restoration is cancelled" +) diff --git a/vendor/modules.txt b/vendor/modules.txt index 7a384f01..0fbb595e 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -120,7 +120,7 @@ github.com/kr/pretty # github.com/kr/text v0.2.0 ## explicit github.com/kr/text -# github.com/longhorn/backupstore v0.0.0-20231227154627-8a80904e9077 +# github.com/longhorn/backupstore v0.0.0-20240207023845-915898cee71c ## explicit; go 1.21 github.com/longhorn/backupstore github.com/longhorn/backupstore/azblob