Skip to content

Commit

Permalink
adding block mode to uploader/provider interfaces
Browse files Browse the repository at this point in the history
Signed-off-by: Shawn Hurley <shawn@hurley.page>
  • Loading branch information
shawn-hurley committed Aug 4, 2023
1 parent b21aef6 commit 4e3f1ed
Show file tree
Hide file tree
Showing 11 changed files with 81 additions and 15 deletions.
6 changes: 5 additions & 1 deletion pkg/datapath/file_system.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,9 +133,13 @@ func (fs *fileSystemBR) StartBackup(source AccessPoint, realSource string, paren
if !fs.initialized {
return errors.New("file system data path is not initialized")
}
volMode := uploader.PersistentVolumeFilesystem
if source.ByBlock != "" {
volMode = uploader.PersistentVolumeBlock
}

go func() {
snapshotID, emptySnapshot, err := fs.uploaderProv.RunBackup(fs.ctx, source.ByPath, realSource, tags, forceFull, parentSnapshot, fs)
snapshotID, emptySnapshot, err := fs.uploaderProv.RunBackup(fs.ctx, source.ByPath, realSource, tags, forceFull, parentSnapshot, volMode, fs)

if err == provider.ErrorCanceled {
fs.callbacks.OnCancelled(context.Background(), fs.namespace, fs.jobName)
Expand Down
3 changes: 2 additions & 1 deletion pkg/datapath/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@ type Callbacks struct {

// AccessPoint represents an access point that has been exposed to a data path instance
type AccessPoint struct {
ByPath string
ByPath string
ByBlock string
}

// AsyncBR is the interface for asynchronous data path methods
Expand Down
7 changes: 6 additions & 1 deletion pkg/uploader/kopia/snapshot.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,10 +88,15 @@ func setupDefaultPolicy() *policy.Tree {

// Backup backup specific sourcePath and update progress
func Backup(ctx context.Context, fsUploader SnapshotUploader, repoWriter repo.RepositoryWriter, sourcePath string, realSource string,
forceFull bool, parentSnapshot string, tags map[string]string, log logrus.FieldLogger) (*uploader.SnapshotInfo, bool, error) {
forceFull bool, parentSnapshot string, volMode uploader.PersistentVolumeMode, tags map[string]string, log logrus.FieldLogger) (*uploader.SnapshotInfo, bool, error) {
if fsUploader == nil {
return nil, false, errors.New("get empty kopia uploader")
}

if volMode == uploader.PersistentVolumeBlock {
return nil, false, errors.New("unable to handle block storage")
}

dir, err := filepath.Abs(sourcePath)
if err != nil {
return nil, false, errors.Wrapf(err, "Invalid source path '%s'", sourcePath)
Expand Down
15 changes: 13 additions & 2 deletions pkg/uploader/kopia/snapshot_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -564,6 +564,7 @@ func TestBackup(t *testing.T) {
isSnapshotSourceError bool
expectedError error
expectedEmpty bool
volMode uploader.PersistentVolumeMode
}
manifest := &snapshot.Manifest{
ID: "test",
Expand All @@ -590,10 +591,20 @@ func TestBackup(t *testing.T) {
tags: nil,
expectedError: errors.New("Unable to read dir"),
},
{
name: "Unable to handle block mode",
sourcePath: "/",
tags: nil,
volMode: uploader.PersistentVolumeBlock,
expectedError: errors.New("unable to handle block storage"),
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
if tc.volMode == "" {
tc.volMode = uploader.PersistentVolumeFilesystem
}
s := injectSnapshotFuncs()
args := []mockArgs{
{methodName: "LoadSnapshot", returns: []interface{}{manifest, nil}},
Expand All @@ -616,9 +627,9 @@ func TestBackup(t *testing.T) {
var snapshotInfo *uploader.SnapshotInfo
var err error
if tc.isEmptyUploader {
snapshotInfo, isSnapshotEmpty, err = Backup(context.Background(), nil, s.repoWriterMock, tc.sourcePath, "", tc.forceFull, tc.parentSnapshot, tc.tags, &logrus.Logger{})
snapshotInfo, isSnapshotEmpty, err = Backup(context.Background(), nil, s.repoWriterMock, tc.sourcePath, "", tc.forceFull, tc.parentSnapshot, tc.volMode, tc.tags, &logrus.Logger{})
} else {
snapshotInfo, isSnapshotEmpty, err = Backup(context.Background(), s.uploderMock, s.repoWriterMock, tc.sourcePath, "", tc.forceFull, tc.parentSnapshot, tc.tags, &logrus.Logger{})
snapshotInfo, isSnapshotEmpty, err = Backup(context.Background(), s.uploderMock, s.repoWriterMock, tc.sourcePath, "", tc.forceFull, tc.parentSnapshot, tc.volMode, tc.tags, &logrus.Logger{})
}
// Check if the returned error matches the expected error
if tc.expectedError != nil {
Expand Down
8 changes: 7 additions & 1 deletion pkg/uploader/provider/kopia.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ func (kp *kopiaProvider) RunBackup(
tags map[string]string,
forceFull bool,
parentSnapshot string,
volMode uploader.PersistentVolumeMode,
updater uploader.ProgressUpdater) (string, bool, error) {
if updater == nil {
return "", false, errors.New("Need to initial backup progress updater first")
Expand All @@ -127,6 +128,11 @@ func (kp *kopiaProvider) RunBackup(
return "", false, errors.New("path is empty")
}

// For now, error on block mode
if volMode == uploader.PersistentVolumeBlock {
return "", false, errors.New("unable to currently support block mode")
}

log := kp.log.WithFields(logrus.Fields{
"path": path,
"realSource": realSource,
Expand All @@ -153,7 +159,7 @@ func (kp *kopiaProvider) RunBackup(
tags[uploader.SnapshotRequesterTag] = kp.requestorType
tags[uploader.SnapshotUploaderTag] = uploader.KopiaType

snapshotInfo, isSnapshotEmpty, err := BackupFunc(ctx, kpUploader, repoWriter, path, realSource, forceFull, parentSnapshot, tags, log)
snapshotInfo, isSnapshotEmpty, err := BackupFunc(ctx, kpUploader, repoWriter, path, realSource, forceFull, parentSnapshot, volMode, tags, log)
if err != nil {
if kpUploader.IsCanceled() {
log.Error("Kopia backup is canceled")
Expand Down
22 changes: 17 additions & 5 deletions pkg/uploader/provider/kopia_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,35 +68,47 @@ func TestRunBackup(t *testing.T) {

testCases := []struct {
name string
hookBackupFunc func(ctx context.Context, fsUploader kopia.SnapshotUploader, repoWriter repo.RepositoryWriter, sourcePath string, realSource string, forceFull bool, parentSnapshot string, tags map[string]string, log logrus.FieldLogger) (*uploader.SnapshotInfo, bool, error)
hookBackupFunc func(ctx context.Context, fsUploader kopia.SnapshotUploader, repoWriter repo.RepositoryWriter, sourcePath string, realSource string, forceFull bool, parentSnapshot string, volMode uploader.PersistentVolumeMode, tags map[string]string, log logrus.FieldLogger) (*uploader.SnapshotInfo, bool, error)
volMode uploader.PersistentVolumeMode
notError bool
}{
{
name: "success to backup",
hookBackupFunc: func(ctx context.Context, fsUploader kopia.SnapshotUploader, repoWriter repo.RepositoryWriter, sourcePath string, realSource string, forceFull bool, parentSnapshot string, tags map[string]string, log logrus.FieldLogger) (*uploader.SnapshotInfo, bool, error) {
hookBackupFunc: func(ctx context.Context, fsUploader kopia.SnapshotUploader, repoWriter repo.RepositoryWriter, sourcePath string, realSource string, forceFull bool, parentSnapshot string, volMode uploader.PersistentVolumeMode, tags map[string]string, log logrus.FieldLogger) (*uploader.SnapshotInfo, bool, error) {
return &uploader.SnapshotInfo{}, false, nil
},
notError: true,
},
{
name: "get error to backup",
hookBackupFunc: func(ctx context.Context, fsUploader kopia.SnapshotUploader, repoWriter repo.RepositoryWriter, sourcePath string, realSource string, forceFull bool, parentSnapshot string, tags map[string]string, log logrus.FieldLogger) (*uploader.SnapshotInfo, bool, error) {
hookBackupFunc: func(ctx context.Context, fsUploader kopia.SnapshotUploader, repoWriter repo.RepositoryWriter, sourcePath string, realSource string, forceFull bool, parentSnapshot string, volMode uploader.PersistentVolumeMode, tags map[string]string, log logrus.FieldLogger) (*uploader.SnapshotInfo, bool, error) {
return &uploader.SnapshotInfo{}, false, errors.New("failed to backup")
},
notError: false,
},
{
name: "got empty snapshot",
hookBackupFunc: func(ctx context.Context, fsUploader kopia.SnapshotUploader, repoWriter repo.RepositoryWriter, sourcePath string, realSource string, forceFull bool, parentSnapshot string, tags map[string]string, log logrus.FieldLogger) (*uploader.SnapshotInfo, bool, error) {
hookBackupFunc: func(ctx context.Context, fsUploader kopia.SnapshotUploader, repoWriter repo.RepositoryWriter, sourcePath string, realSource string, forceFull bool, parentSnapshot string, volMode uploader.PersistentVolumeMode, tags map[string]string, log logrus.FieldLogger) (*uploader.SnapshotInfo, bool, error) {
return nil, true, errors.New("snapshot is empty")
},
notError: false,
},
{
name: "error on vol mode",
hookBackupFunc: func(ctx context.Context, fsUploader kopia.SnapshotUploader, repoWriter repo.RepositoryWriter, sourcePath string, realSource string, forceFull bool, parentSnapshot string, volMode uploader.PersistentVolumeMode, tags map[string]string, log logrus.FieldLogger) (*uploader.SnapshotInfo, bool, error) {
return nil, true, nil
},
volMode: uploader.PersistentVolumeBlock,
notError: false,
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
if tc.volMode == "" {
tc.volMode = uploader.PersistentVolumeFilesystem
}
BackupFunc = tc.hookBackupFunc
_, _, err := kp.RunBackup(context.Background(), "var", "", nil, false, "", &updater)
_, _, err := kp.RunBackup(context.Background(), "var", "", nil, false, "", tc.volMode, &updater)
if tc.notError {
assert.NoError(t, err)
} else {
Expand Down
4 changes: 2 additions & 2 deletions pkg/uploader/provider/mocks/Provider.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions pkg/uploader/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ type Provider interface {
tags map[string]string,
forceFull bool,
parentSnapshot string,
volMode uploader.PersistentVolumeMode,
updater uploader.ProgressUpdater) (string, bool, error)
// RunRestore which will do restore for one specific volume with given snapshot id and return error
// updater is used for updating backup progress which implement by third-party
Expand Down
5 changes: 5 additions & 0 deletions pkg/uploader/provider/restic.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ func (rp *resticProvider) RunBackup(
tags map[string]string,
forceFull bool,
parentSnapshot string,
volMode uploader.PersistentVolumeMode,
updater uploader.ProgressUpdater) (string, bool, error) {
if updater == nil {
return "", false, errors.New("Need to initial backup progress updater first")
Expand All @@ -134,6 +135,10 @@ func (rp *resticProvider) RunBackup(
return "", false, errors.New("real source is not empty, this is not supported by restic uploader")
}

if volMode == uploader.PersistentVolumeBlock {
return "", false, errors.New("unable to currently support block mode")
}

log := rp.log.WithFields(logrus.Fields{
"path": path,
"parentSnapshot": parentSnapshot,
Expand Down
16 changes: 14 additions & 2 deletions pkg/uploader/provider/restic_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ func TestResticRunBackup(t *testing.T) {
nilUpdater bool
parentSnapshot string
rp *resticProvider
volMode uploader.PersistentVolumeMode
hookBackupFunc func(string, string, string, map[string]string) *restic.Command
hookResticBackupFunc func(*restic.Command, logrus.FieldLogger, uploader.ProgressUpdater) (string, string, error)
hookResticGetSnapshotFunc func(string, string, map[string]string) *restic.Command
Expand Down Expand Up @@ -117,6 +118,14 @@ func TestResticRunBackup(t *testing.T) {
return strings.Contains(err.Error(), "failed to get snapshot id")
},
},
{
name: "failed to use block mode",
rp: &resticProvider{log: logrus.New(), extraFlags: []string{"testFlags"}},
volMode: uploader.PersistentVolumeBlock,
errorHandleFunc: func(err error) bool {
return strings.Contains(err.Error(), "unable to currently support block mode")
},
},
}

for _, tc := range testCases {
Expand All @@ -135,11 +144,14 @@ func TestResticRunBackup(t *testing.T) {
if tc.hookResticGetSnapshotIDFunc != nil {
resticGetSnapshotIDFunc = tc.hookResticGetSnapshotIDFunc
}
if tc.volMode == "" {
tc.volMode = uploader.PersistentVolumeFilesystem
}
if !tc.nilUpdater {
updater := FakeBackupProgressUpdater{PodVolumeBackup: &velerov1api.PodVolumeBackup{}, Log: tc.rp.log, Ctx: context.Background(), Cli: fake.NewClientBuilder().WithScheme(scheme.Scheme).Build()}
_, _, err = tc.rp.RunBackup(context.Background(), "var", "", map[string]string{}, false, parentSnapshot, &updater)
_, _, err = tc.rp.RunBackup(context.Background(), "var", "", map[string]string{}, false, parentSnapshot, tc.volMode, &updater)
} else {
_, _, err = tc.rp.RunBackup(context.Background(), "var", "", map[string]string{}, false, parentSnapshot, nil)
_, _, err = tc.rp.RunBackup(context.Background(), "var", "", map[string]string{}, false, parentSnapshot, tc.volMode, nil)
}

tc.rp.log.Infof("test name %v error %v", tc.name, err)
Expand Down
9 changes: 9 additions & 0 deletions pkg/uploader/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,15 @@ const (
SnapshotUploaderTag = "snapshot-uploader"
)

type PersistentVolumeMode string

const (
// PersistentVolumeBlock means the volume will not be formatted with a filesystem and will remain a raw block device.
PersistentVolumeBlock PersistentVolumeMode = "Block"
// PersistentVolumeFilesystem means the volume will be or is formatted with a filesystem.
PersistentVolumeFilesystem PersistentVolumeMode = "Filesystem"
)

// ValidateUploaderType validates if the input param is a valid uploader type.
// It will return an error if it's invalid.
func ValidateUploaderType(t string) error {
Expand Down

0 comments on commit 4e3f1ed

Please sign in to comment.