[lxc-devel] [lxd/master] Storage Instance Quota
tomponline on Github
lxc-bot at linuxcontainers.org
Tue Nov 5 13:50:28 UTC 2019
A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 346 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20191105/784dd799/attachment-0001.bin>
-------------- next part --------------
From e662852c556886462d4712d4aafff4819daa258c Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at 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.parrott at 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.parrott at 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.parrott at 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.parrott at 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.parrott at 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.parrott at 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.parrott at 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.parrott at 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.parrott at 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.parrott at 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.parrott at 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.parrott at 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.parrott at 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.parrott at 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.parrott at 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.parrott at 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.parrott at 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.parrott at 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.parrott at 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.parrott at 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.parrott at 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.parrott at 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.parrott at 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.parrott at 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.parrott at 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.parrott at 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.parrott at 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.parrott at 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.parrott at 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.parrott at 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.parrott at 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.parrott at 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.parrott at 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.parrott at 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.parrott at 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.parrott at 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.parrott at 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.parrott at 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.parrott at 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.parrott at 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.parrott at 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.parrott at 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.parrott at 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.parrott at 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.parrott at 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
More information about the lxc-devel
mailing list