The following pull request was submitted through Github. It can be accessed and reviewed at: https://github.com/lxc/lxd/pull/8217
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) === Fixes #7925.
From 17a021048c153783a97748f09db5ca62141d7361 Mon Sep 17 00:00:00 2001 From: Max Patrick <maxpa...@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 <kevintur...@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 <maxpa...@verizon.net> Date: Mon, 7 Dec 2020 11:25:23 +0530 Subject: [PATCH 2/3] api: Adds limits.instances Signed-off-by: Kevin Turner <kevintur...@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 <maxpa...@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 <kevintur...@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
_______________________________________________ lxc-devel mailing list lxc-devel@lists.linuxcontainers.org http://lists.linuxcontainers.org/listinfo/lxc-devel