[lxc-devel] [lxd/master] Adds a new 'limits.instances' key in project

kevtheappdev on Github lxc-bot at linuxcontainers.org
Mon Dec 7 06:02:54 UTC 2020


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 314 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20201206/bfa78558/attachment.bin>
-------------- next part --------------
From 17a021048c153783a97748f09db5ca62141d7361 Mon Sep 17 00:00:00 2001
From: Max Patrick <maxpat21 at verizon.net>
Date: Mon, 7 Dec 2020 11:24:36 +0530
Subject: [PATCH 1/3] doc: Adds limits.instances key description.

Signed-off-by: Kevin Turner <kevinturner at utexas.edu>
---
 doc/projects.md | 1 +
 1 file changed, 1 insertion(+)

diff --git a/doc/projects.md b/doc/projects.md
index 462864fabb..65a54f9266 100644
--- a/doc/projects.md
+++ b/doc/projects.md
@@ -21,6 +21,7 @@ features.images                      | boolean   | -                     | true
 features.networks                    | boolean   | -                     | true                      | Separate set of networks for the project
 features.profiles                    | boolean   | -                     | true                      | Separate set of profiles for the project
 features.storage.volumes             | boolean   | -                     | true                      | Separate set of storage volumes for the project
+limits.instances                     | integer   | -                     | -                         | Maximum number of total instances that can be created in the project    
 limits.containers                    | integer   | -                     | -                         | Maximum number of containers 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.disk                          | string    | -                     | -                         | Maximum value of aggregate disk space used by all instances volumes, custom volumes and images of the project

From 2d5fc48461dac7d3bfceecade9c1765f361f606b Mon Sep 17 00:00:00 2001
From: Max Patrick <maxpat21 at verizon.net>
Date: Mon, 7 Dec 2020 11:25:23 +0530
Subject: [PATCH 2/3] api: Adds limits.instances

Signed-off-by: Kevin Turner <kevinturner at utexas.edu>
---
 lxd/api_project.go | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/lxd/api_project.go b/lxd/api_project.go
index 5c4993cec1..c87cf8e20e 100644
--- a/lxd/api_project.go
+++ b/lxd/api_project.go
@@ -351,6 +351,7 @@ func projectChange(d *Daemon, project *api.Project, req api.ProjectPut) response
 	// Update the database entry.
 	err = d.cluster.Transaction(func(tx *db.ClusterTx) error {
 		err := projecthelpers.AllowProjectUpdate(tx, project.Name, req.Config, configChanged)
+
 		if err != nil {
 			return err
 		}
@@ -524,6 +525,7 @@ func projectValidateConfig(s *state.State, config map[string]string) error {
 		"features.images":                validate.Optional(validate.IsBool),
 		"features.storage.volumes":       validate.Optional(validate.IsBool),
 		"features.networks":              validate.Optional(validate.IsBool),
+		"limits.instances":				  validate.Optional(validate.IsUint32),
 		"limits.containers":              validate.Optional(validate.IsUint32),
 		"limits.virtual-machines":        validate.Optional(validate.IsUint32),
 		"limits.memory":                  validate.Optional(validate.IsSize),

From bbbd95b3d82c86ac63897de856cf4b12676e5d09 Mon Sep 17 00:00:00 2001
From: Max Patrick <maxpat21 at verizon.net>
Date: Mon, 7 Dec 2020 11:26:03 +0530
Subject: [PATCH 3/3] lxd/project: Adds 'limits.instances' configuration key

Signed-Off-By: Kevin Turner <kevinturner at utexas.edu>
---
 lxd/api_project.go              |  2 +-
 lxd/project/permissions.go      | 52 +++++++++++++++++++++++++++++++++
 lxd/project/permissions_test.go | 35 ++++++++++++++++++++++
 3 files changed, 88 insertions(+), 1 deletion(-)

diff --git a/lxd/api_project.go b/lxd/api_project.go
index c87cf8e20e..103faafd32 100644
--- a/lxd/api_project.go
+++ b/lxd/api_project.go
@@ -525,7 +525,7 @@ func projectValidateConfig(s *state.State, config map[string]string) error {
 		"features.images":                validate.Optional(validate.IsBool),
 		"features.storage.volumes":       validate.Optional(validate.IsBool),
 		"features.networks":              validate.Optional(validate.IsBool),
-		"limits.instances":				  validate.Optional(validate.IsUint32),
+		"limits.instances":	    		  validate.Optional(validate.IsUint32),
 		"limits.containers":              validate.Optional(validate.IsUint32),
 		"limits.virtual-machines":        validate.Optional(validate.IsUint32),
 		"limits.memory":                  validate.Optional(validate.IsSize),
diff --git a/lxd/project/permissions.go b/lxd/project/permissions.go
index 74e9f0380f..df12ef97be 100644
--- a/lxd/project/permissions.go
+++ b/lxd/project/permissions.go
@@ -56,6 +56,12 @@ func AllowInstanceCreation(tx *db.ClusterTx, projectName string, req api.Instanc
 		return err
 	}
 
+	totalInstanceCount := len(info.Instances)
+	err = checkTotalInstanceCountLimit(info.Project, totalInstanceCount)
+	if err != nil {
+		return err
+	}
+	
 	// Add the instance being created.
 	info.Instances = append(info.Instances, db.Instance{
 		Name:     req.Name,
@@ -79,6 +85,27 @@ func AllowInstanceCreation(tx *db.ClusterTx, projectName string, req api.Instanc
 	return nil
 }
 
+// Check that we have not exceeded the maximum total alotted number of instances
+// for both containers and vms
+
+func checkTotalInstanceCountLimit(project *api.Project, totalInstanceCount int) error {
+	
+	overallValue, ok := project.Config["limits.instances"]
+	if ok {
+		limit, err := strconv.Atoi(overallValue)
+		if err != nil || limit < 0 {
+			return fmt.Errorf("Unexpected limits.instances value: %q", overallValue)
+		}
+
+		if totalInstanceCount >= limit {
+			return fmt.Errorf(
+				"Reached maximum number of instances in project %q",
+				project.Name)
+		}
+	}
+	return nil
+}
+
 // Check that we have not reached the maximum number of instances for
 // this type.
 func checkInstanceCountLimit(project *api.Project, instanceCount int, instanceType instancetype.Type) error {
@@ -716,6 +743,11 @@ func AllowProjectUpdate(tx *db.ClusterTx, projectName string, config map[string]
 		}
 
 		switch key {
+		case "limits.instances":
+			err := validateTotalInstanceCountLimit(info.Instances, config[key], projectName)
+			if err != nil {
+				return errors.Wrapf(err, "Can't change limits.instances in project %q", projectName)
+			}
 		case "limits.containers":
 			fallthrough
 		case "limits.virtual-machines":
@@ -752,6 +784,26 @@ func AllowProjectUpdate(tx *db.ClusterTx, projectName string, config map[string]
 	return nil
 }
 
+// Check that limits.instances, i.e. the total limit of containers/virtual machines allocated
+// to the user is equal to or above the current count
+func validateTotalInstanceCountLimit(instances []db.Instance, value, project string) error {
+	if value == "" {
+		return nil
+	}
+
+	limit, err := strconv.Atoi(value)
+	if err != nil {
+		return err
+	}
+
+	count := len(instances)
+
+	if limit < count {
+		return fmt.Errorf("'limits.instances' is too low: there currently are %d total instances in project %s", count, project)
+	}
+	return nil
+}
+
 // Check that limits.containers or limits.virtual-machines is equal or above
 // the current count.
 func validateInstanceCountLimit(instances []db.Instance, key, value, project string) error {
diff --git a/lxd/project/permissions_test.go b/lxd/project/permissions_test.go
index ccede05630..41e5daebe3 100644
--- a/lxd/project/permissions_test.go
+++ b/lxd/project/permissions_test.go
@@ -124,3 +124,38 @@ func TestAllowInstanceCreation_DifferentType(t *testing.T) {
 	err = project.AllowInstanceCreation(tx, "p1", req)
 	assert.NoError(t, err)
 }
+
+// If a limit is configured, but the limit on instances is more
+// restrictive, the check fails
+func TestAllowInstanceCreation_AboveInstances(t *testing.T) {
+	tx, cleanup := db.NewTestClusterTx(t)
+	defer cleanup()
+
+	_, err := tx.CreateProject(api.ProjectsPost{
+		Name: "p1",
+		ProjectPut: api.ProjectPut{
+			Config: map[string]string{
+				"limits.containers": "5",
+				"limits.instances" : "1",
+			},
+		},
+	})
+	require.NoError(t, err)
+
+	_, err = tx.CreateInstance(db.Instance{
+		Project:      "p1",
+		Name:         "c1",
+		Type:         instancetype.Container,
+		Architecture: 1,
+		Node:         "none",
+	})
+	require.NoError(t, err)
+
+	req := api.InstancesPost{
+		Name: "c2",
+		Type: api.InstanceTypeContainer,
+	}
+
+	err = project.AllowInstanceCreation(tx, "p1", req)
+	assert.EqualError(t, err, `Reached maximum number of instances in project "p1"`)
+}
\ No newline at end of file


More information about the lxc-devel mailing list