The following pull request was submitted through Github. It can be accessed and reviewed at: https://github.com/lxc/lxd/pull/6402
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) === Includes https://github.com/lxc/lxd/pull/6401
From e662852c556886462d4712d4aafff4819daa258c Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Tue, 5 Nov 2019 09:28:06 +0000 Subject: [PATCH 01/23] lxd/container: Links containerCreateAsEmpty to new storage package Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/container.go | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/lxd/container.go b/lxd/container.go index b841fc7e17..774b467bbc 100644 --- a/lxd/container.go +++ b/lxd/container.go @@ -254,22 +254,38 @@ type container interface { NextIdmap() (*idmap.IdmapSet, error) } -// Loader functions +// containerCreateAsEmpty creates an empty instance. func containerCreateAsEmpty(d *Daemon, args db.InstanceArgs) (container, error) { - // Create the container + // Create the container. c, err := containerCreateInternal(d.State(), args) if err != nil { return nil, err } - // Now create the empty storage - err = c.Storage().ContainerCreate(c) - if err != nil { - c.Delete() - return nil, err + // Check if we can load new storage layer for pool driver type. + pool, err := storagePools.GetPoolByInstance(d.State(), c) + if err != storageDrivers.ErrUnknownDriver && err != storageDrivers.ErrNotImplemented { + if err != nil { + return nil, errors.Wrap(err, "Load instance storage pool") + } + + err = pool.CreateInstance(c, nil) + if err != nil { + c.Delete() + return nil, errors.Wrap(err, "Create instance") + } + } else if c.Type() == instancetype.Container { + // Now create the empty storage. + err = c.Storage().ContainerCreate(c) + if err != nil { + c.Delete() + return nil, err + } + } else { + return nil, fmt.Errorf("Instance type not supported") } - // Apply any post-storage configuration + // Apply any post-storage configuration. err = containerConfigureInternal(c) if err != nil { c.Delete() From 561cfc75185c7235e0ef523c3292825b6dff24e8 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Tue, 5 Nov 2019 09:37:43 +0000 Subject: [PATCH 02/23] lxd/container: Adds revert to containerCreateFromImage Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/container.go | 1 + 1 file changed, 1 insertion(+) diff --git a/lxd/container.go b/lxd/container.go index 774b467bbc..e81cdbd833 100644 --- a/lxd/container.go +++ b/lxd/container.go @@ -495,6 +495,7 @@ func containerCreateFromImage(d *Daemon, args db.InstanceArgs, hash string, op * err = pool.CreateInstanceFromImage(c, hash, op) if err != nil { + c.Delete() return nil, errors.Wrap(err, "Create instance from image") } } else if c.Type() == instancetype.Container { From 50e540db953de9e133204ce54cd2e5455a0b8989 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Tue, 5 Nov 2019 09:40:40 +0000 Subject: [PATCH 03/23] lxd/container: containerCreateFromImage comment Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/container.go | 1 + 1 file changed, 1 insertion(+) diff --git a/lxd/container.go b/lxd/container.go index e81cdbd833..422ec47da8 100644 --- a/lxd/container.go +++ b/lxd/container.go @@ -419,6 +419,7 @@ func containerCreateEmptySnapshot(s *state.State, args db.InstanceArgs) (contain return c, nil } +// containerCreateFromImage creates an instance from a rootfs image. func containerCreateFromImage(d *Daemon, args db.InstanceArgs, hash string, op *operations.Operation) (container, error) { s := d.State() From f0b2bd348f386f0448dcbf18b002c79ff21ed475 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Tue, 5 Nov 2019 10:31:15 +0000 Subject: [PATCH 04/23] lxd/storage/drivers/utils: Makes GetVolumeSnapshotDir work with either snapshot or parent vol name Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/storage/drivers/utils.go | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/lxd/storage/drivers/utils.go b/lxd/storage/drivers/utils.go index 2277d3c57a..94715add21 100644 --- a/lxd/storage/drivers/utils.go +++ b/lxd/storage/drivers/utils.go @@ -183,11 +183,8 @@ func GetVolumeMountPath(poolName string, volType VolumeType, volName string) str // GetVolumeSnapshotDir gets the snapshot mount directory for the parent volume. func GetVolumeSnapshotDir(poolName string, volType VolumeType, volName string) (string, error) { - if shared.IsSnapshot(volName) { - return "", fmt.Errorf("Volume cannot be a snapshot") - } - - return shared.VarPath("storage-pools", poolName, fmt.Sprintf("%s-snapshots", string(volType)), project.Prefix("default", volName)), nil + parent, _, _ := shared.ContainerGetParentAndSnapshotName(volName) + return shared.VarPath("storage-pools", poolName, fmt.Sprintf("%s-snapshots", string(volType)), project.Prefix("default", parent)), nil } // GetSnapshotVolumeName returns the full volume name for a parent volume and snapshot name. From 7ed69fa051fda3392785891fd9bd9547fb3207e0 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Tue, 5 Nov 2019 10:31:35 +0000 Subject: [PATCH 05/23] lxd/storage/drivers/utils: Removes symlink removal from DeleteParentSnapshotDirIfEmpty Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/storage/drivers/utils.go | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/lxd/storage/drivers/utils.go b/lxd/storage/drivers/utils.go index 94715add21..ffc09539ed 100644 --- a/lxd/storage/drivers/utils.go +++ b/lxd/storage/drivers/utils.go @@ -215,16 +215,5 @@ func DeleteParentSnapshotDirIfEmpty(poolName string, volType VolumeType, volName } } - // If it no longer exists (may have just removed it), remove symlink. - if !shared.PathExists(snapshotsPath) { - snapshotSymlink := shared.VarPath("snapshots", volName) - if shared.PathExists(snapshotSymlink) { - err := os.Remove(snapshotSymlink) - if err != nil { - return err - } - } - } - return nil } From d9fed98fb7c2868025a9f3417dd35cddf72b6d48 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Tue, 5 Nov 2019 10:37:30 +0000 Subject: [PATCH 06/23] lxd/storage/backend/lxd: CreateInstance - Adds todo question regarding templating Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/storage/backend_lxd.go | 65 +++++++++++++++++++++++++++++++------- 1 file changed, 53 insertions(+), 12 deletions(-) diff --git a/lxd/storage/backend_lxd.go b/lxd/storage/backend_lxd.go index 9c1f4651e5..4547f7a886 100644 --- a/lxd/storage/backend_lxd.go +++ b/lxd/storage/backend_lxd.go @@ -161,18 +161,6 @@ func (b *lxdBackend) Unmount() (bool, error) { return b.driver.Unmount() } -func (b *lxdBackend) CreateInstance(inst Instance, op *operations.Operation) error { - return ErrNotImplemented -} - -func (b *lxdBackend) CreateInstanceFromBackup(inst Instance, sourcePath string, op *operations.Operation) error { - return ErrNotImplemented -} - -func (b *lxdBackend) CreateInstanceFromCopy(inst Instance, src Instance, snapshots bool, op *operations.Operation) error { - return ErrNotImplemented -} - // createInstanceSymlink creates a symlink in the instance directory to the instance's mount path. func (b *lxdBackend) createInstanceSymlink(inst Instance, mountPath string) error { symlinkPath := inst.Path() @@ -226,6 +214,56 @@ func (b *lxdBackend) createInstanceSnapshotSymlink(inst Instance, mountPath stri return nil } +// CreateInstance creates an empty instance. +func (b *lxdBackend) CreateInstance(inst Instance, op *operations.Operation) error { + logger := logging.AddContext(b.logger, log.Ctx{"project": inst.Project(), "instance": inst.Name()}) + logger.Debug("CreateInstance started") + defer logger.Debug("CreateInstance finished") + + volType, err := InstanceTypeToVolumeType(inst.Type()) + if err != nil { + return err + } + + revert := true + defer func() { + if !revert { + return + } + b.DeleteInstance(inst, op) + }() + + vol := b.newVolume(volType, drivers.ContentTypeFS, project.Prefix(inst.Project(), inst.Name()), nil) + err = b.driver.CreateVolume(vol, nil, op) + if err != nil { + return err + } + + err = b.createInstanceSymlink(inst, vol.MountPath()) + if err != nil { + return err + } + + // tomp TODO as this modifies the rootfs after being unpacked, it probably needs to run + // as part of the filler function above or perform a separate mount so that the rootfs is + // actually mounted (in the case of optimised images there is no filler function). + err = inst.TemplateApply("create") + if err != nil { + return err + } + + revert = false + return nil +} + +func (b *lxdBackend) CreateInstanceFromBackup(inst Instance, sourcePath string, op *operations.Operation) error { + return ErrNotImplemented +} + +func (b *lxdBackend) CreateInstanceFromCopy(inst Instance, src Instance, snapshots bool, op *operations.Operation) error { + return ErrNotImplemented +} + // imageFiller returns a function that can be used as a filler function with CreateVolume(). This // function will unpack the specified image archive into the specified mount path of the volume. func (b *lxdBackend) imageFiller(fingerprint string, op *operations.Operation) func(mountPath string) error { @@ -295,6 +333,9 @@ func (b *lxdBackend) CreateInstanceFromImage(inst Instance, fingerprint string, return err } + // tomp TODO as this modifies the rootfs after being unpacked, it probably needs to run + // as part of the filler function above or perform a separate mount so that the rootfs is + // actually mounted (in the case of optimised images there is no filler function). err = inst.TemplateApply("create") if err != nil { return err From 382a4dbc0e6f86a3908e8c7269adb3778923b967 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Tue, 5 Nov 2019 10:37:53 +0000 Subject: [PATCH 07/23] lxd/storage/backend/lxd: Updates instance snapshot symlink removal Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/storage/backend_lxd.go | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/lxd/storage/backend_lxd.go b/lxd/storage/backend_lxd.go index 4547f7a886..d43e8aaa46 100644 --- a/lxd/storage/backend_lxd.go +++ b/lxd/storage/backend_lxd.go @@ -396,12 +396,17 @@ func (b *lxdBackend) DeleteInstance(inst Instance, op *operations.Operation) err return err } - // Remove symlink. + // Remove symlinks. err = b.removeInstanceSymlink(inst) if err != nil { return err } + err = b.removeInstanceSnapshotSymlinkIfUnused(inst) + if err != nil { + return err + } + // Remove the volume record from the database. err = b.state.Cluster.StoragePoolVolumeDelete(inst.Project(), inst.Name(), volDBType, b.ID()) if err != nil { @@ -493,6 +498,12 @@ func (b *lxdBackend) DeleteInstanceSnapshot(inst Instance, op *operations.Operat return err } + // Delete symlink if needed. + err = b.removeInstanceSnapshotSymlinkIfUnused(inst) + if err != nil { + return err + } + // Remove the snapshot volume record from the database. err = b.state.Cluster.StoragePoolVolumeDelete(inst.Project(), drivers.GetSnapshotVolumeName(parentName, snapName), volDBType, b.ID()) if err != nil { From 1744771871756f3e4fdecefc161dee402106b0a0 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Tue, 5 Nov 2019 10:34:26 +0000 Subject: [PATCH 08/23] lxd/storage/backend/lxd: Updates instance snapshot symlink management functions Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/storage/backend_lxd.go | 43 ++++++++++++++++++++++++++++++++------ 1 file changed, 37 insertions(+), 6 deletions(-) diff --git a/lxd/storage/backend_lxd.go b/lxd/storage/backend_lxd.go index d43e8aaa46..167fb98084 100644 --- a/lxd/storage/backend_lxd.go +++ b/lxd/storage/backend_lxd.go @@ -187,16 +187,16 @@ func (b *lxdBackend) removeInstanceSymlink(inst Instance) error { return nil } -// createInstanceSnapshotSymlink creates a symlink in the snapshot directory to the instance's -// snapshot path. -func (b *lxdBackend) createInstanceSnapshotSymlink(inst Instance, mountPath string) error { +// ensureInstanceSnapshotSymlink creates a symlink in the snapshot directory to the instance's +// snapshot path if doesn't exist already. +func (b *lxdBackend) ensureInstanceSnapshotSymlink(inst Instance) error { // Check we can convert the instance to the volume types needed. volType, err := InstanceTypeToVolumeType(inst.Type()) if err != nil { return err } - snapshotMntPointSymlink := shared.VarPath("snapshots", project.Prefix(inst.Project(), inst.Name())) + snapshotSymlink := shared.VarPath("snapshots", project.Prefix(inst.Project(), inst.Name())) volStorageName := project.Prefix(inst.Project(), inst.Name()) snapshotTargetPath, err := drivers.GetVolumeSnapshotDir(b.name, volType, volStorageName) @@ -204,8 +204,8 @@ func (b *lxdBackend) createInstanceSnapshotSymlink(inst Instance, mountPath stri return err } - if !shared.PathExists(snapshotMntPointSymlink) { - err := os.Symlink(snapshotTargetPath, snapshotMntPointSymlink) + if !shared.PathExists(snapshotSymlink) { + err := os.Symlink(snapshotTargetPath, snapshotSymlink) if err != nil { return err } @@ -214,6 +214,37 @@ func (b *lxdBackend) createInstanceSnapshotSymlink(inst Instance, mountPath stri return nil } +// removeInstanceSnapshotSymlinkIfUnused removes the symlink in the snapshot directory to the +// instance's snapshot path if the snapshot path is missing. It is expected that the driver will +// remove the instance's snapshot path after the last snapshot is removed or the volume is deleted. +func (b *lxdBackend) removeInstanceSnapshotSymlinkIfUnused(inst Instance) error { + // Check we can convert the instance to the volume types needed. + volType, err := InstanceTypeToVolumeType(inst.Type()) + if err != nil { + return err + } + + snapshotSymlink := shared.VarPath("snapshots", project.Prefix(inst.Project(), inst.Name())) + volStorageName := project.Prefix(inst.Project(), inst.Name()) + + snapshotTargetPath, err := drivers.GetVolumeSnapshotDir(b.name, volType, volStorageName) + if err != nil { + return err + } + + // If snapshot parent directory doesn't exist, remove symlink. + if !shared.PathExists(snapshotTargetPath) { + if shared.PathExists(snapshotSymlink) { + err := os.Remove(snapshotSymlink) + if err != nil { + return err + } + } + } + + return nil +} + // CreateInstance creates an empty instance. func (b *lxdBackend) CreateInstance(inst Instance, op *operations.Operation) error { logger := logging.AddContext(b.logger, log.Ctx{"project": inst.Project(), "instance": inst.Name()}) From d1df84654a53ad2ba86823193198dd0be86468db Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Tue, 5 Nov 2019 11:18:01 +0000 Subject: [PATCH 09/23] lxd/storage/interfaces: Updates instance mount function definitions Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/storage/interfaces.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lxd/storage/interfaces.go b/lxd/storage/interfaces.go index 4e787f07bb..78527691df 100644 --- a/lxd/storage/interfaces.go +++ b/lxd/storage/interfaces.go @@ -55,8 +55,8 @@ type Pool interface { GetInstanceUsage(i Instance) (int64, error) SetInstanceQuota(i Instance, quota uint64) error - MountInstance(i Instance) (bool, error) - UnmountInstance(i Instance) (bool, error) + MountInstance(i Instance, op *operations.Operation) (bool, error) + UnmountInstance(i Instance, op *operations.Operation) (bool, error) GetInstanceDisk(i Instance) (string, string, error) // Instance snapshots. @@ -64,8 +64,8 @@ type Pool interface { RenameInstanceSnapshot(i Instance, newName string, op *operations.Operation) error DeleteInstanceSnapshot(i Instance, op *operations.Operation) error RestoreInstanceSnapshot(i Instance, op *operations.Operation) error - MountInstanceSnapshot(i Instance) (bool, error) - UnmountInstanceSnapshot(i Instance) (bool, error) + MountInstanceSnapshot(i Instance, op *operations.Operation) (bool, error) + UnmountInstanceSnapshot(i Instance, op *operations.Operation) (bool, error) // Images. EnsureImage(fingerprint string, op *operations.Operation) error From 820ae1dcc7d5fcc5555664b10ee1ca81abfd3735 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Tue, 5 Nov 2019 11:18:19 +0000 Subject: [PATCH 10/23] lxd/storage/backend/mock: Updates instance mount function definitions Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/storage/backend_mock.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lxd/storage/backend_mock.go b/lxd/storage/backend_mock.go index 9f20fc1b55..20ccd09129 100644 --- a/lxd/storage/backend_mock.go +++ b/lxd/storage/backend_mock.go @@ -106,11 +106,11 @@ func (b *mockBackend) SetInstanceQuota(i Instance, quota uint64) error { return nil } -func (b *mockBackend) MountInstance(i Instance) (bool, error) { +func (b *mockBackend) MountInstance(i Instance, op *operations.Operation) (bool, error) { return true, nil } -func (b *mockBackend) UnmountInstance(i Instance) (bool, error) { +func (b *mockBackend) UnmountInstance(i Instance, op *operations.Operation) (bool, error) { return true, nil } @@ -134,11 +134,11 @@ func (b *mockBackend) RestoreInstanceSnapshot(i Instance, op *operations.Operati return nil } -func (b *mockBackend) MountInstanceSnapshot(i Instance) (bool, error) { +func (b *mockBackend) MountInstanceSnapshot(i Instance, op *operations.Operation) (bool, error) { return true, nil } -func (b *mockBackend) UnmountInstanceSnapshot(i Instance) (bool, error) { +func (b *mockBackend) UnmountInstanceSnapshot(i Instance, op *operations.Operation) (bool, error) { return true, nil } From 73f0325c8c3f1125d3efd63e27ba2ee503ed8af8 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Tue, 5 Nov 2019 11:18:44 +0000 Subject: [PATCH 11/23] lxd/storage/backend/lxd: Implements instance mount and unmount functions Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/storage/backend_lxd.go | 87 ++++++++++++++++++++++++++++++++++---- 1 file changed, 79 insertions(+), 8 deletions(-) diff --git a/lxd/storage/backend_lxd.go b/lxd/storage/backend_lxd.go index 167fb98084..4f2e3c00ec 100644 --- a/lxd/storage/backend_lxd.go +++ b/lxd/storage/backend_lxd.go @@ -476,12 +476,40 @@ func (b *lxdBackend) SetInstanceQuota(inst Instance, quota uint64) error { return ErrNotImplemented } -func (b *lxdBackend) MountInstance(inst Instance) (bool, error) { - return true, ErrNotImplemented +// MountInstance mounts the instance's rootfs. +func (b *lxdBackend) MountInstance(inst Instance, op *operations.Operation) (bool, error) { + logger := logging.AddContext(b.logger, log.Ctx{"project": inst.Project(), "instance": inst.Name()}) + logger.Debug("MountInstance started") + defer logger.Debug("MountInstance finished") + + // Check we can convert the instance to the volume type needed. + volType, err := InstanceTypeToVolumeType(inst.Type()) + if err != nil { + return false, err + } + + // Get the volume name on storage. + volStorageName := project.Prefix(inst.Project(), inst.Name()) + + return b.driver.MountVolume(volType, volStorageName, op) } -func (b *lxdBackend) UnmountInstance(inst Instance) (bool, error) { - return true, ErrNotImplemented +// UnmountInstance unmounts the instance's rootfs. +func (b *lxdBackend) UnmountInstance(inst Instance, op *operations.Operation) (bool, error) { + logger := logging.AddContext(b.logger, log.Ctx{"project": inst.Project(), "instance": inst.Name()}) + logger.Debug("UnmountInstance started") + defer logger.Debug("UnmountInstance finished") + + // Check we can convert the instance to the volume type needed. + volType, err := InstanceTypeToVolumeType(inst.Type()) + if err != nil { + return false, err + } + + // Get the volume name on storage. + volStorageName := project.Prefix(inst.Project(), inst.Name()) + + return b.driver.UnmountVolume(volType, volStorageName, op) } func (b *lxdBackend) GetInstanceDisk(inst Instance) (string, string, error) { @@ -548,12 +576,55 @@ func (b *lxdBackend) RestoreInstanceSnapshot(inst Instance, op *operations.Opera return ErrNotImplemented } -func (b *lxdBackend) MountInstanceSnapshot(inst Instance) (bool, error) { - return true, ErrNotImplemented +// MountInstanceSnapshot mounts an instance snapshot. It is mounted as read only so that the +// snapshot cannot be modified. +func (b *lxdBackend) MountInstanceSnapshot(inst Instance, op *operations.Operation) (bool, error) { + logger := logging.AddContext(b.logger, log.Ctx{"project": inst.Project(), "instance": inst.Name()}) + logger.Debug("MountInstanceSnapshot started") + defer logger.Debug("MountInstanceSnapshot finished") + + if !inst.IsSnapshot() { + return false, fmt.Errorf("Instance must be a snapshot") + } + + // Check we can convert the instance to the volume type needed. + volType, err := InstanceTypeToVolumeType(inst.Type()) + if err != nil { + return false, err + } + + // Get the volume name on storage. + volStorageName := project.Prefix(inst.Project(), inst.Name()) + + // Get the snapshot name. + _, snapName, _ := shared.ContainerGetParentAndSnapshotName(inst.Name()) + + return b.driver.MountVolumeSnapshot(volType, volStorageName, snapName, op) } -func (b *lxdBackend) UnmountInstanceSnapshot(inst Instance) (bool, error) { - return true, ErrNotImplemented +// UnmountInstanceSnapshot unmounts an instance snapshot. +func (b *lxdBackend) UnmountInstanceSnapshot(inst Instance, op *operations.Operation) (bool, error) { + logger := logging.AddContext(b.logger, log.Ctx{"project": inst.Project(), "instance": inst.Name()}) + logger.Debug("UnmountInstanceSnapshot started") + defer logger.Debug("UnmountInstanceSnapshot finished") + + if !inst.IsSnapshot() { + return false, fmt.Errorf("Instance must be a snapshot") + } + + // Check we can convert the instance to the volume type needed. + volType, err := InstanceTypeToVolumeType(inst.Type()) + if err != nil { + return false, err + } + + // Get the volume name on storage. + volStorageName := project.Prefix(inst.Project(), inst.Name()) + + // Get the snapshot name. + _, snapName, _ := shared.ContainerGetParentAndSnapshotName(inst.Name()) + + return b.driver.UnmountVolumeSnapshot(volType, volStorageName, snapName, op) } // EnsureImage creates an optimized volume of the image if supported by the storage pool driver and From cb69b4bde8b2f6844657a6122678e29bd75f3a16 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Tue, 5 Nov 2019 11:42:09 +0000 Subject: [PATCH 12/23] lxd/storage/backend/lxd: Instance function comment consistency Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/storage/backend_lxd.go | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/lxd/storage/backend_lxd.go b/lxd/storage/backend_lxd.go index 4f2e3c00ec..bc2b2103bb 100644 --- a/lxd/storage/backend_lxd.go +++ b/lxd/storage/backend_lxd.go @@ -384,7 +384,7 @@ func (b *lxdBackend) RenameInstance(inst Instance, newName string, op *operation return ErrNotImplemented } -// DeleteInstance removes the Instance's root volume (all snapshots need to be removed first). +// DeleteInstance removes the instance's root volume (all snapshots need to be removed first). func (b *lxdBackend) DeleteInstance(inst Instance, op *operations.Operation) error { logger := logging.AddContext(b.logger, log.Ctx{"project": inst.Project(), "instance": inst.Name()}) logger.Debug("DeleteInstance started") @@ -459,7 +459,7 @@ func (b *lxdBackend) BackupInstance(inst Instance, targetPath string, optimized return ErrNotImplemented } -// GetInstanceUsage returns the disk usage of the Instance's root device. +// GetInstanceUsage returns the disk usage of the instance's root device. func (b *lxdBackend) GetInstanceUsage(inst Instance) (int64, error) { logger := logging.AddContext(b.logger, log.Ctx{"project": inst.Project(), "instance": inst.Name()}) logger.Debug("GetInstanceUsage started") @@ -473,10 +473,11 @@ func (b *lxdBackend) GetInstanceUsage(inst Instance) (int64, error) { } func (b *lxdBackend) SetInstanceQuota(inst Instance, quota uint64) error { + return ErrNotImplemented } -// MountInstance mounts the instance's rootfs. +// MountInstance mounts the instance's device. func (b *lxdBackend) MountInstance(inst Instance, op *operations.Operation) (bool, error) { logger := logging.AddContext(b.logger, log.Ctx{"project": inst.Project(), "instance": inst.Name()}) logger.Debug("MountInstance started") @@ -494,7 +495,7 @@ func (b *lxdBackend) MountInstance(inst Instance, op *operations.Operation) (boo return b.driver.MountVolume(volType, volStorageName, op) } -// UnmountInstance unmounts the instance's rootfs. +// UnmountInstance unmounts the instance's device. func (b *lxdBackend) UnmountInstance(inst Instance, op *operations.Operation) (bool, error) { logger := logging.AddContext(b.logger, log.Ctx{"project": inst.Project(), "instance": inst.Name()}) logger.Debug("UnmountInstance started") From ec70a0961943b0330f0386331b908d83eded9544 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Tue, 5 Nov 2019 13:13:34 +0000 Subject: [PATCH 13/23] lxd/device/device/utils/disk: Changes signature of StorageRootFSApplyQuota Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/device/device_utils_disk.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lxd/device/device_utils_disk.go b/lxd/device/device_utils_disk.go index c6545869fd..469f32ad54 100644 --- a/lxd/device/device_utils_disk.go +++ b/lxd/device/device_utils_disk.go @@ -17,7 +17,7 @@ var StorageVolumeMount func(s *state.State, poolName string, volumeName string, var StorageVolumeUmount func(s *state.State, poolName string, volumeName string, volumeType int) error // StorageRootFSApplyQuota applies a new quota. -var StorageRootFSApplyQuota func(instance Instance, newSize int64) (bool, error) +var StorageRootFSApplyQuota func(s *state.State, instance Instance, size string) error // BlockFsDetect detects the type of block device. func BlockFsDetect(dev string) (string, error) { From 12bcb26107633af1be943338ffc3c950cfae9aea Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Tue, 5 Nov 2019 13:14:27 +0000 Subject: [PATCH 14/23] lxd/device/disk: Updates applyQuota to use error from storage package Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/device/disk.go | 29 +++++++++-------------------- 1 file changed, 9 insertions(+), 20 deletions(-) diff --git a/lxd/device/disk.go b/lxd/device/disk.go index 853598006b..ee430b6718 100644 --- a/lxd/device/disk.go +++ b/lxd/device/disk.go @@ -15,6 +15,7 @@ import ( "github.com/lxc/lxd/lxd/db" deviceConfig "github.com/lxc/lxd/lxd/device/config" "github.com/lxc/lxd/lxd/instance/instancetype" + storagePools "github.com/lxc/lxd/lxd/storage" "github.com/lxc/lxd/lxd/util" "github.com/lxc/lxd/shared" "github.com/lxc/lxd/shared/logger" @@ -226,8 +227,8 @@ func (d *disk) Start() (*RunConfig, error) { // Handle previous requests for setting new quotas. if v["volatile.apply_quota"] != "" { - applied, err := d.applyQuota(v["volatile.apply_quota"]) - if err != nil || !applied { + err := d.applyQuota(v["volatile.apply_quota"]) + if err != nil { return nil, err } @@ -369,17 +370,15 @@ func (d *disk) Update(oldDevices deviceConfig.Devices, isRunning bool) error { // Apply disk quota changes. if newRootDiskDeviceSize != oldRootDiskDeviceSize { - applied, err := d.applyQuota(newRootDiskDeviceSize) - if err != nil { - return err - } - - if !applied { + err := d.applyQuota(newRootDiskDeviceSize) + if err == storagePools.ErrRunningQuotaResizeNotSupported { // Save volatile apply_quota key for next boot if cannot apply now. err = d.volatileSet(map[string]string{"volatile.apply_quota": newRootDiskDeviceSize}) if err != nil { return err } + } else if err != nil { + return err } } } @@ -401,18 +400,8 @@ func (d *disk) Update(oldDevices deviceConfig.Devices, isRunning bool) error { return nil } -func (d *disk) applyQuota(newSize string) (bool, error) { - newSizeBytes, err := units.ParseByteSizeString(newSize) - if err != nil { - return false, err - } - - applied, err := StorageRootFSApplyQuota(d.instance, newSizeBytes) - if err != nil { - return applied, err - } - - return applied, nil +func (d *disk) applyQuota(newSize string) error { + return StorageRootFSApplyQuota(d.state, d.instance, newSize) } // generateLimits adds a set of cgroup rules to apply specified limits to the supplied RunConfig. From 8c963d054585e56a207aa3b8943291999a3e9694 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Tue, 5 Nov 2019 13:14:57 +0000 Subject: [PATCH 15/23] lxd/storage: Links storageRootFSApplyQuota to new storage package Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/storage.go | 55 ++++++++++++++++++++++++++++++++------------------ 1 file changed, 35 insertions(+), 20 deletions(-) diff --git a/lxd/storage.go b/lxd/storage.go index eae87e50e4..6a3aa7cf7d 100644 --- a/lxd/storage.go +++ b/lxd/storage.go @@ -18,12 +18,14 @@ import ( "github.com/lxc/lxd/lxd/migration" "github.com/lxc/lxd/lxd/operations" "github.com/lxc/lxd/lxd/state" - driver "github.com/lxc/lxd/lxd/storage" + storagePools "github.com/lxc/lxd/lxd/storage" + storageDrivers "github.com/lxc/lxd/lxd/storage/drivers" "github.com/lxc/lxd/shared" "github.com/lxc/lxd/shared/api" "github.com/lxc/lxd/shared/idmap" "github.com/lxc/lxd/shared/ioprogress" "github.com/lxc/lxd/shared/logger" + "github.com/lxc/lxd/shared/units" "github.com/lxc/lxd/shared/version" ) @@ -480,7 +482,7 @@ func storagePoolVolumeAttachInit(s *state.State, poolName string, volumeName str poolVolumePut.Config["volatile.idmap.next"] = nextJsonMap // get mountpoint of storage volume - remapPath := driver.GetStoragePoolVolumeMountPoint(poolName, volumeName) + remapPath := storagePools.GetStoragePoolVolumeMountPoint(poolName, volumeName) if !nextIdmap.Equals(lastIdmap) { logger.Debugf("Shifting storage volume") @@ -840,7 +842,7 @@ func storageVolumeMount(state *state.State, poolName string, volumeName string, return fmt.Errorf("Received non-LXC container instance") } - volumeType, _ := driver.VolumeTypeNameToType(volumeTypeName) + volumeType, _ := storagePools.VolumeTypeNameToType(volumeTypeName) s, err := storagePoolVolumeAttachInit(state, poolName, volumeName, volumeType, c) if err != nil { return err @@ -872,29 +874,42 @@ func storageVolumeUmount(state *state.State, poolName string, volumeName string, // storageRootFSApplyQuota applies a quota to an instance if it can, if it cannot then it will // return false indicating that the quota needs to be stored in volatile to be applied on next boot. -func storageRootFSApplyQuota(instance device.Instance, newSizeBytes int64) (bool, error) { - c, ok := instance.(*containerLXC) +func storageRootFSApplyQuota(state *state.State, inst device.Instance, size string) error { + c, ok := inst.(*containerLXC) if !ok { - return false, fmt.Errorf("Received non-LXC container instance") + return fmt.Errorf("Received non-LXC container instance") } - err := c.initStorage() - if err != nil { - return false, errors.Wrap(err, "Initialize storage") - } + pool, err := storagePools.GetPoolByInstance(state, c) + if err != storageDrivers.ErrUnknownDriver && err != storageDrivers.ErrNotImplemented { + err = pool.SetInstanceQuota(c, size, nil) + if err != nil { + return err + } + } else { + err := c.initStorage() + if err != nil { + return errors.Wrap(err, "Initialize storage") + } - storageTypeName := c.storage.GetStorageTypeName() - storageIsReady := c.storage.ContainerStorageReady(c) + storageTypeName := c.storage.GetStorageTypeName() + storageIsReady := c.storage.ContainerStorageReady(c) - // If we cannot apply the quota now, then return false as needs to be applied on next boot. - if (storageTypeName == "lvm" || storageTypeName == "ceph") && c.IsRunning() || !storageIsReady { - return false, nil - } + // If we cannot apply the quota now, then return false as needs to be applied on next boot. + if (storageTypeName == "lvm" || storageTypeName == "ceph") && c.IsRunning() || !storageIsReady { + return storagePools.ErrRunningQuotaResizeNotSupported + } - err = c.storage.StorageEntitySetQuota(storagePoolVolumeTypeContainer, newSizeBytes, c) - if err != nil { - return false, errors.Wrap(err, "Set storage quota") + newSizeBytes, err := units.ParseByteSizeString(size) + if err != nil { + return err + } + + err = c.storage.StorageEntitySetQuota(storagePoolVolumeTypeContainer, newSizeBytes, c) + if err != nil { + return errors.Wrap(err, "Set storage quota") + } } - return true, nil + return nil } From 2a0182cc3044cdabde58c75902686f42d4c7f8d8 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Tue, 5 Nov 2019 13:15:20 +0000 Subject: [PATCH 16/23] lxd/storage/backend/lxd: SetInstanceQuota Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/storage/backend_lxd.go | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/lxd/storage/backend_lxd.go b/lxd/storage/backend_lxd.go index bc2b2103bb..18d7a82718 100644 --- a/lxd/storage/backend_lxd.go +++ b/lxd/storage/backend_lxd.go @@ -190,7 +190,7 @@ func (b *lxdBackend) removeInstanceSymlink(inst Instance) error { // ensureInstanceSnapshotSymlink creates a symlink in the snapshot directory to the instance's // snapshot path if doesn't exist already. func (b *lxdBackend) ensureInstanceSnapshotSymlink(inst Instance) error { - // Check we can convert the instance to the volume types needed. + // Check we can convert the instance to the volume type needed. volType, err := InstanceTypeToVolumeType(inst.Type()) if err != nil { return err @@ -218,7 +218,7 @@ func (b *lxdBackend) ensureInstanceSnapshotSymlink(inst Instance) error { // instance's snapshot path if the snapshot path is missing. It is expected that the driver will // remove the instance's snapshot path after the last snapshot is removed or the volume is deleted. func (b *lxdBackend) removeInstanceSnapshotSymlinkIfUnused(inst Instance) error { - // Check we can convert the instance to the volume types needed. + // Check we can convert the instance to the volume type needed. volType, err := InstanceTypeToVolumeType(inst.Type()) if err != nil { return err @@ -472,9 +472,28 @@ func (b *lxdBackend) GetInstanceUsage(inst Instance) (int64, error) { return -1, ErrNotImplemented } -func (b *lxdBackend) SetInstanceQuota(inst Instance, quota uint64) error { +// SetInstanceQuota sets the quota on the instance's root device. +// Returns ErrRunningQuotaResizeNotSupported if the instance is running and the storage driver +// doesn't support resizing whilst the instance is running. +func (b *lxdBackend) SetInstanceQuota(inst Instance, size string, op *operations.Operation) error { + logger := logging.AddContext(b.logger, log.Ctx{"project": inst.Project(), "instance": inst.Name()}) + logger.Debug("SetInstanceQuota started") + defer logger.Debug("SetInstanceQuota finished") - return ErrNotImplemented + if inst.IsRunning() && !b.driver.Info().RunningQuotaResize { + return ErrRunningQuotaResizeNotSupported + } + + // Check we can convert the instance to the volume type needed. + volType, err := InstanceTypeToVolumeType(inst.Type()) + if err != nil { + return err + } + + // Get the volume name on storage. + volStorageName := project.Prefix(inst.Project(), inst.Name()) + + return b.driver.SetVolumeQuota(volType, volStorageName, size, op) } // MountInstance mounts the instance's device. From 8ab79c017d1d00759a0cfcb5cc840ba4caacbd1a Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Tue, 5 Nov 2019 13:15:37 +0000 Subject: [PATCH 17/23] lxd/storage/backend/mock: SetInstanceQuota Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/storage/backend_mock.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lxd/storage/backend_mock.go b/lxd/storage/backend_mock.go index 20ccd09129..a0ddb34707 100644 --- a/lxd/storage/backend_mock.go +++ b/lxd/storage/backend_mock.go @@ -102,7 +102,7 @@ func (b *mockBackend) GetInstanceUsage(i Instance) (int64, error) { return 0, nil } -func (b *mockBackend) SetInstanceQuota(i Instance, quota uint64) error { +func (b *mockBackend) SetInstanceQuota(i Instance, size string, op *operations.Operation) error { return nil } From 888b1112ae50193275cf857b0c0740b8b498307e Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Tue, 5 Nov 2019 13:16:04 +0000 Subject: [PATCH 18/23] lxd/storage/drivers/dir: Adds SetVolumeQuota and RunningQuotaResize info flag Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/storage/drivers/driver_dir.go | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/lxd/storage/drivers/driver_dir.go b/lxd/storage/drivers/driver_dir.go index d95bc00f1a..ac24101ce7 100644 --- a/lxd/storage/drivers/driver_dir.go +++ b/lxd/storage/drivers/driver_dir.go @@ -27,14 +27,15 @@ type dir struct { // Info returns info about the driver and its environment. func (d *dir) Info() Info { return Info{ - Name: "dir", - Version: "1", - OptimizedImages: false, - PreservesInodes: false, - Usable: true, - Remote: false, - VolumeTypes: []VolumeType{VolumeTypeCustom, VolumeTypeImage, VolumeTypeContainer}, - BlockBacking: false, + Name: "dir", + Version: "1", + OptimizedImages: false, + PreservesInodes: false, + Usable: true, + Remote: false, + VolumeTypes: []VolumeType{VolumeTypeCustom, VolumeTypeImage, VolumeTypeContainer}, + BlockBacking: false, + RunningQuotaResize: true, } } @@ -659,6 +660,17 @@ func (d *dir) UnmountVolumeSnapshot(volType VolumeType, volName, snapshotName st return forceUnmount(snapPath) } +// SetVolumeQuota sets the quota on the volume. +func (d *dir) SetVolumeQuota(volType VolumeType, volName, size string, op *operations.Operation) error { + volPath := GetVolumeMountPath(d.name, volType, volName) + volID, err := d.getVolID(volType, volName) + if err != nil { + return err + } + + return d.setQuota(volPath, volID, size) +} + // quotaProjectID generates a project quota ID from a volume ID. func (d *dir) quotaProjectID(volID int64) uint32 { return uint32(volID + 10000) From 58d9bb11619ac3d87e9bd15bab9755ef689d5748 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Tue, 5 Nov 2019 13:16:31 +0000 Subject: [PATCH 19/23] lxd/storage/drivers/interface: SetVolumeQuota signature Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/storage/drivers/interface.go | 1 + 1 file changed, 1 insertion(+) diff --git a/lxd/storage/drivers/interface.go b/lxd/storage/drivers/interface.go index 50bab56cb3..ed5a066a74 100644 --- a/lxd/storage/drivers/interface.go +++ b/lxd/storage/drivers/interface.go @@ -38,6 +38,7 @@ type Driver interface { RenameVolume(volType VolumeType, volName string, newName string, op *operations.Operation) error UpdateVolume(vol Volume, changedConfig map[string]string) error GetVolumeUsage(volType VolumeType, volName string) (int64, error) + SetVolumeQuota(volType VolumeType, volName, size string, op *operations.Operation) error // MountVolume mounts a storage volume, returns true if we caused a new mount, false if // already mounted. From e85ac5c893e1cc0a4344bc38ece8a410ba8c74f2 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Tue, 5 Nov 2019 13:16:45 +0000 Subject: [PATCH 20/23] lxd/storage/drivers/load: Adds RunningQuotaResize to driver Info struct Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/storage/drivers/load.go | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/lxd/storage/drivers/load.go b/lxd/storage/drivers/load.go index c3ebfed335..f5732767cd 100644 --- a/lxd/storage/drivers/load.go +++ b/lxd/storage/drivers/load.go @@ -25,14 +25,15 @@ func Load(state *state.State, driverName string, name string, config map[string] // Info represents information about a storage driver. type Info struct { - Name string - Version string - Usable bool - Remote bool - OptimizedImages bool - PreservesInodes bool - VolumeTypes []VolumeType - BlockBacking bool + Name string + Version string + Usable bool + Remote bool + OptimizedImages bool + PreservesInodes bool + VolumeTypes []VolumeType + BlockBacking bool + RunningQuotaResize bool } // SupportedDrivers returns a list of supported storage drivers. From fc2678e971621b85f0708161618ae4f96cad94d0 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Tue, 5 Nov 2019 13:17:02 +0000 Subject: [PATCH 21/23] lxd/storage/errors: Adds ErrRunningQuotaResizeNotSupported error Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/storage/errors.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lxd/storage/errors.go b/lxd/storage/errors.go index efbe5c6c75..64df5f1579 100644 --- a/lxd/storage/errors.go +++ b/lxd/storage/errors.go @@ -9,3 +9,6 @@ var ErrNilValue = fmt.Errorf("Nil value provided") // ErrNotImplemented is the "Not implemented" error var ErrNotImplemented = fmt.Errorf("Not implemented") + +// ErrRunningQuotaResizeNotSupported is the "Running quota resize not supported" error. +var ErrRunningQuotaResizeNotSupported = fmt.Errorf("Running quota resize not supported") From 3749799782ed92260a6f1b39f4488aa1c9cec39f Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Tue, 5 Nov 2019 13:17:20 +0000 Subject: [PATCH 22/23] lxd/storage/interfaces: SetInstanceQuota signature Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/storage/interfaces.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lxd/storage/interfaces.go b/lxd/storage/interfaces.go index 78527691df..87c9bb02e6 100644 --- a/lxd/storage/interfaces.go +++ b/lxd/storage/interfaces.go @@ -53,7 +53,7 @@ type Pool interface { BackupInstance(i Instance, targetPath string, optimized bool, snapshots bool, op *operations.Operation) error GetInstanceUsage(i Instance) (int64, error) - SetInstanceQuota(i Instance, quota uint64) error + SetInstanceQuota(i Instance, size string, op *operations.Operation) error MountInstance(i Instance, op *operations.Operation) (bool, error) UnmountInstance(i Instance, op *operations.Operation) (bool, error) From 94def6ac2726f110e18661f32cd4d3e9d606c69c Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Tue, 5 Nov 2019 13:49:07 +0000 Subject: [PATCH 23/23] lxd/container: Links containerConfigureInternal to new storage package Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/container.go | 92 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 61 insertions(+), 31 deletions(-) diff --git a/lxd/container.go b/lxd/container.go index 422ec47da8..41b94c9f85 100644 --- a/lxd/container.go +++ b/lxd/container.go @@ -286,7 +286,7 @@ func containerCreateAsEmpty(d *Daemon, args db.InstanceArgs) (container, error) } // Apply any post-storage configuration. - err = containerConfigureInternal(c) + err = containerConfigureInternal(d.State(), c) if err != nil { c.Delete() return nil, err @@ -521,7 +521,7 @@ func containerCreateFromImage(d *Daemon, args db.InstanceArgs, hash string, op * } // Apply any post-storage configuration. - err = containerConfigureInternal(c) + err = containerConfigureInternal(d.State(), c) if err != nil { c.Delete() return nil, errors.Wrap(err, "Configure container") @@ -673,7 +673,7 @@ func containerCreateAsCopy(s *state.State, args db.InstanceArgs, sourceContainer } // Apply any post-storage configuration. - err = containerConfigureInternal(ct) + err = containerConfigureInternal(s, ct) if err != nil { if !refresh { ct.Delete() @@ -685,7 +685,7 @@ func containerCreateAsCopy(s *state.State, args db.InstanceArgs, sourceContainer if !containerOnly { for _, cs := range csList { // Apply any post-storage configuration. - err = containerConfigureInternal(*cs) + err = containerConfigureInternal(s, *cs) if err != nil { if !refresh { ct.Delete() @@ -994,47 +994,77 @@ func containerCreateInternal(s *state.State, args db.InstanceArgs) (container, e return c, nil } -func containerConfigureInternal(c Instance) error { +func containerConfigureInternal(state *state.State, c Instance) error { // Find the root device _, rootDiskDevice, err := shared.GetRootDiskDevice(c.ExpandedDevices().CloneNative()) if err != nil { return err } - ourStart, err := c.StorageStart() - if err != nil { - return err - } + // Check if we can load new storage layer for pool driver type. + pool, err := storagePools.GetPoolByInstance(state, c) + if err != storageDrivers.ErrUnknownDriver && err != storageDrivers.ErrNotImplemented { + if err != nil { + return errors.Wrap(err, "Load instance storage pool") + } - // handle quota: at this point, storage is guaranteed to be ready - storage := c.Storage() - if rootDiskDevice["size"] != "" { - storageTypeName := storage.GetStorageTypeName() - if (storageTypeName == "lvm" || storageTypeName == "ceph") && c.IsRunning() { - err = c.VolatileSet(map[string]string{"volatile.apply_quota": rootDiskDevice["size"]}) - if err != nil { - return err - } - } else { - size, err := units.ParseByteSizeString(rootDiskDevice["size"]) - if err != nil { + if rootDiskDevice["size"] != "" { + err = pool.SetInstanceQuota(c, rootDiskDevice["size"], nil) + + // If the storage driver can't set the quota now, store in volatile. + if err == storagePools.ErrRunningQuotaResizeNotSupported { + err = c.VolatileSet(map[string]string{"volatile.apply_quota": rootDiskDevice["size"]}) + if err != nil { + return err + } + } else if err != nil { return err } + } - err = storage.StorageEntitySetQuota(storagePoolVolumeTypeContainer, size, c) - if err != nil { - return err + // tomp TODO this likely needs to mount the volume first. + err = writeBackupFile(c) + if err != nil { + return err + } + } else if c.Type() == instancetype.Container { + ourStart, err := c.StorageStart() + if err != nil { + return err + } + + // handle quota: at this point, storage is guaranteed to be ready + storage := c.Storage() + if rootDiskDevice["size"] != "" { + storageTypeName := storage.GetStorageTypeName() + if (storageTypeName == "lvm" || storageTypeName == "ceph") && c.IsRunning() { + err = c.VolatileSet(map[string]string{"volatile.apply_quota": rootDiskDevice["size"]}) + if err != nil { + return err + } + } else { + size, err := units.ParseByteSizeString(rootDiskDevice["size"]) + if err != nil { + return err + } + + err = storage.StorageEntitySetQuota(storagePoolVolumeTypeContainer, size, c) + if err != nil { + return err + } } } - } - if ourStart { - defer c.StorageStop() - } + if ourStart { + defer c.StorageStop() + } - err = writeBackupFile(c) - if err != nil { - return err + err = writeBackupFile(c) + if err != nil { + return err + } + } else { + return fmt.Errorf("Instance type not supported") } return nil
_______________________________________________ lxc-devel mailing list lxc-devel@lists.linuxcontainers.org http://lists.linuxcontainers.org/listinfo/lxc-devel