The following pull request was submitted through Github. It can be accessed and reviewed at: https://github.com/lxc/lxd/pull/7077
This e-mail was sent by the LXC bot, direct replies will not reach the author unless they happen to be subscribed to this list. === Description (from pull-request) ===
From 949aaf40b2faa5eff6c6c8caeb22787fb2c5af9a Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Tue, 24 Mar 2020 14:39:33 +0000 Subject: [PATCH 1/2] lxd/storage/drivers: Moves functions from generic.go to generic_vfs.go And adds VFS to function names. Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/storage/drivers/generic.go | 423 ----------------------------- lxd/storage/drivers/generic_vfs.go | 407 +++++++++++++++++++++++++++ 2 files changed, 407 insertions(+), 423 deletions(-) delete mode 100644 lxd/storage/drivers/generic.go diff --git a/lxd/storage/drivers/generic.go b/lxd/storage/drivers/generic.go deleted file mode 100644 index ca18a04fc1..0000000000 --- a/lxd/storage/drivers/generic.go +++ /dev/null @@ -1,423 +0,0 @@ -package drivers - -import ( - "fmt" - "io" - "os" - - "github.com/pkg/errors" - - "github.com/lxc/lxd/lxd/migration" - "github.com/lxc/lxd/lxd/operations" - "github.com/lxc/lxd/lxd/revert" - "github.com/lxc/lxd/lxd/rsync" - "github.com/lxc/lxd/shared" - "github.com/lxc/lxd/shared/ioprogress" - log "github.com/lxc/lxd/shared/log15" -) - -// genericCopyVolume copies a volume and its snapshots using a non-optimized method. -// initVolume is run against the main volume (not the snapshots) and is often used for quota initialization. -func genericCopyVolume(d Driver, initVolume func(vol Volume) (func(), error), vol Volume, srcVol Volume, srcSnapshots []Volume, refresh bool, op *operations.Operation) error { - if vol.contentType != srcVol.contentType { - return fmt.Errorf("Content type of source and target must be the same") - } - - bwlimit := d.Config()["rsync.bwlimit"] - - revert := revert.New() - defer revert.Fail() - - // Create the main volume if not refreshing. - if !refresh { - err := d.CreateVolume(vol, nil, op) - if err != nil { - return err - } - - revert.Add(func() { d.DeleteVolume(vol, op) }) - } - - // Ensure the volume is mounted. - err := vol.MountTask(func(mountPath string, op *operations.Operation) error { - // If copying snapshots is indicated, check the source isn't itself a snapshot. - if len(srcSnapshots) > 0 && !srcVol.IsSnapshot() { - for _, srcSnapshot := range srcSnapshots { - _, snapName, _ := shared.InstanceGetParentAndSnapshotName(srcSnapshot.name) - - // Mount the source snapshot. - err := srcSnapshot.MountTask(func(srcMountPath string, op *operations.Operation) error { - // Copy the snapshot. - _, err := rsync.LocalCopy(srcMountPath, mountPath, bwlimit, true) - if err != nil { - return err - } - - if srcSnapshot.IsVMBlock() { - srcDevPath, err := d.GetVolumeDiskPath(srcSnapshot) - if err != nil { - return err - } - - targetDevPath, err := d.GetVolumeDiskPath(vol) - if err != nil { - return err - } - - err = copyDevice(srcDevPath, targetDevPath) - if err != nil { - return err - } - } - - return nil - }, op) - if err != nil { - return err - } - - fullSnapName := GetSnapshotVolumeName(vol.name, snapName) - snapVol := NewVolume(d, d.Name(), vol.volType, vol.contentType, fullSnapName, vol.config, vol.poolConfig) - - // Create the snapshot itself. - err = d.CreateVolumeSnapshot(snapVol, op) - if err != nil { - return err - } - - // Setup the revert. - revert.Add(func() { - d.DeleteVolumeSnapshot(snapVol, op) - }) - } - } - - // Run volume-specific init logic. - if initVolume != nil { - _, err := initVolume(vol) - if err != nil { - return err - } - } - - // Copy source to destination (mounting each volume if needed). - err := srcVol.MountTask(func(srcMountPath string, op *operations.Operation) error { - _, err := rsync.LocalCopy(srcMountPath, mountPath, bwlimit, true) - if err != nil { - return err - } - - if srcVol.IsVMBlock() { - srcDevPath, err := d.GetVolumeDiskPath(srcVol) - if err != nil { - return err - } - - targetDevPath, err := d.GetVolumeDiskPath(vol) - if err != nil { - return err - } - - err = copyDevice(srcDevPath, targetDevPath) - if err != nil { - return err - } - } - - return nil - }, op) - if err != nil { - return err - } - - // Run EnsureMountPath after mounting and copying to ensure the mounted directory has the - // correct permissions set. - err = vol.EnsureMountPath() - if err != nil { - return err - } - - return nil - }, op) - if err != nil { - return err - } - - revert.Success() - return nil -} - -// genericCreateVolumeFromMigration receives a volume and its snapshots over a non-optimized method. -// initVolume is run against the main volume (not the snapshots) and is often used for quota initialization. -func genericCreateVolumeFromMigration(d Driver, initVolume func(vol Volume) (func(), error), vol Volume, conn io.ReadWriteCloser, volTargetArgs migration.VolumeTargetArgs, preFiller *VolumeFiller, op *operations.Operation) error { - // Check migration transport type matches volume type. - if vol.IsVMBlock() { - if volTargetArgs.MigrationType.FSType != migration.MigrationFSType_BLOCK_AND_RSYNC { - return ErrNotSupported - } - } else if volTargetArgs.MigrationType.FSType != migration.MigrationFSType_RSYNC { - return ErrNotSupported - } - - revert := revert.New() - defer revert.Fail() - - // Create the main volume if not refreshing. - if !volTargetArgs.Refresh { - err := d.CreateVolume(vol, preFiller, op) - if err != nil { - return err - } - - revert.Add(func() { d.DeleteVolume(vol, op) }) - } - - recvFSVol := func(volName string, conn io.ReadWriteCloser, path string) error { - var wrapper *ioprogress.ProgressTracker - if volTargetArgs.TrackProgress { - wrapper = migration.ProgressTracker(op, "fs_progress", volName) - } - - d.Logger().Debug("Receiving filesystem volume", log.Ctx{"volName": volName, "path": path}) - return rsync.Recv(path, conn, wrapper, volTargetArgs.MigrationType.Features) - } - - recvBlockVol := func(volName string, conn io.ReadWriteCloser, path string) error { - var wrapper *ioprogress.ProgressTracker - if volTargetArgs.TrackProgress { - wrapper = migration.ProgressTracker(op, "block_progress", volName) - } - - to, err := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0) - if err != nil { - return errors.Wrapf(err, "Error opening file for writing %q", path) - } - defer to.Close() - - // Setup progress tracker. - fromPipe := io.ReadCloser(conn) - if wrapper != nil { - fromPipe = &ioprogress.ProgressReader{ - ReadCloser: fromPipe, - Tracker: wrapper, - } - } - - d.Logger().Debug("Receiving block volume", log.Ctx{"volName": volName, "path": path}) - _, err = io.Copy(to, fromPipe) - if err != nil { - return errors.Wrapf(err, "Error copying from migration connection to %q", path) - } - - return nil - } - - // Ensure the volume is mounted. - err := vol.MountTask(func(mountPath string, op *operations.Operation) error { - var err error - - // Setup paths to the main volume. We will receive each snapshot to these paths and then create - // a snapshot of the main volume for each one. - path := shared.AddSlash(mountPath) - pathBlock := "" - - if vol.IsVMBlock() { - pathBlock, err = d.GetVolumeDiskPath(vol) - if err != nil { - return errors.Wrapf(err, "Error getting VM block volume disk path") - } - } - - // Snapshots are sent first by the sender, so create these first. - for _, snapName := range volTargetArgs.Snapshots { - fullSnapshotName := GetSnapshotVolumeName(vol.name, snapName) - snapVol := NewVolume(d, d.Name(), vol.volType, vol.contentType, fullSnapshotName, vol.config, vol.poolConfig) - - // Receive the filesystem snapshot first (as it is sent first). - err = recvFSVol(snapVol.name, conn, path) - if err != nil { - return err - } - - // Receive the block snapshot next (if needed). - if vol.IsVMBlock() { - err = recvBlockVol(snapVol.name, conn, pathBlock) - if err != nil { - return err - } - } - - // Create the snapshot itself. - err = d.CreateVolumeSnapshot(snapVol, op) - if err != nil { - return err - } - - // Setup the revert. - revert.Add(func() { - d.DeleteVolumeSnapshot(snapVol, op) - }) - } - - // Run volume-specific init logic. - if initVolume != nil { - _, err := initVolume(vol) - if err != nil { - return err - } - } - - // Receive main volume. - err = recvFSVol(vol.name, conn, path) - if err != nil { - return err - } - - // Receive the final main volume sync if needed. - if volTargetArgs.Live { - d.Logger().Debug("Starting main volume final sync", log.Ctx{"volName": vol.name, "path": path}) - err = recvFSVol(vol.name, conn, path) - if err != nil { - return err - } - } - - // Run EnsureMountPath after mounting and syncing to ensure the mounted directory has the - // correct permissions set. - err = vol.EnsureMountPath() - if err != nil { - return err - } - - // Receive the block volume next (if needed). - if vol.IsVMBlock() { - err = recvBlockVol(vol.name, conn, pathBlock) - if err != nil { - return err - } - } - - return nil - }, op) - if err != nil { - return err - } - - revert.Success() - return nil -} - -// genericBackupUnpack unpacks a non-optimized backup tarball through a storage driver. -// Returns a post hook function that should be called once the database entries for the restored backup have been -// created and a revert function that can be used to undo the actions this function performs should something -// subsequently fail. -func genericBackupUnpack(d Driver, vol Volume, snapshots []string, srcData io.ReadSeeker, op *operations.Operation) (func(vol Volume) error, func(), error) { - revert := revert.New() - defer revert.Fail() - - // Find the compression algorithm used for backup source data. - srcData.Seek(0, 0) - tarArgs, _, _, err := shared.DetectCompressionFile(srcData) - if err != nil { - return nil, nil, err - } - - if d.HasVolume(vol) { - return nil, nil, fmt.Errorf("Cannot restore volume, already exists on target") - } - - // Create new empty volume. - err = d.CreateVolume(vol, nil, nil) - if err != nil { - return nil, nil, err - } - revert.Add(func() { d.DeleteVolume(vol, op) }) - - if len(snapshots) > 0 { - // Create new snapshots directory. - err := createParentSnapshotDirIfMissing(d.Name(), vol.volType, vol.name) - if err != nil { - return nil, nil, err - } - } - - for _, snapName := range snapshots { - err = vol.MountTask(func(mountPath string, op *operations.Operation) error { - // Prepare tar arguments. - args := append(tarArgs, []string{ - "-", - "--recursive-unlink", - "--xattrs-include=*", - "--strip-components=3", - "-C", mountPath, fmt.Sprintf("backup/snapshots/%s", snapName), - }...) - - // Extract snapshot. - srcData.Seek(0, 0) - err = shared.RunCommandWithFds(srcData, nil, "tar", args...) - if err != nil { - return err - } - - return nil - }, op) - if err != nil { - return nil, nil, err - } - - snapVol, err := vol.NewSnapshot(snapName) - if err != nil { - return nil, nil, err - } - - err = d.CreateVolumeSnapshot(snapVol, op) - if err != nil { - return nil, nil, err - } - revert.Add(func() { d.DeleteVolumeSnapshot(snapVol, op) }) - } - - // Mount main volume and leave mounted (as is needed during backup.yaml generation during latter parts of - // the backup restoration process). - ourMount, err := d.MountVolume(vol, op) - if err != nil { - return nil, nil, err - } - - // Create a post hook function that will be called at the end of the backup restore process to unmount - // the volume if needed. - postHook := func(vol Volume) error { - if ourMount { - d.UnmountVolume(vol, op) - } - - return nil - } - - // Prepare tar extraction arguments. - args := append(tarArgs, []string{ - "-", - "--recursive-unlink", - "--strip-components=2", - "--xattrs-include=*", - "-C", vol.MountPath(), "backup/container", - }...) - - // Extract instance. - srcData.Seek(0, 0) - err = shared.RunCommandWithFds(srcData, nil, "tar", args...) - if err != nil { - return nil, nil, err - } - - // Run EnsureMountPath after mounting and unpacking to ensure the mounted directory has the - // correct permissions set. - err = vol.EnsureMountPath() - if err != nil { - return nil, nil, err - } - - revertExternal := revert.Clone() // Clone before calling revert.Success() so we can return the Fail func. - revert.Success() - return postHook, revertExternal.Fail, nil -} diff --git a/lxd/storage/drivers/generic_vfs.go b/lxd/storage/drivers/generic_vfs.go index f62686ba19..d52421066b 100644 --- a/lxd/storage/drivers/generic_vfs.go +++ b/lxd/storage/drivers/generic_vfs.go @@ -12,6 +12,7 @@ import ( "github.com/lxc/lxd/lxd/migration" "github.com/lxc/lxd/lxd/operations" + "github.com/lxc/lxd/lxd/revert" "github.com/lxc/lxd/lxd/rsync" "github.com/lxc/lxd/lxd/state" "github.com/lxc/lxd/shared" @@ -257,6 +258,166 @@ func genericVFSMigrateVolume(d Driver, s *state.State, vol Volume, conn io.ReadW }, op) } +// genericVFSCreateVolumeFromMigration receives a volume and its snapshots over a non-optimized method. +// initVolume is run against the main volume (not the snapshots) and is often used for quota initialization. +func genericVFSCreateVolumeFromMigration(d Driver, initVolume func(vol Volume) (func(), error), vol Volume, conn io.ReadWriteCloser, volTargetArgs migration.VolumeTargetArgs, preFiller *VolumeFiller, op *operations.Operation) error { + // Check migration transport type matches volume type. + if vol.IsVMBlock() { + if volTargetArgs.MigrationType.FSType != migration.MigrationFSType_BLOCK_AND_RSYNC { + return ErrNotSupported + } + } else if volTargetArgs.MigrationType.FSType != migration.MigrationFSType_RSYNC { + return ErrNotSupported + } + + revert := revert.New() + defer revert.Fail() + + // Create the main volume if not refreshing. + if !volTargetArgs.Refresh { + err := d.CreateVolume(vol, preFiller, op) + if err != nil { + return err + } + + revert.Add(func() { d.DeleteVolume(vol, op) }) + } + + recvFSVol := func(volName string, conn io.ReadWriteCloser, path string) error { + var wrapper *ioprogress.ProgressTracker + if volTargetArgs.TrackProgress { + wrapper = migration.ProgressTracker(op, "fs_progress", volName) + } + + d.Logger().Debug("Receiving filesystem volume", log.Ctx{"volName": volName, "path": path}) + return rsync.Recv(path, conn, wrapper, volTargetArgs.MigrationType.Features) + } + + recvBlockVol := func(volName string, conn io.ReadWriteCloser, path string) error { + var wrapper *ioprogress.ProgressTracker + if volTargetArgs.TrackProgress { + wrapper = migration.ProgressTracker(op, "block_progress", volName) + } + + to, err := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0) + if err != nil { + return errors.Wrapf(err, "Error opening file for writing %q", path) + } + defer to.Close() + + // Setup progress tracker. + fromPipe := io.ReadCloser(conn) + if wrapper != nil { + fromPipe = &ioprogress.ProgressReader{ + ReadCloser: fromPipe, + Tracker: wrapper, + } + } + + d.Logger().Debug("Receiving block volume", log.Ctx{"volName": volName, "path": path}) + _, err = io.Copy(to, fromPipe) + if err != nil { + return errors.Wrapf(err, "Error copying from migration connection to %q", path) + } + + return nil + } + + // Ensure the volume is mounted. + err := vol.MountTask(func(mountPath string, op *operations.Operation) error { + var err error + + // Setup paths to the main volume. We will receive each snapshot to these paths and then create + // a snapshot of the main volume for each one. + path := shared.AddSlash(mountPath) + pathBlock := "" + + if vol.IsVMBlock() { + pathBlock, err = d.GetVolumeDiskPath(vol) + if err != nil { + return errors.Wrapf(err, "Error getting VM block volume disk path") + } + } + + // Snapshots are sent first by the sender, so create these first. + for _, snapName := range volTargetArgs.Snapshots { + fullSnapshotName := GetSnapshotVolumeName(vol.name, snapName) + snapVol := NewVolume(d, d.Name(), vol.volType, vol.contentType, fullSnapshotName, vol.config, vol.poolConfig) + + // Receive the filesystem snapshot first (as it is sent first). + err = recvFSVol(snapVol.name, conn, path) + if err != nil { + return err + } + + // Receive the block snapshot next (if needed). + if vol.IsVMBlock() { + err = recvBlockVol(snapVol.name, conn, pathBlock) + if err != nil { + return err + } + } + + // Create the snapshot itself. + err = d.CreateVolumeSnapshot(snapVol, op) + if err != nil { + return err + } + + // Setup the revert. + revert.Add(func() { + d.DeleteVolumeSnapshot(snapVol, op) + }) + } + + // Run volume-specific init logic. + if initVolume != nil { + _, err := initVolume(vol) + if err != nil { + return err + } + } + + // Receive main volume. + err = recvFSVol(vol.name, conn, path) + if err != nil { + return err + } + + // Receive the final main volume sync if needed. + if volTargetArgs.Live { + d.Logger().Debug("Starting main volume final sync", log.Ctx{"volName": vol.name, "path": path}) + err = recvFSVol(vol.name, conn, path) + if err != nil { + return err + } + } + + // Run EnsureMountPath after mounting and syncing to ensure the mounted directory has the + // correct permissions set. + err = vol.EnsureMountPath() + if err != nil { + return err + } + + // Receive the block volume next (if needed). + if vol.IsVMBlock() { + err = recvBlockVol(vol.name, conn, pathBlock) + if err != nil { + return err + } + } + + return nil + }, op) + if err != nil { + return err + } + + revert.Success() + return nil +} + // genericVFSHasVolume is a generic HasVolume implementation for VFS-only drivers. func genericVFSHasVolume(vol Volume) bool { if shared.PathExists(vol.MountPath()) { @@ -349,6 +510,121 @@ func genericVFSBackupVolume(d Driver, vol Volume, tarWriter *instancewriter.Inst return nil } +// genericVFSBackupUnpack unpacks a non-optimized backup tarball through a storage driver. +// Returns a post hook function that should be called once the database entries for the restored backup have been +// created and a revert function that can be used to undo the actions this function performs should something +// subsequently fail. +func genericVFSBackupUnpack(d Driver, vol Volume, snapshots []string, srcData io.ReadSeeker, op *operations.Operation) (func(vol Volume) error, func(), error) { + revert := revert.New() + defer revert.Fail() + + // Find the compression algorithm used for backup source data. + srcData.Seek(0, 0) + tarArgs, _, _, err := shared.DetectCompressionFile(srcData) + if err != nil { + return nil, nil, err + } + + if d.HasVolume(vol) { + return nil, nil, fmt.Errorf("Cannot restore volume, already exists on target") + } + + // Create new empty volume. + err = d.CreateVolume(vol, nil, nil) + if err != nil { + return nil, nil, err + } + revert.Add(func() { d.DeleteVolume(vol, op) }) + + if len(snapshots) > 0 { + // Create new snapshots directory. + err := createParentSnapshotDirIfMissing(d.Name(), vol.volType, vol.name) + if err != nil { + return nil, nil, err + } + } + + for _, snapName := range snapshots { + err = vol.MountTask(func(mountPath string, op *operations.Operation) error { + // Prepare tar arguments. + args := append(tarArgs, []string{ + "-", + "--recursive-unlink", + "--xattrs-include=*", + "--strip-components=3", + "-C", mountPath, fmt.Sprintf("backup/snapshots/%s", snapName), + }...) + + // Extract snapshot. + srcData.Seek(0, 0) + err = shared.RunCommandWithFds(srcData, nil, "tar", args...) + if err != nil { + return err + } + + return nil + }, op) + if err != nil { + return nil, nil, err + } + + snapVol, err := vol.NewSnapshot(snapName) + if err != nil { + return nil, nil, err + } + + err = d.CreateVolumeSnapshot(snapVol, op) + if err != nil { + return nil, nil, err + } + revert.Add(func() { d.DeleteVolumeSnapshot(snapVol, op) }) + } + + // Mount main volume and leave mounted (as is needed during backup.yaml generation during latter parts of + // the backup restoration process). + ourMount, err := d.MountVolume(vol, op) + if err != nil { + return nil, nil, err + } + + // Create a post hook function that will be called at the end of the backup restore process to unmount + // the volume if needed. + postHook := func(vol Volume) error { + if ourMount { + d.UnmountVolume(vol, op) + } + + return nil + } + + // Prepare tar extraction arguments. + args := append(tarArgs, []string{ + "-", + "--recursive-unlink", + "--strip-components=2", + "--xattrs-include=*", + "-C", vol.MountPath(), "backup/container", + }...) + + // Extract instance. + srcData.Seek(0, 0) + err = shared.RunCommandWithFds(srcData, nil, "tar", args...) + if err != nil { + return nil, nil, err + } + + // Run EnsureMountPath after mounting and unpacking to ensure the mounted directory has the + // correct permissions set. + err = vol.EnsureMountPath() + if err != nil { + return nil, nil, err + } + + revertExternal := revert.Clone() // Clone before calling revert.Success() so we can return the Fail func. + revert.Success() + return postHook, revertExternal.Fail, nil +} + // genericVFSResizeBlockFile resizes an existing block file to the specified size. Returns true if resize took // place, false if not. Both requested size and existing file size are rounded to nearest block size using // roundVolumeBlockFileSizeBytes() before decision whether to resize is taken. @@ -386,3 +662,134 @@ func genericVFSResizeBlockFile(filePath, size string) (bool, error) { return true, nil } + +// genericVFSCopyVolume copies a volume and its snapshots using a non-optimized method. +// initVolume is run against the main volume (not the snapshots) and is often used for quota initialization. +func genericVFSCopyVolume(d Driver, initVolume func(vol Volume) (func(), error), vol Volume, srcVol Volume, srcSnapshots []Volume, refresh bool, op *operations.Operation) error { + if vol.contentType != srcVol.contentType { + return fmt.Errorf("Content type of source and target must be the same") + } + + bwlimit := d.Config()["rsync.bwlimit"] + + revert := revert.New() + defer revert.Fail() + + // Create the main volume if not refreshing. + if !refresh { + err := d.CreateVolume(vol, nil, op) + if err != nil { + return err + } + + revert.Add(func() { d.DeleteVolume(vol, op) }) + } + + // Ensure the volume is mounted. + err := vol.MountTask(func(mountPath string, op *operations.Operation) error { + // If copying snapshots is indicated, check the source isn't itself a snapshot. + if len(srcSnapshots) > 0 && !srcVol.IsSnapshot() { + for _, srcSnapshot := range srcSnapshots { + _, snapName, _ := shared.InstanceGetParentAndSnapshotName(srcSnapshot.name) + + // Mount the source snapshot. + err := srcSnapshot.MountTask(func(srcMountPath string, op *operations.Operation) error { + // Copy the snapshot. + _, err := rsync.LocalCopy(srcMountPath, mountPath, bwlimit, true) + if err != nil { + return err + } + + if srcSnapshot.IsVMBlock() { + srcDevPath, err := d.GetVolumeDiskPath(srcSnapshot) + if err != nil { + return err + } + + targetDevPath, err := d.GetVolumeDiskPath(vol) + if err != nil { + return err + } + + err = copyDevice(srcDevPath, targetDevPath) + if err != nil { + return err + } + } + + return nil + }, op) + if err != nil { + return err + } + + fullSnapName := GetSnapshotVolumeName(vol.name, snapName) + snapVol := NewVolume(d, d.Name(), vol.volType, vol.contentType, fullSnapName, vol.config, vol.poolConfig) + + // Create the snapshot itself. + err = d.CreateVolumeSnapshot(snapVol, op) + if err != nil { + return err + } + + // Setup the revert. + revert.Add(func() { + d.DeleteVolumeSnapshot(snapVol, op) + }) + } + } + + // Run volume-specific init logic. + if initVolume != nil { + _, err := initVolume(vol) + if err != nil { + return err + } + } + + // Copy source to destination (mounting each volume if needed). + err := srcVol.MountTask(func(srcMountPath string, op *operations.Operation) error { + _, err := rsync.LocalCopy(srcMountPath, mountPath, bwlimit, true) + if err != nil { + return err + } + + if srcVol.IsVMBlock() { + srcDevPath, err := d.GetVolumeDiskPath(srcVol) + if err != nil { + return err + } + + targetDevPath, err := d.GetVolumeDiskPath(vol) + if err != nil { + return err + } + + err = copyDevice(srcDevPath, targetDevPath) + if err != nil { + return err + } + } + + return nil + }, op) + if err != nil { + return err + } + + // Run EnsureMountPath after mounting and copying to ensure the mounted directory has the + // correct permissions set. + err = vol.EnsureMountPath() + if err != nil { + return err + } + + return nil + }, op) + if err != nil { + return err + } + + revert.Success() + return nil +} From 563e6bdaa4310146aa92f3222c5442f41de95e07 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Tue, 24 Mar 2020 14:40:05 +0000 Subject: [PATCH 2/2] lxd/storage/drivers: Generic VFS function usage after move &rename Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/storage/drivers/driver_btrfs_volumes.go | 6 +++--- lxd/storage/drivers/driver_ceph_volumes.go | 6 +++--- lxd/storage/drivers/driver_dir_volumes.go | 8 ++++---- lxd/storage/drivers/driver_lvm_volumes.go | 8 ++++---- lxd/storage/drivers/driver_zfs_volumes.go | 6 +++--- 5 files changed, 17 insertions(+), 17 deletions(-) diff --git a/lxd/storage/drivers/driver_btrfs_volumes.go b/lxd/storage/drivers/driver_btrfs_volumes.go index 34d89d3247..97d6773305 100644 --- a/lxd/storage/drivers/driver_btrfs_volumes.go +++ b/lxd/storage/drivers/driver_btrfs_volumes.go @@ -101,7 +101,7 @@ func (d *btrfs) CreateVolume(vol Volume, filler *VolumeFiller, op *operations.Op func (d *btrfs) CreateVolumeFromBackup(vol Volume, snapshots []string, srcData io.ReadSeeker, optimized bool, op *operations.Operation) (func(vol Volume) error, func(), error) { // Handle the non-optimized tarballs through the generic unpacker. if !optimized { - return genericBackupUnpack(d, vol, snapshots, srcData, op) + return genericVFSBackupUnpack(d, vol, snapshots, srcData, op) } revert := revert.New() @@ -265,7 +265,7 @@ func (d *btrfs) CreateVolumeFromCopy(vol Volume, srcVol Volume, copySnapshots bo func (d *btrfs) CreateVolumeFromMigration(vol Volume, conn io.ReadWriteCloser, volTargetArgs migration.VolumeTargetArgs, preFiller *VolumeFiller, op *operations.Operation) error { // Handle simple rsync and block_and_rsync through generic. if volTargetArgs.MigrationType.FSType == migration.MigrationFSType_RSYNC || volTargetArgs.MigrationType.FSType == migration.MigrationFSType_BLOCK_AND_RSYNC { - return genericCreateVolumeFromMigration(d, nil, vol, conn, volTargetArgs, preFiller, op) + return genericVFSCreateVolumeFromMigration(d, nil, vol, conn, volTargetArgs, preFiller, op) } else if volTargetArgs.MigrationType.FSType != migration.MigrationFSType_BTRFS { return ErrNotSupported } @@ -318,7 +318,7 @@ func (d *btrfs) CreateVolumeFromMigration(vol Volume, conn io.ReadWriteCloser, v // RefreshVolume provides same-pool volume and specific snapshots syncing functionality. func (d *btrfs) RefreshVolume(vol Volume, srcVol Volume, srcSnapshots []Volume, op *operations.Operation) error { - return genericCopyVolume(d, nil, vol, srcVol, srcSnapshots, true, op) + return genericVFSCopyVolume(d, nil, vol, srcVol, srcSnapshots, true, op) } // DeleteVolume deletes a volume of the storage device. If any snapshots of the volume remain then diff --git a/lxd/storage/drivers/driver_ceph_volumes.go b/lxd/storage/drivers/driver_ceph_volumes.go index f416d8d2e9..9cb8cd49a8 100644 --- a/lxd/storage/drivers/driver_ceph_volumes.go +++ b/lxd/storage/drivers/driver_ceph_volumes.go @@ -186,7 +186,7 @@ func (d *ceph) CreateVolume(vol Volume, filler *VolumeFiller, op *operations.Ope // CreateVolumeFromBackup re-creates a volume from its exported state. func (d *ceph) CreateVolumeFromBackup(vol Volume, snapshots []string, srcData io.ReadSeeker, optimizedStorage bool, op *operations.Operation) (func(vol Volume) error, func(), error) { - return genericBackupUnpack(d, vol, snapshots, srcData, op) + return genericVFSBackupUnpack(d, vol, snapshots, srcData, op) } // CreateVolumeFromCopy provides same-pool volume copying functionality. @@ -376,7 +376,7 @@ func (d *ceph) CreateVolumeFromCopy(vol Volume, srcVol Volume, copySnapshots boo func (d *ceph) CreateVolumeFromMigration(vol Volume, conn io.ReadWriteCloser, volTargetArgs migration.VolumeTargetArgs, preFiller *VolumeFiller, op *operations.Operation) error { // Handle simple rsync and block_and_rsync through generic. if volTargetArgs.MigrationType.FSType == migration.MigrationFSType_RSYNC || volTargetArgs.MigrationType.FSType == migration.MigrationFSType_BLOCK_AND_RSYNC { - return genericCreateVolumeFromMigration(d, nil, vol, conn, volTargetArgs, preFiller, op) + return genericVFSCreateVolumeFromMigration(d, nil, vol, conn, volTargetArgs, preFiller, op) } else if volTargetArgs.MigrationType.FSType != migration.MigrationFSType_RBD { return ErrNotSupported } @@ -473,7 +473,7 @@ func (d *ceph) CreateVolumeFromMigration(vol Volume, conn io.ReadWriteCloser, vo // RefreshVolume updates an existing volume to match the state of another. func (d *ceph) RefreshVolume(vol Volume, srcVol Volume, srcSnapshots []Volume, op *operations.Operation) error { - return genericCopyVolume(d, nil, vol, srcVol, srcSnapshots, true, op) + return genericVFSCopyVolume(d, nil, vol, srcVol, srcSnapshots, true, op) } // DeleteVolume deletes a volume of the storage device. If any snapshots of the volume remain then diff --git a/lxd/storage/drivers/driver_dir_volumes.go b/lxd/storage/drivers/driver_dir_volumes.go index bb2ca165ba..d79ce2b155 100644 --- a/lxd/storage/drivers/driver_dir_volumes.go +++ b/lxd/storage/drivers/driver_dir_volumes.go @@ -85,7 +85,7 @@ func (d *dir) CreateVolume(vol Volume, filler *VolumeFiller, op *operations.Oper // CreateVolumeFromBackup restores a backup tarball onto the storage device. func (d *dir) CreateVolumeFromBackup(vol Volume, snapshots []string, srcData io.ReadSeeker, optimizedStorage bool, op *operations.Operation) (func(vol Volume) error, func(), error) { // Run the generic backup unpacker - postHook, revertHook, err := genericBackupUnpack(d.withoutGetVolID(), vol, snapshots, srcData, op) + postHook, revertHook, err := genericVFSBackupUnpack(d.withoutGetVolID(), vol, snapshots, srcData, op) if err != nil { return nil, nil, err } @@ -125,17 +125,17 @@ func (d *dir) CreateVolumeFromCopy(vol Volume, srcVol Volume, copySnapshots bool } // Run the generic copy. - return genericCopyVolume(d, d.setupInitialQuota, vol, srcVol, srcSnapshots, false, op) + return genericVFSCopyVolume(d, d.setupInitialQuota, vol, srcVol, srcSnapshots, false, op) } // CreateVolumeFromMigration creates a volume being sent via a migration. func (d *dir) CreateVolumeFromMigration(vol Volume, conn io.ReadWriteCloser, volTargetArgs migration.VolumeTargetArgs, preFiller *VolumeFiller, op *operations.Operation) error { - return genericCreateVolumeFromMigration(d, d.setupInitialQuota, vol, conn, volTargetArgs, preFiller, op) + return genericVFSCreateVolumeFromMigration(d, d.setupInitialQuota, vol, conn, volTargetArgs, preFiller, op) } // RefreshVolume provides same-pool volume and specific snapshots syncing functionality. func (d *dir) RefreshVolume(vol Volume, srcVol Volume, srcSnapshots []Volume, op *operations.Operation) error { - return genericCopyVolume(d, d.setupInitialQuota, vol, srcVol, srcSnapshots, true, op) + return genericVFSCopyVolume(d, d.setupInitialQuota, vol, srcVol, srcSnapshots, true, op) } // DeleteVolume deletes a volume of the storage device. If any snapshots of the volume remain then diff --git a/lxd/storage/drivers/driver_lvm_volumes.go b/lxd/storage/drivers/driver_lvm_volumes.go index 6527de2364..aa15f5b73c 100644 --- a/lxd/storage/drivers/driver_lvm_volumes.go +++ b/lxd/storage/drivers/driver_lvm_volumes.go @@ -104,7 +104,7 @@ func (d *lvm) CreateVolume(vol Volume, filler *VolumeFiller, op *operations.Oper // CreateVolumeFromBackup restores a backup tarball onto the storage device. func (d *lvm) CreateVolumeFromBackup(vol Volume, snapshots []string, srcData io.ReadSeeker, optimizedStorage bool, op *operations.Operation) (func(vol Volume) error, func(), error) { - return genericBackupUnpack(d, vol, snapshots, srcData, op) + return genericVFSBackupUnpack(d, vol, snapshots, srcData, op) } // CreateVolumeFromCopy provides same-pool volume copying functionality. @@ -138,12 +138,12 @@ func (d *lvm) CreateVolumeFromCopy(vol, srcVol Volume, copySnapshots bool, op *o } // Otherwise run the generic copy. - return genericCopyVolume(d, nil, vol, srcVol, srcSnapshots, false, op) + return genericVFSCopyVolume(d, nil, vol, srcVol, srcSnapshots, false, op) } // CreateVolumeFromMigration creates a volume being sent via a migration. func (d *lvm) CreateVolumeFromMigration(vol Volume, conn io.ReadWriteCloser, volTargetArgs migration.VolumeTargetArgs, preFiller *VolumeFiller, op *operations.Operation) error { - return genericCreateVolumeFromMigration(d, nil, vol, conn, volTargetArgs, preFiller, op) + return genericVFSCreateVolumeFromMigration(d, nil, vol, conn, volTargetArgs, preFiller, op) } // RefreshVolume provides same-pool volume and specific snapshots syncing functionality. @@ -154,7 +154,7 @@ func (d *lvm) RefreshVolume(vol, srcVol Volume, srcSnapshots []Volume, op *opera } // Otherwise run the generic copy. - return genericCopyVolume(d, nil, vol, srcVol, srcSnapshots, true, op) + return genericVFSCopyVolume(d, nil, vol, srcVol, srcSnapshots, true, op) } // DeleteVolume deletes a volume of the storage device. If any snapshots of the volume remain then this function diff --git a/lxd/storage/drivers/driver_zfs_volumes.go b/lxd/storage/drivers/driver_zfs_volumes.go index 7fc9ac2cb3..4e899166c1 100644 --- a/lxd/storage/drivers/driver_zfs_volumes.go +++ b/lxd/storage/drivers/driver_zfs_volumes.go @@ -191,7 +191,7 @@ func (d *zfs) CreateVolume(vol Volume, filler *VolumeFiller, op *operations.Oper func (d *zfs) CreateVolumeFromBackup(vol Volume, snapshots []string, srcData io.ReadSeeker, optimized bool, op *operations.Operation) (func(vol Volume) error, func(), error) { // Handle the non-optimized tarballs through the generic unpacker. if !optimized { - return genericBackupUnpack(d, vol, snapshots, srcData, op) + return genericVFSBackupUnpack(d, vol, snapshots, srcData, op) } revert := revert.New() @@ -502,7 +502,7 @@ func (d *zfs) CreateVolumeFromCopy(vol Volume, srcVol Volume, copySnapshots bool func (d *zfs) CreateVolumeFromMigration(vol Volume, conn io.ReadWriteCloser, volTargetArgs migration.VolumeTargetArgs, preFiller *VolumeFiller, op *operations.Operation) error { // Handle simple rsync and block_and_rsync through generic. if volTargetArgs.MigrationType.FSType == migration.MigrationFSType_RSYNC || volTargetArgs.MigrationType.FSType == migration.MigrationFSType_BLOCK_AND_RSYNC { - return genericCreateVolumeFromMigration(d, nil, vol, conn, volTargetArgs, preFiller, op) + return genericVFSCreateVolumeFromMigration(d, nil, vol, conn, volTargetArgs, preFiller, op) } else if volTargetArgs.MigrationType.FSType != migration.MigrationFSType_ZFS { return ErrNotSupported } @@ -581,7 +581,7 @@ func (d *zfs) CreateVolumeFromMigration(vol Volume, conn io.ReadWriteCloser, vol // RefreshVolume updates an existing volume to match the state of another. func (d *zfs) RefreshVolume(vol Volume, srcVol Volume, srcSnapshots []Volume, op *operations.Operation) error { - return genericCopyVolume(d, nil, vol, srcVol, srcSnapshots, true, op) + return genericVFSCopyVolume(d, nil, vol, srcVol, srcSnapshots, true, op) } // DeleteVolume deletes a volume of the storage device. If any snapshots of the volume remain then
_______________________________________________ lxc-devel mailing list lxc-devel@lists.linuxcontainers.org http://lists.linuxcontainers.org/listinfo/lxc-devel