The following pull request was submitted through Github. It can be accessed and reviewed at: https://github.com/lxc/lxd/pull/7270
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) === This PR is larger than expected as I found a number of bugs and issues along the way: - Allows regeneration of cached image volume if size is larger than pool's volume size. - Ensures new volumes have their size set correctly (was previously ignored). - Always respects setting of ``ceph.rbd.clone_copy`. - Reworks zombie volume management to use volume type consistently rather than a mixture of volume type and volume name (WIP). Still a draft as I have some design questions for @stgraber and more testing to do.
From d5ab08fb1679168bcf0768f4552af95afda482a4 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Fri, 24 Apr 2020 11:35:30 +0100 Subject: [PATCH 01/24] lxd/storage/drivers/driver/ceph/volumes: Only check content type is block not volume type No need to check volume type when checking for deleted volumes. Also removes line wrapping. Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/storage/drivers/driver_ceph_volumes.go | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/lxd/storage/drivers/driver_ceph_volumes.go b/lxd/storage/drivers/driver_ceph_volumes.go index 623a12b182..d37908a4dc 100644 --- a/lxd/storage/drivers/driver_ceph_volumes.go +++ b/lxd/storage/drivers/driver_ceph_volumes.go @@ -40,11 +40,10 @@ func (d *ceph) CreateVolume(vol Volume, filler *VolumeFiller, op *operations.Ope } // Figure out the potential zombie volume. - zombieImageVol := NewVolume(d, d.name, VolumeType("zombie_image"), vol.contentType, - fmt.Sprintf("%s_%s", vol.name, d.getRBDFilesystem(vol)), nil, nil) - if (vol.volType == VolumeTypeVM || vol.volType == VolumeTypeImage) && vol.contentType == ContentTypeBlock { - zombieImageVol = NewVolume(d, d.name, VolumeType("zombie_image"), vol.contentType, - fmt.Sprintf("%s_%s.block", vol.name, d.getRBDFilesystem(vol)), nil, nil) + zombieImageVol := NewVolume(d, d.name, VolumeType("zombie_image"), vol.contentType, fmt.Sprintf("%s_%s", vol.name, d.getRBDFilesystem(vol)), nil, nil) + + if vol.contentType == ContentTypeBlock { + zombieImageVol = NewVolume(d, d.name, VolumeType("zombie_image"), vol.contentType, fmt.Sprintf("%s_%s.block", vol.name, d.getRBDFilesystem(vol)), nil, nil) } // Check if we have a zombie image. If so, restore it otherwise From 3ee38d3a370cf7ebf9a0ec55fcbfd8ad82a7145a Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Fri, 24 Apr 2020 11:36:12 +0100 Subject: [PATCH 02/24] lxd/storage/drivers/driver/ceph/volumes: Removes line wrapping Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/storage/drivers/driver_ceph_volumes.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lxd/storage/drivers/driver_ceph_volumes.go b/lxd/storage/drivers/driver_ceph_volumes.go index d37908a4dc..1bdb10d7fc 100644 --- a/lxd/storage/drivers/driver_ceph_volumes.go +++ b/lxd/storage/drivers/driver_ceph_volumes.go @@ -46,8 +46,7 @@ func (d *ceph) CreateVolume(vol Volume, filler *VolumeFiller, op *operations.Ope zombieImageVol = NewVolume(d, d.name, VolumeType("zombie_image"), vol.contentType, fmt.Sprintf("%s_%s.block", vol.name, d.getRBDFilesystem(vol)), nil, nil) } - // Check if we have a zombie image. If so, restore it otherwise - // create a new image volume. + // Check if we have a zombie image. If so, restore it otherwise create a new image volume. if vol.volType == VolumeTypeImage && d.HasVolume(zombieImageVol) { // Figure out the names. oldName := d.getRBDVolumeName(zombieImageVol, "", false, true) From 131ec36441b6b57af205b718aabfc485f93bd575 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Fri, 24 Apr 2020 11:57:39 +0100 Subject: [PATCH 03/24] lxd/storage/drivers/driver/ceph/utils: Uses defaultBlockSize rather than hardcoded 10GB Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/storage/drivers/driver_ceph_utils.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lxd/storage/drivers/driver_ceph_utils.go b/lxd/storage/drivers/driver_ceph_utils.go index 1643142f58..ac3d3b4086 100644 --- a/lxd/storage/drivers/driver_ceph_utils.go +++ b/lxd/storage/drivers/driver_ceph_utils.go @@ -528,7 +528,7 @@ func (d *ceph) getRBDSize(vol Volume) (string, error) { // Safety net: Set to default value. if sz == 0 { - sz, _ = units.ParseByteSizeString("10GB") + sz, _ = units.ParseByteSizeString(defaultBlockSize) } return fmt.Sprintf("%dB", sz), nil From db30e750a06b249631438920495a1745b91ebd30 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Fri, 24 Apr 2020 14:15:40 +0100 Subject: [PATCH 04/24] lxd/storage/drivers/driver/ceph/volumes: Adds getVolumeSize function Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/storage/drivers/driver_ceph_volumes.go | 27 ++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/lxd/storage/drivers/driver_ceph_volumes.go b/lxd/storage/drivers/driver_ceph_volumes.go index 1bdb10d7fc..fbdf1cc762 100644 --- a/lxd/storage/drivers/driver_ceph_volumes.go +++ b/lxd/storage/drivers/driver_ceph_volumes.go @@ -207,6 +207,33 @@ func (d *ceph) CreateVolume(vol Volume, filler *VolumeFiller, op *operations.Ope return nil } +// getVolumeSize returns the volume's size in bytes. +func (d *ceph) getVolumeSize(volumeName string) (int64, error) { + volInfo := struct { + Size int64 `json:"size"` + }{} + + jsonInfo, err := shared.TryRunCommand( + "rbd", + "info", + "--format", "json", + "--id", d.config["ceph.user.name"], + "--cluster", d.config["ceph.cluster_name"], + "--pool", d.config["ceph.osd.pool_name"], + volumeName, + ) + if err != nil { + return -1, err + } + + err = json.Unmarshal([]byte(jsonInfo), &volInfo) + if err != nil { + return -1, err + } + + return volInfo.Size, nil +} + // 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 genericVFSBackupUnpack(d, vol, snapshots, srcData, op) From 55366e926830e7283e650c647a0547d342d4a0ef Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Fri, 24 Apr 2020 14:23:40 +0100 Subject: [PATCH 05/24] lxd/storage/drivers/driver/ceph/volumes: Restructures CreateVolume to reduce repetition Will make it cleaner to support regeneration of cached image volumes. Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/storage/drivers/driver_ceph_volumes.go | 54 ++++++++++++---------- 1 file changed, 30 insertions(+), 24 deletions(-) diff --git a/lxd/storage/drivers/driver_ceph_volumes.go b/lxd/storage/drivers/driver_ceph_volumes.go index fbdf1cc762..d245e330d4 100644 --- a/lxd/storage/drivers/driver_ceph_volumes.go +++ b/lxd/storage/drivers/driver_ceph_volumes.go @@ -25,6 +25,30 @@ import ( // CreateVolume creates an empty volume and can optionally fill it by executing the supplied // filler function. func (d *ceph) CreateVolume(vol Volume, filler *VolumeFiller, op *operations.Operation) error { + // Function to rename an RBD volume. + renameVolume := func(oldName string, newName string) error { + _, err := shared.RunCommand( + "rbd", + "--id", d.config["ceph.user.name"], + "--cluster", d.config["ceph.cluster_name"], + "mv", + oldName, + newName, + ) + return err + } + + // Function to generate the deleted zombie equivalent of a volume. + deletedVolume := func(v Volume) Volume { + deletedVol := NewVolume(d, d.name, VolumeType("zombie_image"), v.contentType, fmt.Sprintf("%s_%s", v.name, d.getRBDFilesystem(vol)), vol.config, vol.poolConfig) + + if vol.contentType == ContentTypeBlock { + deletedVol = NewVolume(d, d.name, VolumeType("zombie_image"), v.contentType, fmt.Sprintf("%s_%s.block", v.name, d.getRBDFilesystem(vol)), vol.config, vol.poolConfig) + } + + return deletedVol + } + // Revert handling. revert := revert.New() defer revert.Fail() @@ -39,41 +63,23 @@ func (d *ceph) CreateVolume(vol Volume, filler *VolumeFiller, op *operations.Ope revert.Add(func() { os.Remove(vol.MountPath()) }) } - // Figure out the potential zombie volume. - zombieImageVol := NewVolume(d, d.name, VolumeType("zombie_image"), vol.contentType, fmt.Sprintf("%s_%s", vol.name, d.getRBDFilesystem(vol)), nil, nil) + deletedVol := deletedVolume(vol) - if vol.contentType == ContentTypeBlock { - zombieImageVol = NewVolume(d, d.name, VolumeType("zombie_image"), vol.contentType, fmt.Sprintf("%s_%s.block", vol.name, d.getRBDFilesystem(vol)), nil, nil) - } - - // Check if we have a zombie image. If so, restore it otherwise create a new image volume. - if vol.volType == VolumeTypeImage && d.HasVolume(zombieImageVol) { - // Figure out the names. - oldName := d.getRBDVolumeName(zombieImageVol, "", false, true) - newName := d.getRBDVolumeName(vol, "", false, true) - - // Rename back to active. - _, err := shared.RunCommand( - "rbd", - "--id", d.config["ceph.user.name"], - "--cluster", d.config["ceph.cluster_name"], - "mv", - oldName, - newName) + // Check if we have a deleted zombie image. If so, restore it otherwise create a new image volume. + if vol.volType == VolumeTypeImage && d.HasVolume(deletedVol) { + err := renameVolume(d.getRBDVolumeName(deletedVol, "", false, true), d.getRBDVolumeName(vol, "", false, true)) if err != nil { return err } - // For VMs, also create the filesystem volume. if vol.IsVMBlock() { + fsDeletedVol := deletedVol.NewVMBlockFilesystemVolume() fsVol := vol.NewVMBlockFilesystemVolume() - err := d.CreateVolume(fsVol, nil, op) + err = renameVolume(d.getRBDVolumeName(fsDeletedVol, "", false, true), d.getRBDVolumeName(fsVol, "", false, true)) if err != nil { return err } - - revert.Add(func() { d.DeleteVolume(fsVol, op) }) } revert.Success() From 47c1f01e1ea6b027e20859bdc55a5b3e11515d8c Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Fri, 24 Apr 2020 15:13:33 +0100 Subject: [PATCH 06/24] lxd/storage/drivers/driver/ceph/volumes: Removes unnecessary mount/unmount Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/storage/drivers/driver_ceph_volumes.go | 9 --------- 1 file changed, 9 deletions(-) diff --git a/lxd/storage/drivers/driver_ceph_volumes.go b/lxd/storage/drivers/driver_ceph_volumes.go index d245e330d4..74e09a916a 100644 --- a/lxd/storage/drivers/driver_ceph_volumes.go +++ b/lxd/storage/drivers/driver_ceph_volumes.go @@ -436,15 +436,6 @@ func (d *ceph) CreateVolumeFromCopy(vol Volume, srcVol Volume, copySnapshots boo return err } - ourMount, err := d.MountVolume(vol, op) - if err != nil { - return err - } - - if ourMount { - defer d.UnmountVolume(vol, op) - } - revert.Success() return nil From 022d9e6ea97207f48c9f1e5d66d78fe843ee7330 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Fri, 24 Apr 2020 15:20:19 +0100 Subject: [PATCH 07/24] lxd/storage/drivers/driver/zfs/volumes: Clarify clone comments Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/storage/drivers/driver_zfs_volumes.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lxd/storage/drivers/driver_zfs_volumes.go b/lxd/storage/drivers/driver_zfs_volumes.go index 972c63211e..73bc4fac87 100644 --- a/lxd/storage/drivers/driver_zfs_volumes.go +++ b/lxd/storage/drivers/driver_zfs_volumes.go @@ -491,7 +491,7 @@ func (d *zfs) CreateVolumeFromCopy(vol Volume, srcVol Volume, copySnapshots bool } } - // Handle zfs.clone_copy + // If zfs.clone_copy is disabled or source volume has snapshots, then use full copy mode. if (d.config["zfs.clone_copy"] != "" && !shared.IsTrue(d.config["zfs.clone_copy"])) || len(snapshots) > 0 { snapName := strings.SplitN(srcSnapshot, "@", 2)[1] @@ -557,6 +557,7 @@ func (d *zfs) CreateVolumeFromCopy(vol Volume, srcVol Volume, copySnapshots bool } } } else { + // Perform volume clone. args := []string{ "clone", srcSnapshot, From 62f0ecfe410d41548dab30ec91d36df4dddd4ae6 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Fri, 24 Apr 2020 16:09:12 +0100 Subject: [PATCH 08/24] lxd/storage/drivers/driver/ceph/volumes: Dont wrap lines Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/storage/drivers/driver_ceph_volumes.go | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/lxd/storage/drivers/driver_ceph_volumes.go b/lxd/storage/drivers/driver_ceph_volumes.go index 74e09a916a..5918e36232 100644 --- a/lxd/storage/drivers/driver_ceph_volumes.go +++ b/lxd/storage/drivers/driver_ceph_volumes.go @@ -248,11 +248,11 @@ func (d *ceph) CreateVolumeFromBackup(vol Volume, snapshots []string, srcData io // CreateVolumeFromCopy provides same-pool volume copying functionality. func (d *ceph) CreateVolumeFromCopy(vol Volume, srcVol Volume, copySnapshots bool, op *operations.Operation) error { var err error - snapshots := []string{} - revert := revert.New() defer revert.Fail() + // Retrieve snapshots on the source. + snapshots := []string{} if !srcVol.IsSnapshot() && copySnapshots { snapshots, err = d.VolumeSnapshots(srcVol, op) if err != nil { @@ -262,16 +262,16 @@ func (d *ceph) CreateVolumeFromCopy(vol Volume, srcVol Volume, copySnapshots boo // Copy without snapshots. if !copySnapshots || len(snapshots) == 0 { - if d.config["ceph.rbd.clone_copy"] != "" && - !shared.IsTrue(d.config["ceph.rbd.clone_copy"]) && - srcVol.volType != VolumeTypeImage { + // If lightweight clone mode isn't enabled, perform a full copy of the volume. + if d.config["ceph.rbd.clone_copy"] != "" && !shared.IsTrue(d.config["ceph.rbd.clone_copy"]) && srcVol.volType != VolumeTypeImage { _, err = shared.RunCommand( "rbd", "--id", d.config["ceph.user.name"], "--cluster", d.config["ceph.cluster_name"], "cp", d.getRBDVolumeName(srcVol, "", false, true), - d.getRBDVolumeName(vol, "", false, true)) + d.getRBDVolumeName(vol, "", false, true), + ) if err != nil { return err } @@ -292,10 +292,8 @@ func (d *ceph) CreateVolumeFromCopy(vol Volume, srcVol Volume, copySnapshots boo snapshotName = fmt.Sprintf("zombie_snapshot_%s", uuid.NewRandom().String()) if srcVol.IsSnapshot() { - srcParentName, srcSnapOnlyName, _ := - shared.InstanceGetParentAndSnapshotName(srcVol.name) + srcParentName, srcSnapOnlyName, _ := shared.InstanceGetParentAndSnapshotName(srcVol.name) snapshotName = fmt.Sprintf("snapshot_%s", srcSnapOnlyName) - parentVol = NewVolume(d, d.name, srcVol.volType, srcVol.contentType, srcParentName, nil, nil) } else { // Create snapshot. From 5ed4129bf42c77b0d6cdc0c579d64c78f2e48c43 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Fri, 24 Apr 2020 17:24:53 +0100 Subject: [PATCH 09/24] lxd/storage/drivers/driver/ceph/volumes: Allow regeneration of image volumes in CreateVolume When volume.size is smaller than cached image size. Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/storage/drivers/driver_ceph_volumes.go | 82 +++++++++++++++------- 1 file changed, 56 insertions(+), 26 deletions(-) diff --git a/lxd/storage/drivers/driver_ceph_volumes.go b/lxd/storage/drivers/driver_ceph_volumes.go index 5918e36232..a023287a80 100644 --- a/lxd/storage/drivers/driver_ceph_volumes.go +++ b/lxd/storage/drivers/driver_ceph_volumes.go @@ -38,17 +38,6 @@ func (d *ceph) CreateVolume(vol Volume, filler *VolumeFiller, op *operations.Ope return err } - // Function to generate the deleted zombie equivalent of a volume. - deletedVolume := func(v Volume) Volume { - deletedVol := NewVolume(d, d.name, VolumeType("zombie_image"), v.contentType, fmt.Sprintf("%s_%s", v.name, d.getRBDFilesystem(vol)), vol.config, vol.poolConfig) - - if vol.contentType == ContentTypeBlock { - deletedVol = NewVolume(d, d.name, VolumeType("zombie_image"), v.contentType, fmt.Sprintf("%s_%s.block", v.name, d.getRBDFilesystem(vol)), vol.config, vol.poolConfig) - } - - return deletedVol - } - // Revert handling. revert := revert.New() defer revert.Fail() @@ -63,37 +52,77 @@ func (d *ceph) CreateVolume(vol Volume, filler *VolumeFiller, op *operations.Ope revert.Add(func() { os.Remove(vol.MountPath()) }) } - deletedVol := deletedVolume(vol) + // Create a "zombie" deleted volume representation of the specified volume to look for its existance. + deletedVol := NewVolume(d, d.name, cephVolumeTypeZombieImage, vol.contentType, vol.name, vol.config, vol.poolConfig) // Check if we have a deleted zombie image. If so, restore it otherwise create a new image volume. if vol.volType == VolumeTypeImage && d.HasVolume(deletedVol) { - err := renameVolume(d.getRBDVolumeName(deletedVol, "", false, true), d.getRBDVolumeName(vol, "", false, true)) + canRestore := true + + // Check if the cached image volume is larger than the current pool volume.size setting + // (if so we won't be able to resize the snapshot to that the smaller size later). + volSizeBytes, err := d.getVolumeSize(d.getRBDVolumeName(deletedVol, "", false, true)) if err != nil { return err } - if vol.IsVMBlock() { - fsDeletedVol := deletedVol.NewVMBlockFilesystemVolume() - fsVol := vol.NewVMBlockFilesystemVolume() + poolVolSize := defaultBlockSize + if vol.poolConfig["volume.size"] != "" { + poolVolSize = vol.poolConfig["volume.size"] + } - err = renameVolume(d.getRBDVolumeName(fsDeletedVol, "", false, true), d.getRBDVolumeName(fsVol, "", false, true)) + poolVolSizeBytes, err := units.ParseByteSizeString(poolVolSize) + if err != nil { + return err + } + + // If the cached volume is larger than the pool volume size, then we can't use the + // deleted cached image volume and instead we will rename it to a random UUID so it can't + // be restored in the future and a new cached image volume will be created instead. + if volSizeBytes > poolVolSizeBytes { + randomVol := NewVolume(d, d.name, deletedVol.volType, deletedVol.contentType, strings.Replace(uuid.NewRandom().String(), "-", "", -1), deletedVol.config, deletedVol.poolConfig) + err = renameVolume(d.getRBDVolumeName(deletedVol, "", false, true), d.getRBDVolumeName(randomVol, "", false, true)) if err != nil { return err } + + if vol.IsVMBlock() { + fsDeletedVol := deletedVol.NewVMBlockFilesystemVolume() + fsRandomVol := randomVol.NewVMBlockFilesystemVolume() + + err = renameVolume(d.getRBDVolumeName(fsDeletedVol, "", false, true), d.getRBDVolumeName(fsRandomVol, "", false, true)) + if err != nil { + return err + } + } + + canRestore = false } - revert.Success() - return nil - } + // Restore the image. + if canRestore { + err = renameVolume(d.getRBDVolumeName(deletedVol, "", false, true), d.getRBDVolumeName(vol, "", false, true)) + if err != nil { + return err + } - // Get size. - RBDSize, err := d.getRBDSize(vol) - if err != nil { - return err + if vol.IsVMBlock() { + fsDeletedVol := deletedVol.NewVMBlockFilesystemVolume() + fsVol := vol.NewVMBlockFilesystemVolume() + + err = renameVolume(d.getRBDVolumeName(fsDeletedVol, "", false, true), d.getRBDVolumeName(fsVol, "", false, true)) + if err != nil { + return err + } + } + + revert.Success() + return nil + } } // Create volume. - err = d.rbdCreateVolume(vol, RBDSize) + err := d.rbdCreateVolume(vol, d.volumeSize(vol)) if err != nil { return err } @@ -182,7 +211,8 @@ func (d *ceph) CreateVolume(vol Volume, filler *VolumeFiller, op *operations.Ope } if vol.contentType == ContentTypeBlock { - // Re-create the FS config volume's readonly snapshot now that the filler function has run and unpacked into both config and block volumes. + // Re-create the FS config volume's readonly snapshot now that the filler function has run + // and unpacked into both config and block volumes. fsVol := NewVolume(d, d.name, vol.volType, ContentTypeFS, vol.name, vol.config, vol.poolConfig) err := d.rbdUnprotectVolumeSnapshot(fsVol, "readonly") From 9c24641cd9a07d4a5adecb09eb291c0a9bb7e76c Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Mon, 27 Apr 2020 11:23:09 +0100 Subject: [PATCH 10/24] lxd/storage/drivers/driver/ceph/volumes: Dont use clone mode when creating volume from cached image when it is disabled Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/storage/drivers/driver_ceph_volumes.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lxd/storage/drivers/driver_ceph_volumes.go b/lxd/storage/drivers/driver_ceph_volumes.go index a023287a80..a602524ac5 100644 --- a/lxd/storage/drivers/driver_ceph_volumes.go +++ b/lxd/storage/drivers/driver_ceph_volumes.go @@ -293,7 +293,7 @@ func (d *ceph) CreateVolumeFromCopy(vol Volume, srcVol Volume, copySnapshots boo // Copy without snapshots. if !copySnapshots || len(snapshots) == 0 { // If lightweight clone mode isn't enabled, perform a full copy of the volume. - if d.config["ceph.rbd.clone_copy"] != "" && !shared.IsTrue(d.config["ceph.rbd.clone_copy"]) && srcVol.volType != VolumeTypeImage { + if d.config["ceph.rbd.clone_copy"] != "" && !shared.IsTrue(d.config["ceph.rbd.clone_copy"]) { _, err = shared.RunCommand( "rbd", "--id", d.config["ceph.user.name"], From a79d560399a4a7973880557f3998aa1bc0400c16 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Tue, 28 Apr 2020 15:05:10 +0100 Subject: [PATCH 11/24] lxd/storage/utils: VolumeDBCreate comment formatting Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/storage/utils.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lxd/storage/utils.go b/lxd/storage/utils.go index 7065b98708..e7f55e3fdd 100644 --- a/lxd/storage/utils.go +++ b/lxd/storage/utils.go @@ -133,8 +133,7 @@ func VolumeDBCreate(s *state.State, project, poolName, volumeName, volumeDescrip return err } - // Check that a storage volume of the same storage volume type does not - // already exist. + // Check that a storage volume of the same storage volume type does not already exist. volumeID, _ := s.Cluster.StoragePoolNodeVolumeGetTypeIDByProject(project, volumeName, volumeType, poolID) if volumeID > 0 { return fmt.Errorf("A storage volume of type %s already exists", volumeTypeName) From e20330d1c2777ecff8b9e3fcf8ed2ec8b942e914 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Tue, 28 Apr 2020 15:05:32 +0100 Subject: [PATCH 12/24] lxd/storage/drivers/driver/zfs/volumes: Pass operation in CreateVolumeFromCopy 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 73bc4fac87..abcade9d49 100644 --- a/lxd/storage/drivers/driver_zfs_volumes.go +++ b/lxd/storage/drivers/driver_zfs_volumes.go @@ -596,7 +596,7 @@ func (d *zfs) CreateVolumeFromCopy(vol Volume, srcVol Volume, copySnapshots bool } // Resize the new volume and filesystem to the correct size. - err := d.SetVolumeQuota(vol, vol.ExpandedConfig("size"), nil) + err := d.SetVolumeQuota(vol, vol.ExpandedConfig("size"), op) if err != nil { return err } From 7c7a71eb0afbb4fb1b0b0f74ebf2bd1d5efa95ae Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Tue, 28 Apr 2020 15:07:12 +0100 Subject: [PATCH 13/24] lxc/storage/drivers/driver/ceph/utils: Reworks parseParent to return a Volume struct Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/storage/drivers/driver_ceph_utils.go | 63 ++++++++++-------------- 1 file changed, 25 insertions(+), 38 deletions(-) diff --git a/lxd/storage/drivers/driver_ceph_utils.go b/lxd/storage/drivers/driver_ceph_utils.go index ac3d3b4086..a90eee051d 100644 --- a/lxd/storage/drivers/driver_ceph_utils.go +++ b/lxd/storage/drivers/driver_ceph_utils.go @@ -7,6 +7,7 @@ import ( "io/ioutil" "os" "os/exec" + "regexp" "strconv" "strings" "syscall" @@ -853,54 +854,40 @@ func (d *ceph) deleteVolumeSnapshot(vol Volume, snapshotName string) (int, error // parseParent splits a string describing a RBD storage entity into its components. // This can be used on strings like // <osd-pool-name>/<lxd-specific-prefix>_<rbd-storage-volume>@<rbd-snapshot-name> -// and will split it into -// <osd-pool-name>, <rbd-storage-volume>, <lxd-specific-prefix>, <rbdd-snapshot-name> -func (d *ceph) parseParent(parent string) (string, string, string, string, error) { +// and will return a Volume and snapshot name. +func (d *ceph) parseParent(parent string) (Volume, string, error) { + vol := Volume{} + idx := strings.Index(parent, "/") if idx == -1 { - return "", "", "", "", fmt.Errorf("Unexpected parsing error") + return vol, "", fmt.Errorf("Pool delimiter not found") } slider := parent[(idx + 1):] poolName := parent[:idx] - volumeType := slider - idx = strings.Index(slider, "zombie_") - if idx == 0 { - idx += len("zombie_") - volumeType = slider - slider = slider[idx:] - } - - idxType := strings.Index(slider, "_") - if idxType == -1 { - return "", "", "", "", fmt.Errorf("Unexpected parsing error") - } - - if idx == len("zombie_") { - idxType += idx - } - volumeType = volumeType[:idxType] - - idx = strings.Index(slider, "_") - if idx == -1 { - return "", "", "", "", fmt.Errorf("Unexpected parsing error") - } + // Match image volumes and extract their various parts into a Volume struct. + // Looks for image volumes like: + // pool/zombie_image_9e90b7b9ccdd7a671a987fadcf07ab92363be57e7f056d18d42af452cdaf95bb_ext4.block@readonly + // pool/image_9e90b7b9ccdd7a671a987fadcf07ab92363be57e7f056d18d42af452cdaf95bb_xfs + reImage := regexp.MustCompile(`^((?:zombie_)?image)_([A-Za-z0-9]+)_([A-Za-z0-9]+)\.?(block)?@?([-\w]+)?$`) + if imageRes := reImage.FindStringSubmatch(slider); imageRes != nil { + vol.volType = VolumeType(imageRes[1]) + vol.pool = poolName + vol.name = imageRes[2] + vol.config = map[string]string{ + "block.filesystem": imageRes[3], + } - volumeName := slider - idx = strings.Index(volumeName, "_") - if idx == -1 { - return "", "", "", "", fmt.Errorf("Unexpected parsing error") - } - volumeName = volumeName[(idx + 1):] + if imageRes[4] == "block" { + vol.contentType = ContentTypeBlock + } else { + vol.contentType = ContentTypeFS + } - idx = strings.Index(volumeName, "@") - if idx == -1 { - return "", "", "", "", fmt.Errorf("Unexpected parsing error") + return vol, imageRes[5], nil } - snapshotName := volumeName[(idx + 1):] - volumeName = volumeName[:idx] - return poolName, volumeType, volumeName, snapshotName, nil + return vol, "", fmt.Errorf("Unrecognised parent: %q", parent) } // parseClone splits a strings describing an RBD storage volume. From 9c2396fc772fce1c52924bd5258e252f605ac78a Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Tue, 28 Apr 2020 15:07:36 +0100 Subject: [PATCH 14/24] lxd/storage/drivers/driver/ceph/utils: Adds cephVolumeTypeZombieImage constant Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/storage/drivers/driver_ceph_utils.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lxd/storage/drivers/driver_ceph_utils.go b/lxd/storage/drivers/driver_ceph_utils.go index a90eee051d..5042d98824 100644 --- a/lxd/storage/drivers/driver_ceph_utils.go +++ b/lxd/storage/drivers/driver_ceph_utils.go @@ -22,6 +22,8 @@ import ( "github.com/lxc/lxd/shared/units" ) +const cephVolumeTypeZombieImage = VolumeType("zombie_image") + // osdPoolExists checks whether a given OSD pool exists. func (d *ceph) osdPoolExists() bool { _, err := shared.RunCommand( From b8b091d740c8e7c1c15219f18be1f3fc63b40ac6 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Tue, 28 Apr 2020 15:08:00 +0100 Subject: [PATCH 15/24] lxd/storage/drivers/driver/ceph/utils: Updates rbdCreateVolume to accept string size And parse it to bytes internally. Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/storage/drivers/driver_ceph_utils.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/lxd/storage/drivers/driver_ceph_utils.go b/lxd/storage/drivers/driver_ceph_utils.go index 5042d98824..2fdd6bd1d0 100644 --- a/lxd/storage/drivers/driver_ceph_utils.go +++ b/lxd/storage/drivers/driver_ceph_utils.go @@ -70,6 +70,11 @@ func (d *ceph) osdDeletePool() error { // library and the kernel module are minimized. Otherwise random panics might // occur. func (d *ceph) rbdCreateVolume(vol Volume, size string) error { + sizeBytes, err := units.ParseByteSizeString(size) + if err != nil { + return err + } + cmd := []string{ "--id", d.config["ceph.user.name"], "--image-feature", "layering,", @@ -82,11 +87,11 @@ func (d *ceph) rbdCreateVolume(vol Volume, size string) error { } cmd = append(cmd, - "--size", size, + "--size", fmt.Sprintf("%dB", sizeBytes), "create", d.getRBDVolumeName(vol, "", false, false)) - _, err := shared.RunCommand("rbd", cmd...) + _, err = shared.RunCommand("rbd", cmd...) return err } From fd9a7d9dfe3b7e75da09bee51d0f8a3431da9373 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Tue, 28 Apr 2020 15:09:22 +0100 Subject: [PATCH 16/24] lxd/storage/drivers/driver/ceph/utils: Pass volume config in rbdMarkVolumeDeleted Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/storage/drivers/driver_ceph_utils.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lxd/storage/drivers/driver_ceph_utils.go b/lxd/storage/drivers/driver_ceph_utils.go index 2fdd6bd1d0..33f795f50a 100644 --- a/lxd/storage/drivers/driver_ceph_utils.go +++ b/lxd/storage/drivers/driver_ceph_utils.go @@ -356,15 +356,19 @@ func (d *ceph) rbdListSnapshotClones(vol Volume, snapshotName string) ([]string, // creating a sparse copy of a container or when LXD updated an image and the // image still has dependent container clones. func (d *ceph) rbdMarkVolumeDeleted(vol Volume, newVolumeName string) error { - newVol := NewVolume(d, d.name, vol.volType, vol.contentType, newVolumeName, nil, nil) + // Ensure that new volume contains the config from the source volume to maintain filesystem suffix on + // new volume name generated in getRBDVolumeName. + newVol := NewVolume(d, d.name, vol.volType, vol.contentType, newVolumeName, vol.config, vol.poolConfig) deletedName := d.getRBDVolumeName(newVol, "", true, true) + _, err := shared.RunCommand( "rbd", "--id", d.config["ceph.user.name"], "--cluster", d.config["ceph.cluster_name"], "mv", d.getRBDVolumeName(vol, "", false, true), - deletedName) + deletedName, + ) if err != nil { return err } From 625c8cfa86366f40e06c40ae78b1644d1fde99ce Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Tue, 28 Apr 2020 15:09:42 +0100 Subject: [PATCH 17/24] lxd/storage/drivers/driver/ceph/utils: Pass volume config in rbdRenameVolume Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/storage/drivers/driver_ceph_utils.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lxd/storage/drivers/driver_ceph_utils.go b/lxd/storage/drivers/driver_ceph_utils.go index 33f795f50a..1fc7b0819a 100644 --- a/lxd/storage/drivers/driver_ceph_utils.go +++ b/lxd/storage/drivers/driver_ceph_utils.go @@ -382,7 +382,9 @@ func (d *ceph) rbdMarkVolumeDeleted(vol Volume, newVolumeName string) error { // under its original name and the callers maps it under its new name the image // will be mapped twice. This will prevent it from being deleted. func (d *ceph) rbdRenameVolume(vol Volume, newVolumeName string) error { - newVol := NewVolume(d, d.name, vol.volType, vol.contentType, newVolumeName, nil, nil) + // Ensure that new volume contains the config from the source volume to maintain filesystem suffix on + // new volume name generated in getRBDVolumeName. + newVol := NewVolume(d, d.name, vol.volType, vol.contentType, newVolumeName, vol.config, vol.poolConfig) _, err := shared.RunCommand( "rbd", @@ -390,7 +392,8 @@ func (d *ceph) rbdRenameVolume(vol Volume, newVolumeName string) error { "--cluster", d.config["ceph.cluster_name"], "mv", d.getRBDVolumeName(vol, "", false, true), - d.getRBDVolumeName(newVol, "", false, true)) + d.getRBDVolumeName(newVol, "", false, true), + ) if err != nil { return err } From c73736ec551b31bd3f070ac667871dcc0c27ca62 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Tue, 28 Apr 2020 15:10:07 +0100 Subject: [PATCH 18/24] lxd/storage/drivers/driver/ceph/utils: Replaces getRBDSize with volumeSize Aligns with LVM behaviour. Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/storage/drivers/driver_ceph_utils.go | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/lxd/storage/drivers/driver_ceph_utils.go b/lxd/storage/drivers/driver_ceph_utils.go index 1fc7b0819a..5326da6f97 100644 --- a/lxd/storage/drivers/driver_ceph_utils.go +++ b/lxd/storage/drivers/driver_ceph_utils.go @@ -529,24 +529,14 @@ func (d *ceph) rbdListVolumeSnapshots(vol Volume) ([]string, error) { return snapshots, nil } -// getRBDSize returns the size the RBD storage volume is supposed to be created with. -func (d *ceph) getRBDSize(vol Volume) (string, error) { - size, ok := vol.config["size"] - if !ok { - size = vol.poolConfig["volume.size"] +// volumeSize returns the size to use when creating new RBD volumes. +func (d *ceph) volumeSize(vol Volume) string { + size := vol.ExpandedConfig("size") + if size == "" || size == "0" { + return defaultBlockSize } - sz, err := units.ParseByteSizeString(size) - if err != nil { - return "", err - } - - // Safety net: Set to default value. - if sz == 0 { - sz, _ = units.ParseByteSizeString(defaultBlockSize) - } - - return fmt.Sprintf("%dB", sz), nil + return size } // getRBDFilesystem returns the filesystem the RBD storage volume is supposed to be created with. From 3246555da3ae6f437b496ed628cbf3e1dc32b407 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Tue, 28 Apr 2020 15:10:38 +0100 Subject: [PATCH 19/24] lxd/storage/drivers/driver/ceph/utils: Dont wrap lines Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/storage/drivers/driver_ceph_utils.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lxd/storage/drivers/driver_ceph_utils.go b/lxd/storage/drivers/driver_ceph_utils.go index 5326da6f97..ce2e8209e2 100644 --- a/lxd/storage/drivers/driver_ceph_utils.go +++ b/lxd/storage/drivers/driver_ceph_utils.go @@ -658,8 +658,7 @@ func (d *ceph) deleteVolume(vol Volume) (int, error) { return -1, err } - if strings.HasPrefix(vol.name, "zombie_") || - strings.HasPrefix(string(vol.volType), "zombie_") { + if strings.HasPrefix(vol.name, "zombie_") || strings.HasPrefix(string(vol.volType), "zombie_") { return 1, nil } From ce3556c89698dac94bc96b773d549161f7763d80 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Tue, 28 Apr 2020 15:10:59 +0100 Subject: [PATCH 20/24] lxd/storage/drivers/driver/ceph/utils: Updates usage of d.parseParent in deleteVolume Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/storage/drivers/driver_ceph_utils.go | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/lxd/storage/drivers/driver_ceph_utils.go b/lxd/storage/drivers/driver_ceph_utils.go index ce2e8209e2..cf1195e3d2 100644 --- a/lxd/storage/drivers/driver_ceph_utils.go +++ b/lxd/storage/drivers/driver_ceph_utils.go @@ -677,8 +677,7 @@ func (d *ceph) deleteVolume(vol Volume) (int, error) { parent, err := d.rbdGetVolumeParent(vol) if err == nil { - _, parentVolumeType, parentVolumeName, - parentSnapshotName, err := d.parseParent(parent) + parentVol, parentSnapshotName, err := d.parseParent(parent) if err != nil { return -1, err } @@ -695,13 +694,9 @@ func (d *ceph) deleteVolume(vol Volume) (int, error) { return -1, err } - parentVol := NewVolume(d, d.name, VolumeType(parentVolumeType), vol.contentType, parentVolumeName, nil, nil) - - // Only delete the parent snapshot of the container if - // it is a zombie. If it is not we know that LXD is - // still using it. - if strings.HasPrefix(parentVolumeType, "zombie_") || - strings.HasPrefix(parentSnapshotName, "zombie_") { + // Only delete the parent snapshot of the container if it is a zombie. + // If it is not we know that LXD is still using it. + if strings.HasPrefix(string(parentVol.volType), "zombie_") { ret, err := d.deleteVolumeSnapshot(parentVol, parentSnapshotName) if ret < 0 { return -1, err From 16b62ffd9ed5059922ed3724ec93babdce7219ef Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Tue, 28 Apr 2020 15:11:26 +0100 Subject: [PATCH 21/24] lxd/storage/drivers/driver/ceph/utils: Updates RBD naming logic in getRBDVolumeName Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/storage/drivers/driver_ceph_utils.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lxd/storage/drivers/driver_ceph_utils.go b/lxd/storage/drivers/driver_ceph_utils.go index cf1195e3d2..8c8e39d00a 100644 --- a/lxd/storage/drivers/driver_ceph_utils.go +++ b/lxd/storage/drivers/driver_ceph_utils.go @@ -1041,11 +1041,12 @@ func (d *ceph) getRBDVolumeName(vol Volume, snapName string, zombie bool, withPo volumeType := string(vol.volType) parentName, snapshotName, isSnapshot := shared.InstanceGetParentAndSnapshotName(vol.name) - if vol.volType == VolumeTypeImage { + // Only use filesystem suffix on filesystem type image volumes (for all content types). + if vol.volType == VolumeTypeImage || vol.volType == cephVolumeTypeZombieImage { parentName = fmt.Sprintf("%s_%s", parentName, d.getRBDFilesystem(vol)) } - if (vol.volType == VolumeTypeVM || vol.volType == VolumeTypeImage) && vol.contentType == ContentTypeBlock { + if vol.contentType == ContentTypeBlock { parentName = fmt.Sprintf("%s.block", parentName) } From 61770828dd7574c96a0363e18e2e31037e2ec125 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Tue, 28 Apr 2020 15:11:52 +0100 Subject: [PATCH 22/24] lxd/storage/drivers/driver/ceph/utils: Adds tests for parseParent Both for testing and documentation purposes. Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/storage/drivers/driver_ceph_utils_test.go | 31 ++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/lxd/storage/drivers/driver_ceph_utils_test.go b/lxd/storage/drivers/driver_ceph_utils_test.go index 7f558e3c73..59c7e5732b 100644 --- a/lxd/storage/drivers/driver_ceph_utils_test.go +++ b/lxd/storage/drivers/driver_ceph_utils_test.go @@ -1,6 +1,9 @@ package drivers -import "testing" +import ( + "fmt" + "testing" +) func Test_ceph_getRBDVolumeName(t *testing.T) { type args struct { @@ -110,3 +113,29 @@ func Test_ceph_getRBDVolumeName(t *testing.T) { }) } } +func Example_ceph_parseParent() { + d := &ceph{} + + parents := []string{ + "pool/zombie_image_9e90b7b9ccdd7a671a987fadcf07ab92363be57e7f056d18d42af452cdaf95bb_ext4.block@readonly", + "pool/zombie_image_9e90b7b9ccdd7a671a987fadcf07ab92363be57e7f056d18d42af452cdaf95bb_ext4.block", + "pool/image_9e90b7b9ccdd7a671a987fadcf07ab92363be57e7f056d18d42af452cdaf95bb_ext4.block@readonly", + "pool/zombie_image_9e90b7b9ccdd7a671a987fadcf07ab92363be57e7f056d18d42af452cdaf95bb_ext4@readonly", + "pool/zombie_image_9e90b7b9ccdd7a671a987fadcf07ab92363be57e7f056d18d42af452cdaf95bb_ext4", + "pool/image_9e90b7b9ccdd7a671a987fadcf07ab92363be57e7f056d18d42af452cdaf95bb_ext4@readonly", + "pool/zombie_image_2cfc5a5567b8d74c0986f3d8a77a2a78e58fe22ea9abd2693112031f85afa1a1_xfs@zombie_snapshot_7f6d679b-ee25-419e-af49-bb805cb32088", + } + + for _, parent := range parents { + vol, snapName, err := d.parseParent(parent) + fmt.Println(vol.pool, vol.volType, vol.name, vol.config["block.filesystem"], vol.contentType, snapName, err) + } + + // Output: pool zombie_image 9e90b7b9ccdd7a671a987fadcf07ab92363be57e7f056d18d42af452cdaf95bb ext4 block readonly <nil> + // pool zombie_image 9e90b7b9ccdd7a671a987fadcf07ab92363be57e7f056d18d42af452cdaf95bb ext4 block <nil> + // pool image 9e90b7b9ccdd7a671a987fadcf07ab92363be57e7f056d18d42af452cdaf95bb ext4 block readonly <nil> + // pool zombie_image 9e90b7b9ccdd7a671a987fadcf07ab92363be57e7f056d18d42af452cdaf95bb ext4 fs readonly <nil> + // pool zombie_image 9e90b7b9ccdd7a671a987fadcf07ab92363be57e7f056d18d42af452cdaf95bb ext4 fs <nil> + // pool image 9e90b7b9ccdd7a671a987fadcf07ab92363be57e7f056d18d42af452cdaf95bb ext4 fs readonly <nil> + // pool zombie_image 2cfc5a5567b8d74c0986f3d8a77a2a78e58fe22ea9abd2693112031f85afa1a1 xfs fs zombie_snapshot_7f6d679b-ee25-419e-af49-bb805cb32088 <nil> +} From eb9023127a94d949a32ddb5dfa5dc5c8f6b9c0f4 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Tue, 28 Apr 2020 15:13:55 +0100 Subject: [PATCH 23/24] lxd/storage/drivers/driver/ceph/volumes: Ensures CreateVolumeFromCopy always sizes new volume Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/storage/drivers/driver_ceph_volumes.go | 82 ++++++++++------------ 1 file changed, 39 insertions(+), 43 deletions(-) diff --git a/lxd/storage/drivers/driver_ceph_volumes.go b/lxd/storage/drivers/driver_ceph_volumes.go index a602524ac5..32a5d1eb1b 100644 --- a/lxd/storage/drivers/driver_ceph_volumes.go +++ b/lxd/storage/drivers/driver_ceph_volumes.go @@ -281,6 +281,37 @@ func (d *ceph) CreateVolumeFromCopy(vol Volume, srcVol Volume, copySnapshots boo revert := revert.New() defer revert.Fail() + // Function to run once the volume is created, which will regenerate the filesystem UUID (if needed), + // ensure permissions on mount path inside the volume are correct, and resize the volume to specified size. + postCreateTasks := func(v Volume) error { + // Map the RBD volume. + RBDDevPath, err := d.rbdMapVolume(v) + if err != nil { + return err + } + defer d.rbdUnmapVolume(v, true) + + if vol.contentType == ContentTypeFS { + // Re-generate the UUID. Do this first as ensuring permissions and setting quota can + // rely on being able to mount the volume. + err = d.generateUUID(d.getRBDFilesystem(v), RBDDevPath) + if err != nil { + return err + } + + // Mount the volume and ensure the permissions are set correctly inside the mounted volume. + err = v.MountTask(func(_ string, _ *operations.Operation) error { + return v.EnsureMountPath() + }, op) + if err != nil { + return err + } + } + + // Resize the new volume and filesystem to the correct size. + return d.SetVolumeQuota(v, d.volumeSize(v), op) + } + // Retrieve snapshots on the source. snapshots := []string{} if !srcVol.IsSnapshot() && copySnapshots { @@ -350,40 +381,21 @@ func (d *ceph) CreateVolumeFromCopy(vol Volume, srcVol Volume, copySnapshots boo revert.Add(func() { d.DeleteVolume(vol, op) }) } - if vol.contentType == ContentTypeFS { - // Map the RBD volume. - RBDDevPath, err := d.rbdMapVolume(vol) - if err != nil { - return err - } - defer d.rbdUnmapVolume(vol, true) - - // Re-generate the UUID. - err = d.generateUUID(d.getRBDFilesystem(vol), RBDDevPath) - if err != nil { - return err - } - - // Mount the volume and ensure the permissions are set correctly inside the mounted volume. - err = vol.MountTask(func(_ string, _ *operations.Operation) error { - return vol.EnsureMountPath() - }, op) - if err != nil { - return err - } - } - // For VMs, also copy the filesystem volume. if vol.IsVMBlock() { srcFSVol := srcVol.NewVMBlockFilesystemVolume() fsVol := vol.NewVMBlockFilesystemVolume() - err := d.CreateVolumeFromCopy(fsVol, srcFSVol, false, op) if err != nil { return err } } + err = postCreateTasks(vol) + if err != nil { + return err + } + revert.Success() return nil } @@ -418,11 +430,7 @@ func (d *ceph) CreateVolumeFromCopy(vol Volume, srcVol Volume, copySnapshots boo lastSnap = fmt.Sprintf("snapshot_%s", snap) sourceVolumeName := d.getRBDVolumeName(srcVol, lastSnap, false, true) - - err = d.copyWithSnapshots( - sourceVolumeName, - targetVolumeName, - prev) + err = d.copyWithSnapshots(sourceVolumeName, targetVolumeName, prev) if err != nil { return err } @@ -443,29 +451,17 @@ func (d *ceph) CreateVolumeFromCopy(vol Volume, srcVol Volume, copySnapshots boo // Copy snapshot. sourceVolumeName := d.getRBDVolumeName(srcVol, "", false, true) - err = d.copyWithSnapshots( - sourceVolumeName, - targetVolumeName, - lastSnap) - if err != nil { - return err - } - - // Map the RBD volume. - RBDDevPath, err := d.rbdMapVolume(vol) + err = d.copyWithSnapshots(sourceVolumeName, targetVolumeName, lastSnap) if err != nil { return err } - defer d.rbdUnmapVolume(vol, true) - // Re-generate the UUID. - err = d.generateUUID(d.getRBDFilesystem(vol), RBDDevPath) + err = postCreateTasks(vol) if err != nil { return err } revert.Success() - return nil } From 6a1aa390e1dcb38e94c56cefb4dd5c1852bef21b Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Tue, 28 Apr 2020 15:14:16 +0100 Subject: [PATCH 24/24] lxd/storage/drivers/driver/ceph/volumes: If volume doesnt exist in DeleteVolume do nothing Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/storage/drivers/driver_ceph_volumes.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lxd/storage/drivers/driver_ceph_volumes.go b/lxd/storage/drivers/driver_ceph_volumes.go index 32a5d1eb1b..49d1b02557 100644 --- a/lxd/storage/drivers/driver_ceph_volumes.go +++ b/lxd/storage/drivers/driver_ceph_volumes.go @@ -580,6 +580,10 @@ func (d *ceph) RefreshVolume(vol Volume, srcVol Volume, srcSnapshots []Volume, o // DeleteVolume deletes a volume of the storage device. If any snapshots of the volume remain then // this function will return an error. func (d *ceph) DeleteVolume(vol Volume, op *operations.Operation) error { + if !d.HasVolume(vol) { + return nil + } + if vol.volType == VolumeTypeImage { // Try to umount but don't fail. d.UnmountVolume(vol, op) @@ -630,10 +634,6 @@ func (d *ceph) DeleteVolume(vol Volume, op *operations.Operation) error { return err } } else { - if !d.HasVolume(vol) { - return nil - } - _, err := d.UnmountVolume(vol, op) if err != nil { return err
_______________________________________________ lxc-devel mailing list lxc-devel@lists.linuxcontainers.org http://lists.linuxcontainers.org/listinfo/lxc-devel