From 077256b69c16ebe26ae7c85284ef6b3101bd3c80 Mon Sep 17 00:00:00 2001 From: Dhruv Dhruv Date: Thu, 26 Sep 2024 13:50:17 +0000 Subject: [PATCH] feat: [CDE-354]: Adding gitspace usage limiter & checking usage before creation and start. (#2745) * feat: [CDE-354]: Adding gitspace usage limiter & checking usage before creation and start. --- app/api/controller/gitspace/action.go | 5 +++ app/api/controller/gitspace/controller.go | 4 +++ app/api/controller/gitspace/create.go | 6 ++++ app/api/controller/gitspace/wire.go | 3 ++ app/api/controller/limiter/gitspace.go | 39 +++++++++++++++++++++++ app/api/controller/limiter/wire.go | 5 +++ cmd/gitness/wire_gen.go | 3 +- 7 files changed, 64 insertions(+), 1 deletion(-) create mode 100644 app/api/controller/limiter/gitspace.go diff --git a/app/api/controller/gitspace/action.go b/app/api/controller/gitspace/action.go index 030c3d772..6a7f7f603 100644 --- a/app/api/controller/gitspace/action.go +++ b/app/api/controller/gitspace/action.go @@ -89,6 +89,11 @@ func (c *Controller) Action( // All the actions should be idempotent. switch in.Action { case enum.GitspaceActionTypeStart: + err = c.gitspaceLimiter.Usage(ctx, space.ID) + if err != nil { + return nil, fmt.Errorf("usage has exceeded limit, can not start any gitspaces: %w", err) + } + c.emitGitspaceConfigEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeGitspaceActionStart) err = c.startGitspaceAction(ctx, gitspaceConfig) return gitspaceConfig, err diff --git a/app/api/controller/gitspace/controller.go b/app/api/controller/gitspace/controller.go index 595758eb3..d36e6600a 100644 --- a/app/api/controller/gitspace/controller.go +++ b/app/api/controller/gitspace/controller.go @@ -15,6 +15,7 @@ package gitspace import ( + "github.com/harness/gitness/app/api/controller/limiter" "github.com/harness/gitness/app/auth/authz" gitspaceevents "github.com/harness/gitness/app/events/gitspace" "github.com/harness/gitness/app/gitspace/logutil" @@ -40,6 +41,7 @@ type Controller struct { scm scm.SCM repoStore store.RepoStore gitspaceSvc *gitspace.Service + gitspaceLimiter limiter.Gitspace } func NewController( @@ -56,6 +58,7 @@ func NewController( scm scm.SCM, repoStore store.RepoStore, gitspaceSvc *gitspace.Service, + gitspaceLimiter limiter.Gitspace, ) *Controller { return &Controller{ tx: tx, @@ -71,5 +74,6 @@ func NewController( scm: scm, repoStore: repoStore, gitspaceSvc: gitspaceSvc, + gitspaceLimiter: gitspaceLimiter, } } diff --git a/app/api/controller/gitspace/create.go b/app/api/controller/gitspace/create.go index b12f64e93..5cffa93cd 100644 --- a/app/api/controller/gitspace/create.go +++ b/app/api/controller/gitspace/create.go @@ -81,6 +81,12 @@ func (c *Controller) Create( enum.PermissionGitspaceEdit); err != nil { return nil, err } + + err = c.gitspaceLimiter.Usage(ctx, space.ID) + if err != nil { + return nil, fmt.Errorf("usage has exceeded limit, can not create any gitspaces: %w", err) + } + // check if it's an internal repo if in.CodeRepoType == enum.CodeRepoTypeGitness && *in.CodeRepoRef != "" { repo, err := c.repoStore.FindByRef(ctx, *in.CodeRepoRef) diff --git a/app/api/controller/gitspace/wire.go b/app/api/controller/gitspace/wire.go index 3fe6954d3..41381f373 100644 --- a/app/api/controller/gitspace/wire.go +++ b/app/api/controller/gitspace/wire.go @@ -15,6 +15,7 @@ package gitspace import ( + "github.com/harness/gitness/app/api/controller/limiter" "github.com/harness/gitness/app/auth/authz" gitspaceevents "github.com/harness/gitness/app/events/gitspace" "github.com/harness/gitness/app/gitspace/logutil" @@ -47,6 +48,7 @@ func ProvideController( scm scm.SCM, repoStore store.RepoStore, gitspaceSvc *gitspace.Service, + gitspaceLimiter limiter.Gitspace, ) *Controller { return NewController( tx, @@ -62,5 +64,6 @@ func ProvideController( scm, repoStore, gitspaceSvc, + gitspaceLimiter, ) } diff --git a/app/api/controller/limiter/gitspace.go b/app/api/controller/limiter/gitspace.go new file mode 100644 index 000000000..a875784c6 --- /dev/null +++ b/app/api/controller/limiter/gitspace.go @@ -0,0 +1,39 @@ +// Copyright 2023 Harness, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package limiter + +import ( + "context" +) + +// Gitspace is an interface for managing gitspace limitations. +type Gitspace interface { + // Usage checks if the total usage for the root space and all sub-spaces is under a limit. + Usage(ctx context.Context, spaceID int64) error +} + +var _ Gitspace = (*UnlimitedUsage)(nil) + +type UnlimitedUsage struct { +} + +// NewUnlimitedUsage creates a new instance of UnlimitedGitspace. +func NewUnlimitedUsage() Gitspace { + return UnlimitedUsage{} +} + +func (UnlimitedUsage) Usage(_ context.Context, _ int64) error { + return nil +} diff --git a/app/api/controller/limiter/wire.go b/app/api/controller/limiter/wire.go index f190905a7..4b3a281cd 100644 --- a/app/api/controller/limiter/wire.go +++ b/app/api/controller/limiter/wire.go @@ -20,8 +20,13 @@ import ( var WireSet = wire.NewSet( ProvideLimiter, + ProvideGitspaceLimiter, ) func ProvideLimiter() (ResourceLimiter, error) { return NewResourceLimiter(), nil } + +func ProvideGitspaceLimiter() Gitspace { + return NewUnlimitedUsage() +} diff --git a/cmd/gitness/wire_gen.go b/cmd/gitness/wire_gen.go index 240824c23..d47f5c8b5 100644 --- a/cmd/gitness/wire_gen.go +++ b/cmd/gitness/wire_gen.go @@ -405,7 +405,8 @@ func initSystem(ctx context.Context, config *types.Config) (*server.System, erro resolverFactory := secret2.ProvideResolverFactory(passwordResolver) orchestratorOrchestrator := orchestrator.ProvideOrchestrator(scmSCM, infraProviderResourceStore, infraProvisioner, containerOrchestrator, reporter5, orchestratorConfig, vsCode, vsCodeWeb, resolverFactory) gitspaceEventStore := database.ProvideGitspaceEventStore(db) - gitspaceController := gitspace2.ProvideController(transactor, authorizer, infraproviderService, gitspaceConfigStore, gitspaceInstanceStore, spaceStore, reporter5, orchestratorOrchestrator, gitspaceEventStore, statefulLogger, scmSCM, repoStore, gitspaceService) + limiterGitspace := limiter.ProvideGitspaceLimiter() + gitspaceController := gitspace2.ProvideController(transactor, authorizer, infraproviderService, gitspaceConfigStore, gitspaceInstanceStore, spaceStore, reporter5, orchestratorOrchestrator, gitspaceEventStore, statefulLogger, scmSCM, repoStore, gitspaceService, limiterGitspace) rule := migrate.ProvideRuleImporter(ruleStore, transactor, principalStore) migrateWebhook := migrate.ProvideWebhookImporter(webhookConfig, transactor, webhookStore) migrateController := migrate2.ProvideController(authorizer, publicaccessService, gitInterface, provider, pullReq, rule, migrateWebhook, resourceLimiter, auditService, repoIdentifier, transactor, spaceStore, repoStore)