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