The following pull request was submitted through Github. It can be accessed and reviewed at: https://github.com/lxc/lxd/pull/7238
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) === When creating containers on a block backed pool or creating a VM that supports optimized images, a cached image volume is created that contains the unpacked image using the `volume.size` property of the pool (or the default block size). This is used to speed up subsequent image creations by creating a snapshot of the cached image volume. However if the `volume.size` property of a pool is changed *after* the initial cached block volume is created, subsequent instance creates will notice this an attempt to resize the new volume to the correct size. A problem occurs if the new `volume.size` is smaller than the cached image volume size, as some filesystems used by containers don't support shrinking, and no VM volumes allow for shrinking currently. This PR allows the storage pool driver to advise via a custom error that the volume cannot be shrunk, and if the instance is being created from a cached image copy then the cached image copy is deleted and re-created using the current storage pool settings.
From ddcc2a1d5bafb30cf3e9f12e64ac1586d2a11886 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Wed, 22 Apr 2020 11:40:36 +0100 Subject: [PATCH 1/5] lxd/storage/backend/lxd: Updates CreateInstanceFromImage to use reverter Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/storage/backend_lxd.go | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/lxd/storage/backend_lxd.go b/lxd/storage/backend_lxd.go index 9308304b26..497e3203c1 100644 --- a/lxd/storage/backend_lxd.go +++ b/lxd/storage/backend_lxd.go @@ -940,14 +940,6 @@ func (b *lxdBackend) CreateInstanceFromImage(inst instance.Instance, fingerprint contentType := InstanceContentType(inst) - revert := true - defer func() { - if !revert { - return - } - b.DeleteInstance(inst, op) - }() - // Get the root disk device config. rootDiskConf, err := b.instanceRootVolumeConfig(inst) if err != nil { @@ -959,6 +951,10 @@ func (b *lxdBackend) CreateInstanceFromImage(inst instance.Instance, fingerprint vol := b.newVolume(volType, contentType, volStorageName, rootDiskConf) + revert := revert.New() + defer revert.Fail() + revert.Add(func() { b.DeleteInstance(inst, op) }) + // If the driver doesn't support optimized image volumes then create a new empty volume and // populate it with the contents of the image archive. if !b.driver.Info().OptimizedImages { @@ -998,7 +994,7 @@ func (b *lxdBackend) CreateInstanceFromImage(inst instance.Instance, fingerprint return err } - revert = false + revert.Success() return nil } From a641fd66daee754f5df2729acf3bf8d4bce0fd26 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Wed, 22 Apr 2020 11:54:12 +0100 Subject: [PATCH 2/5] lxd/storage/drivers/errors: Adds ErrCannotBeShrunk error Used to indicate to the backend that the volume cannot be shrunk. Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/storage/drivers/errors.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lxd/storage/drivers/errors.go b/lxd/storage/drivers/errors.go index cae5eba16a..838452192e 100644 --- a/lxd/storage/drivers/errors.go +++ b/lxd/storage/drivers/errors.go @@ -13,6 +13,9 @@ var ErrUnknownDriver = fmt.Errorf("Unknown driver") // ErrNotSupported is the "Not supported" error var ErrNotSupported = fmt.Errorf("Not supported") +// ErrCannotBeShrunk is the "Cannot be shrunk" error +var ErrCannotBeShrunk = fmt.Errorf("Cannot be shrunk") + // ErrDeleteSnapshots is a special error used to tell the backend to delete more recent snapshots type ErrDeleteSnapshots struct { Snapshots []string From 72cb844fa4f9ce78e0c248ab7f6a2af65d00e9b0 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Wed, 22 Apr 2020 11:54:47 +0100 Subject: [PATCH 3/5] lxd/storage/drivers/utils: Updates to shrinkFileSystem ErrCannotBeShrunk error Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/storage/drivers/utils.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lxd/storage/drivers/utils.go b/lxd/storage/drivers/utils.go index edfa9c2130..9f1e55c275 100644 --- a/lxd/storage/drivers/utils.go +++ b/lxd/storage/drivers/utils.go @@ -462,7 +462,7 @@ func shrinkFileSystem(fsType string, devPath string, vol Volume, byteSize int64) case "": // if not specified, default to ext4. fallthrough case "xfs": - return fmt.Errorf(`Shrinking not supported for filesystem type "%s". A dump, mkfs, and restore are required`, fsType) + return errors.Wrapf(ErrCannotBeShrunk, `Shrinking not supported for filesystem type "%s". A dump, mkfs, and restore are required`, fsType) case "ext4": return vol.UnmountTask(func(op *operations.Operation) error { output, err := shared.RunCommand("e2fsck", "-f", "-y", devPath) @@ -488,7 +488,7 @@ func shrinkFileSystem(fsType string, devPath string, vol Volume, byteSize int64) return nil }, nil) default: - return fmt.Errorf(`Shrinking not supported for filesystem type "%s"`, fsType) + return errors.Wrapf(ErrCannotBeShrunk, `Shrinking not supported for filesystem type "%s"`, fsType) } } From 3a56e7534eb43c7b3aeabedf226895c4fc8ea51d Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Wed, 22 Apr 2020 11:55:18 +0100 Subject: [PATCH 4/5] lxd/storage/backend/lxd: Updates CreateInstanceFromImage to detect ErrCannotBeShrunk When creating a volume from cached image volume, if the driver returns ErrCannotBeShrunk regenerate the cached image volume so that it takes the pool's current settings (including volume.size) to allow the potential for the create to succeed a 2nd time. Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/storage/backend_lxd.go | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/lxd/storage/backend_lxd.go b/lxd/storage/backend_lxd.go index 497e3203c1..8718bb7733 100644 --- a/lxd/storage/backend_lxd.go +++ b/lxd/storage/backend_lxd.go @@ -971,7 +971,7 @@ func (b *lxdBackend) CreateInstanceFromImage(inst instance.Instance, fingerprint // If the driver does support optimized images then ensure the optimized image // volume has been created for the archive's fingerprint and then proceed to create // a new volume by copying the optimized image volume. - err := b.EnsureImage(fingerprint, op) + err = b.EnsureImage(fingerprint, op) if err != nil { return err } @@ -979,8 +979,30 @@ func (b *lxdBackend) CreateInstanceFromImage(inst instance.Instance, fingerprint // No config for an image volume so set to nil. imgVol := b.newVolume(drivers.VolumeTypeImage, contentType, fingerprint, nil) err = b.driver.CreateVolumeFromCopy(vol, imgVol, false, op) - if err != nil { + + // If the driver returns ErrCannotBeShrunk, this means that the cached volume is larger than the + // requested new volume size and the cached image volume, once snapshotted, cannot be shrunk. + // We then need to delete the cached image volume and re-create, as this should solve the issue + // by creating a new cached image volume using the pool's current settings (including volume.size). + if errors.Cause(err) == drivers.ErrCannotBeShrunk { + logger.Debug("Cached image volume is larger than new volume and cannot be shrunk, regenerating image volume") + err = b.DeleteImage(fingerprint, op) + if err != nil { + return err + } + + err = b.EnsureImage(fingerprint, op) + if err != nil { + return err + } + + err = b.driver.CreateVolumeFromCopy(vol, imgVol, false, op) + if err != nil { + return err + } + } else if err != nil { return err + } } From bf686baf3ff07bc23d2f345a2005851863d13635 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Wed, 22 Apr 2020 12:14:18 +0100 Subject: [PATCH 5/5] lxd/storage/drivers: Returns ErrCannotBeShrunk when block volume cannot be shrunk Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/storage/drivers/driver_ceph_volumes.go | 2 +- lxd/storage/drivers/driver_lvm_volumes.go | 2 +- lxd/storage/drivers/driver_zfs_volumes.go | 2 +- lxd/storage/drivers/generic_vfs.go | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lxd/storage/drivers/driver_ceph_volumes.go b/lxd/storage/drivers/driver_ceph_volumes.go index 9c799793bf..7af0b8a4ff 100644 --- a/lxd/storage/drivers/driver_ceph_volumes.go +++ b/lxd/storage/drivers/driver_ceph_volumes.go @@ -815,7 +815,7 @@ func (d *ceph) SetVolumeQuota(vol Volume, size string, op *operations.Operation) } } else { if newSizeBytes < oldSizeBytes { - return fmt.Errorf("You cannot shrink block volumes") + return errors.Wrap(ErrCannotBeShrunk, "You cannot shrink block volumes") } // Grow the block device. diff --git a/lxd/storage/drivers/driver_lvm_volumes.go b/lxd/storage/drivers/driver_lvm_volumes.go index 0c2257fa72..363a6672ae 100644 --- a/lxd/storage/drivers/driver_lvm_volumes.go +++ b/lxd/storage/drivers/driver_lvm_volumes.go @@ -382,7 +382,7 @@ func (d *lvm) SetVolumeQuota(vol Volume, size string, op *operations.Operation) } } else { if newSizeBytes < oldSizeBytes { - return fmt.Errorf("You cannot shrink block volumes") + return errors.Wrap(ErrCannotBeShrunk, "You cannot shrink block volumes") } err = d.resizeLogicalVolume(volDevPath, newSizeBytes) diff --git a/lxd/storage/drivers/driver_zfs_volumes.go b/lxd/storage/drivers/driver_zfs_volumes.go index c2b7ed1996..d5e48e96b2 100644 --- a/lxd/storage/drivers/driver_zfs_volumes.go +++ b/lxd/storage/drivers/driver_zfs_volumes.go @@ -853,7 +853,7 @@ func (d *zfs) SetVolumeQuota(vol Volume, size string, op *operations.Operation) } if sizeBytes < oldVolSizeBytes { - return fmt.Errorf("You cannot shrink block volumes") + return errors.Wrap(ErrCannotBeShrunk, "You cannot shrink block volumes") } err = d.setDatasetProperties(d.dataset(vol, false), fmt.Sprintf("volsize=%d", sizeBytes)) diff --git a/lxd/storage/drivers/generic_vfs.go b/lxd/storage/drivers/generic_vfs.go index 88d81e8720..75f344c484 100644 --- a/lxd/storage/drivers/generic_vfs.go +++ b/lxd/storage/drivers/generic_vfs.go @@ -781,7 +781,7 @@ func genericVFSResizeBlockFile(filePath, size string) (bool, error) { } if newSizeBytes < oldSizeBytes { - return false, fmt.Errorf("You cannot shrink block volumes") + return false, errors.Wrap(ErrCannotBeShrunk, "You cannot shrink block volumes") } if newSizeBytes == oldSizeBytes {
_______________________________________________ lxc-devel mailing list lxc-devel@lists.linuxcontainers.org http://lists.linuxcontainers.org/listinfo/lxc-devel