[lxc-devel] [lxd/master] Support disk limits in projects

freeekanayaka on Github lxc-bot at linuxcontainers.org
Tue Jul 14 12:48:12 UTC 2020


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 301 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20200714/7725da7f/attachment.bin>
-------------- next part --------------
From 5b5df83d8b462d077436daba1757d345ac8d26a3 Mon Sep 17 00:00:00 2001
From: Free Ekanayaka <free.ekanayaka at canonical.com>
Date: Tue, 14 Jul 2020 10:56:28 +0200
Subject: [PATCH 1/6] lxd/db: Drive-by removal of leftover fmt.Printf's

Signed-off-by: Free Ekanayaka <free.ekanayaka at canonical.com>
---
 lxd/db/node.go | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/lxd/db/node.go b/lxd/db/node.go
index 51628cad1c..ceb2ee2b8c 100644
--- a/lxd/db/node.go
+++ b/lxd/db/node.go
@@ -786,16 +786,13 @@ func (c *ClusterTx) GetNodeWithLeastInstances(archs []int) (string, error) {
 			supported = append(supported, personalities...)
 
 			match := false
-			fmt.Printf("stgraber: supported=%v requested=%v\n", supported, archs)
 			for _, entry := range supported {
 				if shared.IntInSlice(entry, archs) {
-					fmt.Printf("stgraber: supported\n")
 					match = true
 				}
 			}
 
 			if !match {
-				fmt.Printf("stgraber: unsupported\n")
 				continue
 			}
 		}

From 22fae6f11d9248c8b54dfc2150b18df39caf2d5a Mon Sep 17 00:00:00 2001
From: Free Ekanayaka <free.ekanayaka at canonical.com>
Date: Tue, 14 Jul 2020 12:29:38 +0200
Subject: [PATCH 2/6] shared/version: Add projects_limits_disk extension

Signed-off-by: Free Ekanayaka <free.ekanayaka at canonical.com>
---
 doc/api-extensions.md | 5 +++++
 shared/version/api.go | 1 +
 2 files changed, 6 insertions(+)

diff --git a/doc/api-extensions.md b/doc/api-extensions.md
index 1a2b81ed67..5a568ee74a 100644
--- a/doc/api-extensions.md
+++ b/doc/api-extensions.md
@@ -1118,3 +1118,8 @@ be set to `console` (default) or `vga` (the new type added by this extension).
 When POST'ing to `/1.0/<instance name>/console?type=vga` the data websocket
 returned by the operation in the metadata field will be a bidirectional proxy
 attached to a SPICE unix socket of the target virtual machine.
+
+## projects\_limits\_disk
+Add `limits.disk` to the available project configuration keys. If set, it limits
+the total amount of disk space that instances volumes, custom volumes and images
+volumes can use in the project.
diff --git a/shared/version/api.go b/shared/version/api.go
index 8fb696c459..43931942bc 100644
--- a/shared/version/api.go
+++ b/shared/version/api.go
@@ -219,6 +219,7 @@ var APIExtensions = []string{
 	"clustering_failure_domains",
 	"resources_gpu_mdev",
 	"console_vga_type",
+	"projects_limits_disk",
 }
 
 // APIExtensionsCount returns the number of available API extensions.

From f3cdbb42f009e1b81aa68aede01afc3e6cf14150 Mon Sep 17 00:00:00 2001
From: Free Ekanayaka <free.ekanayaka at canonical.com>
Date: Tue, 14 Jul 2020 12:38:45 +0200
Subject: [PATCH 3/6] doc: Document limits.disk project configuration key

Signed-off-by: Free Ekanayaka <free.ekanayaka at canonical.com>
---
 doc/projects.md | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/doc/projects.md b/doc/projects.md
index 18f225728b..882592db65 100644
--- a/doc/projects.md
+++ b/doc/projects.md
@@ -23,7 +23,8 @@ features.storage.volumes             | boolean   | -                     | true
 limits.containers                    | integer   | -                     | -                         | Maximum number of containers that can be created in the project
 limits.virtual-machines              | integer   | -                     | -                         | Maximum number of VMs that can be created in the project
 limits.cpu                           | integer   | -                     | -                         | Maximum value for the sum of individual "limits.cpu" configs set on the instances of the project
-limits.memory                        | integer   | -                     | -                         | Maximum value for the sum of individual "limits.memory" configs set on the instances of the project
+limits.disk                          | string    | -                     | -                         | Maximum value for the sum of individual "limits.memory" configs set on the instances of the project
+limits.memory                        | string    | -                     | -                         | Maximum value of aggregate disk space used by all instances volumes, custom volumes and images of the project
 limits.processes                     | integer   | -                     | -                         | Maximum value for the sum of individual "limits.processes" configs set on the instances of the project
 restricted                           | boolean   | -                     | true                      | Block access to security-sensitive features
 restricted.containers.nesting        | string    | -                     | block                     | Prevents setting security.nesting=true.

From a8efb7fc1698c916d42b39f0b9b2f81b7b064caf Mon Sep 17 00:00:00 2001
From: Free Ekanayaka <free.ekanayaka at canonical.com>
Date: Tue, 14 Jul 2020 12:39:17 +0200
Subject: [PATCH 4/6] lxd: Add "limits.disk" to supported project config keys

Signed-off-by: Free Ekanayaka <free.ekanayaka at canonical.com>
---
 lxd/api_project.go | 1 +
 1 file changed, 1 insertion(+)

diff --git a/lxd/api_project.go b/lxd/api_project.go
index 5a95f71ab5..4e336fd7ed 100644
--- a/lxd/api_project.go
+++ b/lxd/api_project.go
@@ -530,6 +530,7 @@ var projectConfigKeys = map[string]func(value string) error{
 	"limits.memory":                  shared.IsSize,
 	"limits.processes":               shared.IsUint32,
 	"limits.cpu":                     shared.IsUint32,
+	"limits.disk":                    shared.IsSize,
 	"restricted":                     shared.IsBool,
 	"restricted.containers.nesting":  isEitherAllowOrBlock,
 	"restricted.containers.lowlevel": isEitherAllowOrBlock,

From e35dd7ccb1559ed9569fb249037ddf33e4195d9f Mon Sep 17 00:00:00 2001
From: Free Ekanayaka <free.ekanayaka at canonical.com>
Date: Tue, 14 Jul 2020 14:45:38 +0200
Subject: [PATCH 5/6] lxd/project: Check that root disk sizes are within
 limits.disk

Signed-off-by: Free Ekanayaka <free.ekanayaka at canonical.com>
---
 lxd/project/permissions.go | 38 +++++++++++++++++++++++++++++++++-----
 1 file changed, 33 insertions(+), 5 deletions(-)

diff --git a/lxd/project/permissions.go b/lxd/project/permissions.go
index dbc5ce801d..30402a5d0e 100644
--- a/lxd/project/permissions.go
+++ b/lxd/project/permissions.go
@@ -418,6 +418,7 @@ func checkRestrictions(project *api.Project, instances []db.Instance, profiles [
 
 var allAggregateLimits = []string{
 	"limits.cpu",
+	"limits.disk",
 	"limits.memory",
 	"limits.processes",
 }
@@ -599,6 +600,8 @@ func AllowProjectUpdate(tx *db.ClusterTx, projectName string, config map[string]
 		case "limits.cpu":
 			fallthrough
 		case "limits.memory":
+			fallthrough
+		case "limits.disk":
 			aggregateKeys = append(aggregateKeys, key)
 
 		}
@@ -785,11 +788,30 @@ func getInstanceLimits(instance db.Instance, keys []string) (map[string]int64, e
 	limits := map[string]int64{}
 
 	for _, key := range keys {
-		value, ok := instance.Config[key]
-		if !ok || value == "" {
-			return nil, fmt.Errorf(
-				"Instance %s in project %s has no '%s' config, either directly or via a profile",
-				instance.Name, instance.Project, key)
+		var value string
+		var ok bool
+		if key == "limits.disk" {
+			_, device, err := shared.GetRootDiskDevice(instance.Devices)
+			if err != nil {
+				return nil, fmt.Errorf(
+					"Instance %s in project %s has no root device",
+					instance.Name, instance.Project)
+			}
+			value, ok = device["size"]
+			if !ok || value == "" {
+				return nil, fmt.Errorf(
+					"Instance %s in project %s has no 'size' config set on the root device, "+
+						"either directly or via a profile",
+					instance.Name, instance.Project)
+			}
+		} else {
+			value, ok = instance.Config[key]
+			if !ok || value == "" {
+				return nil, fmt.Errorf(
+					"Instance %s in project %s has no '%s' config, "+
+						"either directly or via a profile",
+					instance.Name, instance.Project, key)
+			}
 		}
 
 		parser := aggregateLimitConfigValueParsers[key]
@@ -832,6 +854,9 @@ var aggregateLimitConfigValueParsers = map[string]func(string) (int64, error){
 
 		return int64(limit), nil
 	},
+	"limits.disk": func(value string) (int64, error) {
+		return units.ParseByteSizeString(value)
+	},
 }
 
 var aggregateLimitConfigValuePrinters = map[string]func(int64) string{
@@ -844,4 +869,7 @@ var aggregateLimitConfigValuePrinters = map[string]func(int64) string{
 	"limits.cpu": func(limit int64) string {
 		return fmt.Sprintf("%d", limit)
 	},
+	"limits.disk": func(limit int64) string {
+		return units.GetByteSizeString(limit, 1)
+	},
 }

From 7d9fde021bac46e27771985ad9ac3c29d7e0a6cb Mon Sep 17 00:00:00 2001
From: Free Ekanayaka <free.ekanayaka at canonical.com>
Date: Tue, 14 Jul 2020 14:46:28 +0200
Subject: [PATCH 6/6] test: Add tests for the "limits.disk" project config key

Signed-off-by: Free Ekanayaka <free.ekanayaka at canonical.com>
---
 test/suites/projects.sh | 27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)

diff --git a/test/suites/projects.sh b/test/suites/projects.sh
index e7f9458a43..83cea1cb54 100644
--- a/test/suites/projects.sh
+++ b/test/suites/projects.sh
@@ -633,6 +633,33 @@ test_projects_limits() {
   lxc profile set default limits.cpu=3
   lxc config set c2 limits.cpu=3
 
+  # Can't set the project's disk limit because not all instances have
+  # the "size" config defined on the root device.
+  ! lxc project set p1 limits.disk 1GB || false
+
+  # Set a disk limit on the default profile and also on instance c2
+  lxc profile device set default root size=100MB
+  lxc config device add c2 root disk path="/" pool="${pool}" size=50MB
+
+  # Can't set the project's disk limit below the current aggregate count.
+  ! lxc project set p1 limits.disk 100MB || false
+
+  # Set the project's disk limit
+  lxc project set p1 limits.disk 200MB
+
+  # Can't update the project's disk limit below the current aggregate count.
+  ! lxc project set p1 limits.disk 100MB || false
+
+  # Changing profile or instance root device size above the aggregate project's
+  # limit is not possible.
+  ! lxc profile device set default root size=160MB || false
+  ! lxc config device set c2 root size 110MB || false
+
+  # Disk limits can be updated if they stay within limits.
+  lxc project set p1 limits.disk 150MB
+  lxc profile device set default root size=90MB
+  lxc config device set c2 root size 60MB
+
   lxc delete c1
   lxc delete c2
   lxc image delete testimage


More information about the lxc-devel mailing list