[lxc-devel] [lxd/master] zfs: enable volume.size property

brauner on Github lxc-bot at linuxcontainers.org
Tue Aug 22 14:44:08 UTC 2017


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 364 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20170822/b9577878/attachment.bin>
-------------- next part --------------
From 0e6f72aced5a18d7e90a520d76e33425eb41c6fd Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Tue, 22 Aug 2017 16:37:19 +0200
Subject: [PATCH 1/2] zfs: apply quota on container creation

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 lxd/storage_zfs.go | 26 ++++++++++++++++++++++++++
 1 file changed, 26 insertions(+)

diff --git a/lxd/storage_zfs.go b/lxd/storage_zfs.go
index 61b829e96..de61d6c43 100644
--- a/lxd/storage_zfs.go
+++ b/lxd/storage_zfs.go
@@ -760,6 +760,19 @@ func (s *storageZfs) ContainerCreate(container container) error {
 		defer s.ContainerUmount(containerName, containerPath)
 	}
 
+	// apply quota
+	if s.volume.Config["size"] != "" {
+		size, err := shared.ParseByteSizeString(s.volume.Config["size"])
+		if err != nil {
+			return err
+		}
+
+		err = s.StorageEntitySetQuota(storagePoolVolumeTypeContainer, size, container)
+		if err != nil {
+			return err
+		}
+	}
+
 	err = createContainerMountpoint(containerPoolVolumeMntPoint, containerPath, container.IsPrivileged())
 	if err != nil {
 		return err
@@ -836,6 +849,19 @@ func (s *storageZfs) ContainerCreateFromImage(container container, fingerprint s
 		defer s.ContainerUmount(containerName, containerPath)
 	}
 
+	// apply quota
+	if s.volume.Config["size"] != "" {
+		size, err := shared.ParseByteSizeString(s.volume.Config["size"])
+		if err != nil {
+			return err
+		}
+
+		err = s.StorageEntitySetQuota(storagePoolVolumeTypeContainer, size, container)
+		if err != nil {
+			return err
+		}
+	}
+
 	privileged := container.IsPrivileged()
 	err = createContainerMountpoint(containerPoolVolumeMntPoint, containerPath, privileged)
 	if err != nil {

From 14b57e8bb3441abeb8d62e00eeb412e7d55e7b7f Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Tue, 22 Aug 2017 16:37:38 +0200
Subject: [PATCH 2/2] zfs: allow to change "volume.size" property

The logic here is:
- Profile beats Pool:
  If the container has a "size" property set on a root disk device it has in
  its local devices or inherits from a profile then the "volume.size" property
  from the pool will not be applied.
- Volume beats Pool:
  If the storage volume has a "size" property applied then the "volume.size"
  property from the pool will not be applied.

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 lxd/container.go              |  4 +--
 lxd/storage_pools_config.go   |  8 ++++-
 lxd/storage_volumes_config.go |  5 ++++
 lxd/storage_zfs.go            | 68 ++++++++++++++++++++++++++++++++++++++++++-
 4 files changed, 81 insertions(+), 4 deletions(-)

diff --git a/lxd/container.go b/lxd/container.go
index 39be1d83f..426e41d2c 100644
--- a/lxd/container.go
+++ b/lxd/container.go
@@ -488,9 +488,9 @@ type container interface {
 
 	StoragePool() (string, error)
 
-	// FIXME: Those should be internal functions
-	// Needed for migration for now.
 	StorageStart() (bool, error)
+	// Kill this function as soon as zfs is fixed.
+	StorageStartSensitive() (bool, error)
 	StorageStop() (bool, error)
 	Storage() storage
 	IdmapSet() (*shared.IdmapSet, error)
diff --git a/lxd/storage_pools_config.go b/lxd/storage_pools_config.go
index cc429186a..785e28942 100644
--- a/lxd/storage_pools_config.go
+++ b/lxd/storage_pools_config.go
@@ -122,7 +122,13 @@ func storagePoolValidateConfig(name string, driver string, config map[string]str
 		}
 
 		if driver != "lvm" && driver != "ceph" {
-			if prfx(key, "lvm.") || prfx(key, "volume.block.") || key == "volume.size" {
+			if prfx(key, "lvm.") || prfx(key, "volume.block.") {
+				return fmt.Errorf("the key %s cannot be used with %s storage pools", key, strings.ToUpper(driver))
+			}
+		}
+
+		if driver != "lvm" && driver != "ceph" && driver != "zfs" {
+			if key == "volume.size" {
 				return fmt.Errorf("the key %s cannot be used with %s storage pools", key, strings.ToUpper(driver))
 			}
 		}
diff --git a/lxd/storage_volumes_config.go b/lxd/storage_volumes_config.go
index 37ac53877..9e94083e4 100644
--- a/lxd/storage_volumes_config.go
+++ b/lxd/storage_volumes_config.go
@@ -103,6 +103,11 @@ func storageVolumeFillDefault(name string, config map[string]string, parentPool
 			config["size"] = "10GB"
 		}
 	} else {
+		// Does the pool request a default size for new storage volumes?
+		if config["size"] == "0" || config["size"] == "" {
+			config["size"] = parentPool.Config["volume.size"]
+		}
+
 		if config["size"] != "" {
 			_, err := shared.ParseByteSizeString(config["size"])
 			if err != nil {
diff --git a/lxd/storage_zfs.go b/lxd/storage_zfs.go
index de61d6c43..4ccb99f48 100644
--- a/lxd/storage_zfs.go
+++ b/lxd/storage_zfs.go
@@ -547,7 +547,73 @@ func (s *storageZfs) StoragePoolUpdate(writable *api.StoragePoolPut, changedConf
 	}
 
 	if shared.StringInSlice("volume.size", changedConfig) {
-		return fmt.Errorf("the \"volume.size\" property cannot be changed")
+		volumes, err := db.StoragePoolVolumesGet(s.d.db, s.poolID,
+			[]int{storagePoolVolumeTypeContainer})
+		if err != nil {
+			if err != db.NoSuchObjectError {
+				return err
+			}
+		}
+
+		// The name of a container is always identical to the name of
+		// its storage volume.
+		for _, volume := range volumes {
+			ct, err := containerLoadByName(s.d, volume.Name)
+			if err != nil {
+				return err
+			}
+
+			// Quota do not apply to snapshots (I *think*.)
+			if ct.IsSnapshot() {
+				continue
+			}
+
+			// Check if the storage volume itself already has local
+			// "size" property set.
+			if volume.Config["size"] != "" {
+				continue
+			}
+
+			// Check if the container has a "size" property set on
+			// its root disk device in its local devices.
+			localDevices := ct.LocalDevices()
+			_, rootDiskDevice, _ := containerGetRootDiskDevice(localDevices)
+			// Check if the container inherits a "size" property
+			// from a root disk device in one of its profiles.
+			if rootDiskDevice["size"] == "" {
+				expandedDevices := ct.ExpandedDevices()
+				_, rootDiskDevice, _ = containerGetRootDiskDevice(expandedDevices)
+			}
+
+			// Non-storage pool "size" properties override storage
+			// pool "size" properties
+			if rootDiskDevice["size"] != "" {
+				continue
+			}
+
+			ourStart, err := ct.StorageStartSensitive()
+			if err != nil {
+				return err
+			}
+			if ourStart {
+				defer ct.StorageStop()
+			}
+
+			size := int64(0)
+			if writable.Config["volume.size"] != "" {
+				size, err = shared.ParseByteSizeString(writable.Config["volume.size"])
+				if err != nil {
+					return err
+				}
+			}
+
+			st := ct.Storage()
+			err = st.StorageEntitySetQuota(storagePoolVolumeTypeContainer,
+				size, ct)
+			if err != nil {
+				return err
+			}
+		}
 	}
 
 	if shared.StringInSlice("volume.block.mount_options", changedConfig) {


More information about the lxc-devel mailing list