2
0
Эх сурвалжийг харах

add exceeded boolean and exceeded since key

Alexander Belanger 4 жил өмнө
parent
commit
6bd483b8bd

+ 1 - 1
.air.toml

@@ -7,7 +7,7 @@ tmp_dir = "tmp"
 
 [build]
 # Just plain old shell command. You could use `make` as well.
-cmd = "go build -o ./tmp/app ./cmd/app"
+cmd = "go build -o ./tmp/app -tags ee ./cmd/app"
 # Binary file yields from `cmd`.
 bin = "tmp/app"
 # Customize binary.

+ 3 - 1
api/server/handlers/project/get_usage.go

@@ -30,7 +30,7 @@ func (p *ProjectGetUsageHandler) ServeHTTP(w http.ResponseWriter, r *http.Reques
 
 	res := &types.GetProjectUsageResponse{}
 
-	currUsage, limit, err := usage.GetUsage(p.Config(), proj)
+	currUsage, limit, usageCache, err := usage.GetUsage(p.Config(), proj)
 
 	if err != nil {
 		p.HandleAPIError(w, r, apierrors.NewErrInternal(err))
@@ -39,6 +39,8 @@ func (p *ProjectGetUsageHandler) ServeHTTP(w http.ResponseWriter, r *http.Reques
 
 	res.Current = *currUsage
 	res.Limit = *limit
+	res.IsExceeded = usageCache.Exceeded
+	res.ExceededSince = usageCache.ExceededSince
 
 	p.WriteResult(w, r, res)
 }

+ 1 - 1
api/server/router/middleware/usage.go

@@ -27,7 +27,7 @@ func (b *UsageMiddleware) Middleware(next http.Handler) http.Handler {
 		proj, _ := r.Context().Value(types.ProjectScope).(*models.Project)
 
 		// get the project usage limits
-		currentUsage, limit, err := usage.GetUsage(b.config, proj)
+		currentUsage, limit, _, err := usage.GetUsage(b.config, proj)
 
 		if err != nil {
 			apierrors.HandleAPIError(

+ 8 - 0
api/types/usage.go

@@ -1,5 +1,7 @@
 package types
 
+import "time"
+
 type UsageMetric string
 
 const (
@@ -58,4 +60,10 @@ var EnterprisePlan = ProjectUsage{
 type GetProjectUsageResponse struct {
 	Current ProjectUsage `json:"current"`
 	Limit   ProjectUsage `json:"limit"`
+
+	// Whether the usage is exceeded
+	IsExceeded bool `json:"exceeded"`
+
+	// When the usage has been exceeded since, if IsExceeded
+	ExceededSince *time.Time `json:"exceeded_since,omitempty"`
 }

+ 6 - 0
internal/models/usage.go

@@ -50,6 +50,12 @@ type ProjectUsageCache struct {
 
 	// The memory usage, in bytes
 	ResourceMemory uint
+
+	// Whether the user is exceeding usage
+	Exceeded bool
+
+	// How long the user has been exceeding resource limits
+	ExceededSince *time.Time
 }
 
 func (p *ProjectUsageCache) Is24HrOld() bool {

+ 24 - 8
internal/usage/usage.go

@@ -3,6 +3,7 @@ package usage
 import (
 	"errors"
 	"fmt"
+	"time"
 
 	"github.com/porter-dev/porter/api/server/authz"
 	"github.com/porter-dev/porter/api/server/shared/config"
@@ -16,33 +17,34 @@ import (
 // GetUsage gets a project's current usage and usage limit
 func GetUsage(config *config.Config, proj *models.Project) (
 	current, limit *types.ProjectUsage,
+	resourceUse *models.ProjectUsageCache,
 	err error,
 ) {
 	limit, err = GetLimit(config, proj)
 
 	if err != nil {
-		return nil, nil, err
+		return nil, nil, nil, err
 	}
 
 	// query for the linked cluster counts
 	clusters, err := config.Repo.Cluster().ListClustersByProjectID(proj.ID)
 
 	if err != nil {
-		return nil, nil, err
+		return nil, nil, nil, err
 	}
 
 	// query for the linked user counts
 	roles, err := config.Repo.Project().ListProjectRoles(proj.ID)
 
 	if err != nil {
-		return nil, nil, err
+		return nil, nil, nil, err
 	}
 
 	usageCache, err := config.Repo.ProjectUsage().ReadProjectUsageCache(proj.ID)
 	isCacheFound := true
 
 	if isCacheFound = !errors.Is(err, gorm.ErrRecordNotFound); err != nil && isCacheFound {
-		return nil, nil, err
+		return nil, nil, nil, err
 	}
 
 	// if the usage cache is 24 hours old, was not found, or usage is over limit,
@@ -51,19 +53,33 @@ func GetUsage(config *config.Config, proj *models.Project) (
 		cpu, memory, err := getResourceUsage(config, clusters)
 
 		if err != nil {
-			return nil, nil, err
+			return nil, nil, nil, err
 		}
 
 		if !isCacheFound {
-			usageCache, err = config.Repo.ProjectUsage().CreateProjectUsageCache(&models.ProjectUsageCache{
+			usageCache = &models.ProjectUsageCache{
 				ProjectID:      proj.ID,
 				ResourceCPU:    cpu,
 				ResourceMemory: memory,
-			})
+			}
 		} else {
 			usageCache.ResourceCPU = cpu
 			usageCache.ResourceMemory = memory
+		}
+
+		isExceeded := usageCache.ResourceCPU > limit.ResourceCPU || usageCache.ResourceMemory > limit.ResourceMemory
+
+		if !usageCache.Exceeded && isExceeded {
+			// update the usage cache with a time exceeded
+			currTime := time.Now()
+			usageCache.ExceededSince = &currTime
+		}
 
+		usageCache.Exceeded = isExceeded
+
+		if !isCacheFound {
+			usageCache, err = config.Repo.ProjectUsage().CreateProjectUsageCache(usageCache)
+		} else {
 			usageCache, err = config.Repo.ProjectUsage().UpdateProjectUsageCache(usageCache)
 		}
 	}
@@ -73,7 +89,7 @@ func GetUsage(config *config.Config, proj *models.Project) (
 		ResourceMemory: usageCache.ResourceMemory,
 		Clusters:       uint(len(clusters)),
 		Users:          uint(len(roles)),
-	}, limit, nil
+	}, limit, usageCache, nil
 }
 
 // gets the total resource usage across all nodes in all clusters