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

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) ===
For generic VM backups, restore the original volume sizes rather than the target's default volume size.

In order to accommodate this change, whilst avoiding unnecessary scans of the compressed backup file, I have introduced the concept of a `Volume` setting called `allowUnsafeResize` that allows us to indicate to the storage driver that a we can shrink block volumes (as we do this before unpacking the backup volume).
From 259be8515763a0a7a9fdc3dbc4d622a5bb0d9eae Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Thu, 30 Apr 2020 15:16:13 +0100
Subject: [PATCH 01/10] lxd/instances/post: Fix revert in createFromBackup

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

diff --git a/lxd/instances_post.go b/lxd/instances_post.go
index 77fba7b94e..d056df29c2 100644
--- a/lxd/instances_post.go
+++ b/lxd/instances_post.go
@@ -663,7 +663,7 @@ func createFromBackup(d *Daemon, project string, data 
io.Reader, pool string) re
                if err != nil {
                        return errors.Wrap(err, "Create instance from backup")
                }
-               revert.Add(revertHook)
+               runRevert.Add(revertHook)
 
                body, err := json.Marshal(&internalImportPost{
                        Name:  bInfo.Name,

From 40003d5c942a7dac91bfe8b8493d3f2fab2c2cad Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Thu, 30 Apr 2020 15:16:31 +0100
Subject: [PATCH 02/10] lxd/storage/drivers/volume: Adds allowUnsafeResize bool
 to Volume struct

Used to indicate unsafe resizing (shrinking) is wanted by the caller and all 
helpers (such as GPT moving) should be skipped.

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

diff --git a/lxd/storage/drivers/volume.go b/lxd/storage/drivers/volume.go
index a97a311389..ac98e6e324 100644
--- a/lxd/storage/drivers/volume.go
+++ b/lxd/storage/drivers/volume.go
@@ -62,15 +62,16 @@ 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
-       customMountPath string
+       name              string
+       pool              string
+       poolConfig        map[string]string
+       volType           VolumeType
+       contentType       ContentType
+       config            map[string]string
+       driver            Driver
+       keepDevice        bool
+       customMountPath   string
+       allowUnsafeResize bool // Whether to allow potentially destructive 
unchecked resizing of volume.
 }
 
 // NewVolume instantiates a new Volume struct.

From 9e63148f3c7c8466511858894997a56762c96579 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Thu, 30 Apr 2020 15:17:23 +0100
Subject: [PATCH 03/10] lxd/storage/backend/lxd: Adds cannot shrink error
 handling in CreateInstanceFromBackup

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

diff --git a/lxd/storage/backend_lxd.go b/lxd/storage/backend_lxd.go
index 574ff172d7..1ff2fbb41b 100644
--- a/lxd/storage/backend_lxd.go
+++ b/lxd/storage/backend_lxd.go
@@ -587,7 +587,17 @@ func (b *lxdBackend) CreateInstanceFromBackup(srcBackup 
backup.Info, srcData io.
                        logger.Debug("Applying volume quota from root disk 
config", log.Ctx{"size": rootDiskConf["size"]})
                        err = b.driver.SetVolumeQuota(vol, 
rootDiskConf["size"], op)
                        if err != nil {
-                               return err
+                               // The restored volume can end up being larger 
than the root disk config's size
+                               // property due to the block boundary rounding 
some storage drivers use. As such
+                               // if the restored volume is larger than the 
config's size and it cannot be shrunk
+                               // to the equivalent size on the target storage 
driver, don't fail as the backup
+                               // has still been restored successfully.
+                               if errors.Cause(err) == 
drivers.ErrCannotBeShrunk {
+                                       logger.Warn("Could not apply volume 
quota from root disk config as restored volume cannot be shrunk", 
log.Ctx{"size": rootDiskConf["size"]})
+
+                               } else {
+                                       return err
+                               }
                        }
                }
 

From 96456f4d7c8b4226756148a33fd31deba7518d91 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Thu, 30 Apr 2020 15:17:59 +0100
Subject: [PATCH 04/10] lxd/storage/drivers/generic/vfs: Sets block volume size
 to file size of volume in tarball in genericVFSBackupUnpack

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

diff --git a/lxd/storage/drivers/generic_vfs.go 
b/lxd/storage/drivers/generic_vfs.go
index 966cbb374d..57ad06a62a 100644
--- a/lxd/storage/drivers/generic_vfs.go
+++ b/lxd/storage/drivers/generic_vfs.go
@@ -653,6 +653,17 @@ func genericVFSBackupUnpack(d Driver, vol Volume, 
snapshots []string, srcData io
                                        }
                                        defer to.Close()
 
+                                       // Restore original size of volume from 
raw block backup file size.
+                                       d.Logger().Debug("Setting volume size 
from source", log.Ctx{"source": srcFile, "target": targetPath, "size": 
hdr.Size})
+
+                                       // Allow potentially destructive resize 
of volume as we are going to be
+                                       // overwriting it entirely anyway. This 
allows shrinking of block volumes.
+                                       vol.allowUnsafeResize = true
+                                       err = d.SetVolumeQuota(vol, 
fmt.Sprintf("%d", hdr.Size), op)
+                                       if err != nil {
+                                               return err
+                                       }
+
                                        _, err = io.Copy(to, tr)
                                        if err != nil {
                                                return err

From 43b1a64cf91afaed7ea21dcf6141347557c4be26 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Thu, 30 Apr 2020 15:18:57 +0100
Subject: [PATCH 05/10] lxd/storage/drivers/driver/btrfs/volumes: No need to
 move GPT header if no filler used in CreateVolume

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

diff --git a/lxd/storage/drivers/driver_btrfs_volumes.go 
b/lxd/storage/drivers/driver_btrfs_volumes.go
index 0092085c8f..f9748538c0 100644
--- a/lxd/storage/drivers/driver_btrfs_volumes.go
+++ b/lxd/storage/drivers/driver_btrfs_volumes.go
@@ -65,8 +65,8 @@ func (d *btrfs) CreateVolume(vol Volume, filler 
*VolumeFiller, op *operations.Op
                        return err
                }
 
-               // Move the GPT alt header to end of disk if needed.
-               if vol.IsVMBlock() {
+               // Move the GPT alt header to end of disk if needed and if 
filler specified.
+               if vol.IsVMBlock() && filler != nil && filler.Fill != nil {
                        err = d.moveGPTAltHeader(rootBlockPath)
                        if err != nil {
                                return err

From f8e4bf5d93832678bedcfc71bbee3a81eacaa909 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Thu, 30 Apr 2020 15:19:30 +0100
Subject: [PATCH 06/10] lxd/storage/drivers/driver/btrfs/volumes: Skip GPT
 header move in SetVolumeQuota when allowUnsafeResize is enabled

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

diff --git a/lxd/storage/drivers/driver_btrfs_volumes.go 
b/lxd/storage/drivers/driver_btrfs_volumes.go
index f9748538c0..a8ca986e9e 100644
--- a/lxd/storage/drivers/driver_btrfs_volumes.go
+++ b/lxd/storage/drivers/driver_btrfs_volumes.go
@@ -461,8 +461,10 @@ func (d *btrfs) SetVolumeQuota(vol Volume, size string, op 
*operations.Operation
                        return err
                }
 
-               // Move the GPT alt header to end of disk if needed and resize 
has taken place.
-               if vol.IsVMBlock() && resized {
+               // Move the GPT alt header to end of disk if needed and resize 
has taken place (not needed in
+               // unsafe resize mode as it is  expected the caller will do all 
necessary post resize actions
+               // themselves).
+               if vol.IsVMBlock() && resized && !vol.allowUnsafeResize {
                        err = d.moveGPTAltHeader(rootBlockPath)
                        if err != nil {
                                return err

From 58cdf30ccd7c907ba26167b055bd2c7c165d4b33 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Thu, 30 Apr 2020 15:20:25 +0100
Subject: [PATCH 07/10] lxd/storage/drivers/driver/dir/volumes: Skip GPT header
 move in SetVolumeQuota when allowUnsafeResize is enabled

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

diff --git a/lxd/storage/drivers/driver_dir_volumes.go 
b/lxd/storage/drivers/driver_dir_volumes.go
index 7f3fcadb38..58b1d0b157 100644
--- a/lxd/storage/drivers/driver_dir_volumes.go
+++ b/lxd/storage/drivers/driver_dir_volumes.go
@@ -260,8 +260,10 @@ func (d *dir) SetVolumeQuota(vol Volume, size string, op 
*operations.Operation)
                        return err
                }
 
-               // Move the GPT alt header to end of disk if needed and resize 
has taken place.
-               if vol.IsVMBlock() && resized {
+               // Move the GPT alt header to end of disk if needed and resize 
has taken place (not needed in
+               // unsafe resize mode as it is  expected the caller will do all 
necessary post resize actions
+               // themselves).
+               if vol.IsVMBlock() && resized && !vol.allowUnsafeResize {
                        err = d.moveGPTAltHeader(rootBlockPath)
                        if err != nil {
                                return err

From 0d7925abb6fb5cb9dea3281fd7d400c1074be008 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Thu, 30 Apr 2020 15:20:48 +0100
Subject: [PATCH 08/10] lxd/storage/drivers/driver/lvm/volumes: Allow unsafe
 shrinking when allowUnsafeResize is enabled

Also skip GPT header move.

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

diff --git a/lxd/storage/drivers/driver_lvm_volumes.go 
b/lxd/storage/drivers/driver_lvm_volumes.go
index 363a6672ae..62ef87fc49 100644
--- a/lxd/storage/drivers/driver_lvm_volumes.go
+++ b/lxd/storage/drivers/driver_lvm_volumes.go
@@ -381,7 +381,7 @@ func (d *lvm) SetVolumeQuota(vol Volume, size string, op 
*operations.Operation)
                        d.logger.Debug("Logical volume filesystem grown", 
logCtx)
                }
        } else {
-               if newSizeBytes < oldSizeBytes {
+               if newSizeBytes < oldSizeBytes && !vol.allowUnsafeResize {
                        return errors.Wrap(ErrCannotBeShrunk, "You cannot 
shrink block volumes")
                }
 
@@ -391,8 +391,9 @@ func (d *lvm) SetVolumeQuota(vol Volume, size string, op 
*operations.Operation)
 
                }
 
-               // Move the GPT alt header to end of disk if needed.
-               if vol.IsVMBlock() {
+               // Move the VM GPT alt header to end of disk if needed (not 
needed in unsafe resize mode as it is
+               // expected the caller will do all necessary post resize 
actions themselves).
+               if vol.IsVMBlock() && !vol.allowUnsafeResize {
                        err = d.moveGPTAltHeader(volDevPath)
                        if err != nil {
                                return err

From 403f65543e8983160da811cf56eb55ea2c6a74df Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Thu, 30 Apr 2020 15:21:43 +0100
Subject: [PATCH 09/10] lxd/storage/drivers/driver/zfs/volumes: Allow unsafe
 shrinking when allowUnsafeResize is enabled

Also skip GPT header move.

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

diff --git a/lxd/storage/drivers/driver_zfs_volumes.go 
b/lxd/storage/drivers/driver_zfs_volumes.go
index 972c63211e..8ab7c255bf 100644
--- a/lxd/storage/drivers/driver_zfs_volumes.go
+++ b/lxd/storage/drivers/driver_zfs_volumes.go
@@ -914,7 +914,7 @@ func (d *zfs) SetVolumeQuota(vol Volume, size string, op 
*operations.Operation)
                        return nil
                }
 
-               if sizeBytes < oldVolSizeBytes {
+               if sizeBytes < oldVolSizeBytes && !vol.allowUnsafeResize {
                        return errors.Wrap(ErrCannotBeShrunk, "You cannot 
shrink block volumes")
                }
 
@@ -929,8 +929,9 @@ func (d *zfs) SetVolumeQuota(vol Volume, size string, op 
*operations.Operation)
                                return err
                        }
 
-                       // Move the GPT alt header to end of disk if needed.
-                       if vol.IsVMBlock() {
+                       // Move the VM GPT alt header to end of disk if needed 
(not needed in unsafe resize mode as
+                       // it is expected the caller will do all necessary post 
resize actions themselves).
+                       if vol.IsVMBlock() && !vol.allowUnsafeResize {
                                err = d.moveGPTAltHeader(devPath)
                                if err != nil {
                                        return err

From 4601d72857b58e9cc3bd636c750008cb6a2fd58f Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Thu, 30 Apr 2020 15:48:42 +0100
Subject: [PATCH 10/10] lxd/storage/drivers/driver/ceph/volumes: Allow unsafe
 shrinking when allowUnsafeResize is enabled

Also skip GPT header move.

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

diff --git a/lxd/storage/drivers/driver_ceph_volumes.go 
b/lxd/storage/drivers/driver_ceph_volumes.go
index 623a12b182..643b4542e7 100644
--- a/lxd/storage/drivers/driver_ceph_volumes.go
+++ b/lxd/storage/drivers/driver_ceph_volumes.go
@@ -774,50 +774,33 @@ func (d *ceph) SetVolumeQuota(vol Volume, size string, op 
*operations.Operation)
        }
 
        // Resize filesystem if needed.
-       if vol.contentType == ContentTypeFS {
-               if newSizeBytes < oldSizeBytes {
-                       err = shrinkFileSystem(fsType, RBDDevPath, vol, 
newSizeBytes)
-                       if err != nil {
-                               return err
-                       }
+       if newSizeBytes < oldSizeBytes {
+               if vol.contentType == ContentTypeBlock && 
!vol.allowUnsafeResize {
+                       return errors.Wrap(ErrCannotBeShrunk, "You cannot 
shrink block volumes")
+               }
 
-                       _, err = shared.TryRunCommand(
-                               "rbd",
-                               "resize",
-                               "--allow-shrink",
-                               "--id", d.config["ceph.user.name"],
-                               "--cluster", d.config["ceph.cluster_name"],
-                               "--pool", d.config["ceph.osd.pool_name"],
-                               "--size", fmt.Sprintf("%dB", newSizeBytes),
-                               d.getRBDVolumeName(vol, "", false, false))
-                       if err != nil {
-                               return err
-                       }
-               } else {
-                       // Grow the block device.
-                       _, err = shared.TryRunCommand(
-                               "rbd",
-                               "resize",
-                               "--id", d.config["ceph.user.name"],
-                               "--cluster", d.config["ceph.cluster_name"],
-                               "--pool", d.config["ceph.osd.pool_name"],
-                               "--size", fmt.Sprintf("%dB", newSizeBytes),
-                               d.getRBDVolumeName(vol, "", false, false))
+               // Shrink the filesystem.
+               if vol.contentType == ContentTypeFS {
+                       err = shrinkFileSystem(fsType, RBDDevPath, vol, 
newSizeBytes)
                        if err != nil {
                                return err
                        }
+               }
 
-                       // Grow the filesystem.
-                       err = growFileSystem(fsType, RBDDevPath, vol)
-                       if err != nil {
-                               return err
-                       }
+               // Shrink the block device.
+               _, err = shared.TryRunCommand(
+                       "rbd",
+                       "resize",
+                       "--allow-shrink",
+                       "--id", d.config["ceph.user.name"],
+                       "--cluster", d.config["ceph.cluster_name"],
+                       "--pool", d.config["ceph.osd.pool_name"],
+                       "--size", fmt.Sprintf("%dB", newSizeBytes),
+                       d.getRBDVolumeName(vol, "", false, false))
+               if err != nil {
+                       return err
                }
        } else {
-               if newSizeBytes < oldSizeBytes {
-                       return errors.Wrap(ErrCannotBeShrunk, "You cannot 
shrink block volumes")
-               }
-
                // Grow the block device.
                _, err = shared.TryRunCommand(
                        "rbd",
@@ -831,15 +814,24 @@ func (d *ceph) SetVolumeQuota(vol Volume, size string, op 
*operations.Operation)
                        return err
                }
 
-               // Move the GPT alt header to end of disk if needed.
-               if vol.IsVMBlock() {
-                       err = d.moveGPTAltHeader(RBDDevPath)
+               // Grow the filesystem.
+               if vol.contentType == ContentTypeFS {
+                       err = growFileSystem(fsType, RBDDevPath, vol)
                        if err != nil {
                                return err
                        }
                }
        }
 
+       // Move the VM GPT alt header to end of disk if needed (not needed in 
unsafe resize mode as it is
+       // expected the caller will do all necessary post resize actions 
themselves).
+       if vol.IsVMBlock() && !vol.allowUnsafeResize {
+               err = d.moveGPTAltHeader(RBDDevPath)
+               if err != nil {
+                       return err
+               }
+       }
+
        return nil
 }
 
_______________________________________________
lxc-devel mailing list
lxc-devel@lists.linuxcontainers.org
http://lists.linuxcontainers.org/listinfo/lxc-devel

Reply via email to