The following pull request was submitted through Github.
It can be accessed and reviewed at: https://github.com/lxc/lxd/pull/7122

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) ===
As tarball creation will not create consistent backup when instance is running and files are being modified during backup, we avoid this by creating a read-only snapshot of the main volume.

This is possible because BTRFS allows us to create a snapshot quickly without freezing the main volume.
From 6be11c50f62d110b63fed72b9fbaddae6aa2aa2e Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Thu, 2 Apr 2020 15:51:53 +0100
Subject: [PATCH 1/5] lxd/storage/drivers/driver/zfs/volumes: Comment
 clarification

Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com>
---
 lxd/storage/drivers/driver_zfs_volumes.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lxd/storage/drivers/driver_zfs_volumes.go 
b/lxd/storage/drivers/driver_zfs_volumes.go
index 143c660e20..d121254e0d 100644
--- a/lxd/storage/drivers/driver_zfs_volumes.go
+++ b/lxd/storage/drivers/driver_zfs_volumes.go
@@ -1186,7 +1186,7 @@ func (d *zfs) MigrateVolume(vol Volume, conn 
io.ReadWriteCloser, volSrcArgs *mig
 func (d *zfs) BackupVolume(vol Volume, tarWriter 
*instancewriter.InstanceTarWriter, optimized bool, snapshots bool, op 
*operations.Operation) error {
        // Handle the non-optimized tarballs through the generic packer.
        if !optimized {
-               // For block volumes that are exporting snapshots, we need to 
mount parent volume first so that
+               // For block volumes that are exporting snapshots, we need to 
activate parent volume first so that
                // the snapshot volumes can have their devices accessible.
                if vol.contentType == ContentTypeBlock && snapshots {
                        parent, _, _ := 
shared.InstanceGetParentAndSnapshotName(vol.Name())

From 77d6616b4be115bb8b23349be0014ae6db575e77 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Thu, 2 Apr 2020 17:34:58 +0100
Subject: [PATCH 2/5] lxd/storage/drivers/volume: Adds support for setting
 custom mount path

Can be used when creating snapshots at a custom location that needs to be 
reflected in Volume.MountPath().

Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com>
---
 lxd/storage/drivers/volume.go | 21 +++++++++++++--------
 1 file changed, 13 insertions(+), 8 deletions(-)

diff --git a/lxd/storage/drivers/volume.go b/lxd/storage/drivers/volume.go
index f612b5f2e0..e52f7ad685 100644
--- a/lxd/storage/drivers/volume.go
+++ b/lxd/storage/drivers/volume.go
@@ -61,14 +61,15 @@ var BaseDirectories = map[VolumeType][]string{
 
 // Volume represents a storage volume, and provides functions to mount and 
unmount it.
 type Volume struct {
-       name        string
-       pool        string
-       poolConfig  map[string]string
-       volType     VolumeType
-       contentType ContentType
-       config      map[string]string
-       driver      Driver
-       keepDevice  bool
+       name            string
+       pool            string
+       poolConfig      map[string]string
+       volType         VolumeType
+       contentType     ContentType
+       config          map[string]string
+       driver          Driver
+       keepDevice      bool
+       customMountPath string
 }
 
 // NewVolume instantiates a new Volume struct.
@@ -121,6 +122,10 @@ func (v Volume) IsSnapshot() bool {
 
 // MountPath returns the path where the volume will be mounted.
 func (v Volume) MountPath() string {
+       if v.customMountPath != "" {
+               return v.customMountPath
+       }
+
        return GetVolumeMountPath(v.pool, v.volType, v.name)
 }
 

From 6c48834fb7ebb3a84d4cbfe44e8a969592b0ba33 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Thu, 2 Apr 2020 17:36:37 +0100
Subject: [PATCH 3/5] lxd/storage/drivers/driver/btrfs/volumes: Create
 temporary snapshot in BackupVolume()

Ensures consistent backups when instance files are being modified during backup.

Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com>
---
 lxd/storage/drivers/driver_btrfs_volumes.go | 31 +++++++++++++++++++++
 1 file changed, 31 insertions(+)

diff --git a/lxd/storage/drivers/driver_btrfs_volumes.go 
b/lxd/storage/drivers/driver_btrfs_volumes.go
index 6a592f1af9..656cf44b23 100644
--- a/lxd/storage/drivers/driver_btrfs_volumes.go
+++ b/lxd/storage/drivers/driver_btrfs_volumes.go
@@ -650,6 +650,37 @@ func (d *btrfs) MigrateVolume(vol Volume, conn 
io.ReadWriteCloser, volSrcArgs *m
 func (d *btrfs) BackupVolume(vol Volume, tarWriter 
*instancewriter.InstanceTarWriter, optimized bool, snapshots bool, op 
*operations.Operation) error {
        // Handle the non-optimized tarballs through the generic packer.
        if !optimized {
+               // Because the generic backup method will not take a consistent 
backup if files are being modified
+               // as they are copied to the tarball, as BTRFS allows us to 
take a quick snapshot without impacting
+               // the parent volume we do so here to ensure the backup taken 
is consistent.
+               if vol.contentType == ContentTypeFS {
+                       sourcePath := vol.MountPath()
+                       poolPath := GetPoolMountPath(d.name)
+                       tmpDir, err := ioutil.TempDir(poolPath, "backup.")
+                       if err != nil {
+                               return errors.Wrapf(err, "Failed to create 
temporary directory under %q", poolPath)
+                       }
+                       defer os.RemoveAll(tmpDir)
+
+                       err = os.Chmod(tmpDir, 0100)
+                       if err != nil {
+                               return errors.Wrapf(err, "Failed to chmod %q", 
tmpDir)
+                       }
+
+                       // Override volume's mount path with location of 
snapshot so genericVFSBackupVolume reads
+                       // from there instead of main volume.
+                       vol.customMountPath = filepath.Join(tmpDir, vol.name)
+
+                       // Create the read-only snapshot.
+                       mountPath := vol.MountPath()
+                       err = d.snapshotSubvolume(sourcePath, mountPath, true, 
true)
+                       if err != nil {
+                               return err
+                       }
+                       d.logger.Debug("Created read-only backup snapshot", 
log.Ctx{"sourcePath": sourcePath, "path": mountPath})
+                       defer d.deleteSubvolume(mountPath, true)
+               }
+
                return genericVFSBackupVolume(d, vol, tarWriter, snapshots, op)
        }
 

From a86bed47ad14d379261f1a227cb3393a48176353 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Thu, 2 Apr 2020 17:37:55 +0100
Subject: [PATCH 4/5] lxd/storage/drivers/driver/btrfs/volumes: Renames
 container vars to instance

Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com>
---
 lxd/storage/drivers/driver_btrfs_volumes.go | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/lxd/storage/drivers/driver_btrfs_volumes.go 
b/lxd/storage/drivers/driver_btrfs_volumes.go
index 656cf44b23..1c0f5af81b 100644
--- a/lxd/storage/drivers/driver_btrfs_volumes.go
+++ b/lxd/storage/drivers/driver_btrfs_volumes.go
@@ -763,23 +763,23 @@ func (d *btrfs) BackupVolume(vol Volume, tarWriter 
*instancewriter.InstanceTarWr
                }
        }
 
-       // Make a temporary copy of the container.
+       // Make a temporary copy of the instance.
        sourceVolume := vol.MountPath()
-       containersPath := GetVolumeMountPath(d.name, vol.volType, "")
+       instancesPath := GetVolumeMountPath(d.name, vol.volType, "")
 
-       tmpContainerMntPoint, err := ioutil.TempDir(containersPath, "backup.")
+       tmpInstanceMntPoint, err := ioutil.TempDir(instancesPath, "backup.")
        if err != nil {
-               return errors.Wrapf(err, "Failed to create temporary directory 
under '%s'", containersPath)
+               return errors.Wrapf(err, "Failed to create temporary directory 
under '%s'", instancesPath)
        }
-       defer os.RemoveAll(tmpContainerMntPoint)
+       defer os.RemoveAll(tmpInstanceMntPoint)
 
-       err = os.Chmod(tmpContainerMntPoint, 0100)
+       err = os.Chmod(tmpInstanceMntPoint, 0100)
        if err != nil {
-               return errors.Wrapf(err, "Failed to chmod '%s'", 
tmpContainerMntPoint)
+               return errors.Wrapf(err, "Failed to chmod '%s'", 
tmpInstanceMntPoint)
        }
 
        // Create the read-only snapshot.
-       targetVolume := fmt.Sprintf("%s/.backup", tmpContainerMntPoint)
+       targetVolume := fmt.Sprintf("%s/.backup", tmpInstanceMntPoint)
        err = d.snapshotSubvolume(sourceVolume, targetVolume, true, true)
        if err != nil {
                return err

From b13c5a27a80f19f7b0a45b22423df2efb4790138 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Thu, 2 Apr 2020 17:40:34 +0100
Subject: [PATCH 5/5] lxd/storage/drivers/driver/btrfs/volumes: Consistent
 quoting of error message variables

Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com>
---
 lxd/storage/drivers/driver_btrfs_volumes.go | 20 ++++++++++----------
 1 file changed, 10 insertions(+), 10 deletions(-)

diff --git a/lxd/storage/drivers/driver_btrfs_volumes.go 
b/lxd/storage/drivers/driver_btrfs_volumes.go
index 1c0f5af81b..4841be48e3 100644
--- a/lxd/storage/drivers/driver_btrfs_volumes.go
+++ b/lxd/storage/drivers/driver_btrfs_volumes.go
@@ -197,13 +197,13 @@ func (d *btrfs) CreateVolumeFromBackup(vol Volume, 
snapshots []string, srcData i
        // Create a temporary directory to unpack the backup into.
        unpackDir, err := ioutil.TempDir(GetVolumeMountPath(d.name, 
vol.volType, ""), "backup.")
        if err != nil {
-               return nil, nil, errors.Wrapf(err, "Failed to create temporary 
directory under '%s'", GetVolumeMountPath(d.name, vol.volType, ""))
+               return nil, nil, errors.Wrapf(err, "Failed to create temporary 
directory under %q", GetVolumeMountPath(d.name, vol.volType, ""))
        }
        defer os.RemoveAll(unpackDir)
 
        err = os.Chmod(unpackDir, 0100)
        if err != nil {
-               return nil, nil, errors.Wrapf(err, "Failed to chmod '%s'", 
unpackDir)
+               return nil, nil, errors.Wrapf(err, "Failed to chmod %q", 
unpackDir)
        }
 
        // Extract main volume.
@@ -325,13 +325,13 @@ func (d *btrfs) CreateVolumeFromMigration(vol Volume, 
conn io.ReadWriteCloser, v
        // Create a temporary directory which will act as the parent directory 
of the received ro snapshot.
        tmpVolumesMountPoint, err := ioutil.TempDir(instancesPath, "migration.")
        if err != nil {
-               return errors.Wrapf(err, "Failed to create temporary directory 
under '%s'", instancesPath)
+               return errors.Wrapf(err, "Failed to create temporary directory 
under %q", instancesPath)
        }
        defer os.RemoveAll(tmpVolumesMountPoint)
 
        err = os.Chmod(tmpVolumesMountPoint, 0100)
        if err != nil {
-               return errors.Wrapf(err, "Failed to chmod '%s'", 
tmpVolumesMountPoint)
+               return errors.Wrapf(err, "Failed to chmod %q", 
tmpVolumesMountPoint)
        }
 
        wrapper := migration.ProgressWriter(op, "fs_progress", vol.name)
@@ -507,7 +507,7 @@ func (d *btrfs) SetVolumeQuota(vol Volume, size string, op 
*operations.Operation
                        }
 
                        if id == "" {
-                               return fmt.Errorf("Failed to find subvolume id 
for %s", volPath)
+                               return fmt.Errorf("Failed to find subvolume id 
for %q", volPath)
                        }
 
                        // Create a qgroup.
@@ -607,13 +607,13 @@ func (d *btrfs) MigrateVolume(vol Volume, conn 
io.ReadWriteCloser, volSrcArgs *m
        // Create a temporary directory which will act as the parent directory 
of the read-only snapshot.
        tmpVolumesMountPoint, err := ioutil.TempDir(instancesPath, "migration.")
        if err != nil {
-               return errors.Wrapf(err, "Failed to create temporary directory 
under '%s'", instancesPath)
+               return errors.Wrapf(err, "Failed to create temporary directory 
under %q", instancesPath)
        }
        defer os.RemoveAll(tmpVolumesMountPoint)
 
        err = os.Chmod(tmpVolumesMountPoint, 0100)
        if err != nil {
-               return errors.Wrapf(err, "Failed to chmod '%s'", 
tmpVolumesMountPoint)
+               return errors.Wrapf(err, "Failed to chmod %q", 
tmpVolumesMountPoint)
        }
 
        // Make read-only snapshot of the subvolume as writable subvolumes 
cannot be sent.
@@ -769,13 +769,13 @@ func (d *btrfs) BackupVolume(vol Volume, tarWriter 
*instancewriter.InstanceTarWr
 
        tmpInstanceMntPoint, err := ioutil.TempDir(instancesPath, "backup.")
        if err != nil {
-               return errors.Wrapf(err, "Failed to create temporary directory 
under '%s'", instancesPath)
+               return errors.Wrapf(err, "Failed to create temporary directory 
under %q", instancesPath)
        }
        defer os.RemoveAll(tmpInstanceMntPoint)
 
        err = os.Chmod(tmpInstanceMntPoint, 0100)
        if err != nil {
-               return errors.Wrapf(err, "Failed to chmod '%s'", 
tmpInstanceMntPoint)
+               return errors.Wrapf(err, "Failed to chmod %q", 
tmpInstanceMntPoint)
        }
 
        // Create the read-only snapshot.
@@ -864,7 +864,7 @@ func (d *btrfs) RestoreVolume(vol Volume, snapshotName 
string, op *operations.Op
        backupSubvolume := fmt.Sprintf("%s%s", vol.MountPath(), tmpVolSuffix)
        err := os.Rename(vol.MountPath(), backupSubvolume)
        if err != nil {
-               return errors.Wrapf(err, "Failed to rename '%s' to '%s'", 
vol.MountPath(), backupSubvolume)
+               return errors.Wrapf(err, "Failed to rename %q to %q", 
vol.MountPath(), backupSubvolume)
        }
 
        // Setup revert logic.
_______________________________________________
lxc-devel mailing list
lxc-devel@lists.linuxcontainers.org
http://lists.linuxcontainers.org/listinfo/lxc-devel

Reply via email to