فهرست منبع

add capability to parse feature flags

Alexander Belanger 3 سال پیش
والد
کامیت
ebac8cca7b

+ 7 - 0
api/types/project.go

@@ -11,6 +11,13 @@ type Project struct {
 	StacksEnabled       bool    `json:"stacks_enabled"`
 }
 
+type FeatureFlags struct {
+	PreviewEnvironmentsEnabled string `json:"preview_environments_enabled,omitempty"`
+	ManagedInfraEnabled        string `json:"managed_infra_enabled,omitempty"`
+	StacksEnabled              string `json:"stacks_enabled,omitempty"`
+	ManagedDatabasesEnabled    string `json:"managed_databases_enabled,omitempty"`
+}
+
 type CreateProjectRequest struct {
 	Name string `json:"name" form:"required"`
 }

+ 33 - 1
ee/api/server/handlers/billing/webhook.go

@@ -5,6 +5,7 @@ import (
 	"fmt"
 	"io/ioutil"
 	"net/http"
+	"strconv"
 
 	"github.com/porter-dev/porter/api/server/authz"
 	"github.com/porter-dev/porter/api/server/handlers"
@@ -48,7 +49,7 @@ func (c *BillingWebhookHandler) ServeHTTP(w http.ResponseWriter, r *http.Request
 	}
 
 	// parse usage and update project
-	newUsage, err := c.Config().BillingManager.ParseProjectUsageFromWebhook(payload)
+	newUsage, features, err := c.Config().BillingManager.ParseProjectUsageFromWebhook(payload)
 
 	if err != nil {
 		c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
@@ -81,4 +82,35 @@ func (c *BillingWebhookHandler) ServeHTTP(w http.ResponseWriter, r *http.Request
 		c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
 		return
 	}
+
+	// update the feature flags
+	project, err := c.Repo().Project().ReadProject(newUsage.ProjectID)
+
+	if err != nil {
+		c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
+		return
+	}
+
+	if managedDatabasesEnabled, err := strconv.ParseBool(features.ManagedDatabasesEnabled); err == nil {
+		project.RDSDatabasesEnabled = managedDatabasesEnabled
+	}
+
+	if managedInfraEnabled, err := strconv.ParseBool(features.ManagedInfraEnabled); err == nil {
+		project.ManagedInfraEnabled = managedInfraEnabled
+	}
+
+	if stacksEnabled, err := strconv.ParseBool(features.StacksEnabled); err == nil {
+		project.StacksEnabled = stacksEnabled
+	}
+
+	if previewEnvsEnabled, err := strconv.ParseBool(features.PreviewEnvironmentsEnabled); err == nil {
+		project.PreviewEnvsEnabled = previewEnvsEnabled
+	}
+
+	_, err = c.Repo().Project().UpdateProject(project)
+
+	if err != nil {
+		c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
+		return
+	}
 }

+ 14 - 8
ee/billing/client.go

@@ -15,6 +15,7 @@ import (
 	"strings"
 	"time"
 
+	"github.com/porter-dev/porter/api/types"
 	cemodels "github.com/porter-dev/porter/internal/models"
 )
 
@@ -221,20 +222,25 @@ const (
 	FeatureSlugUsers    string = "users"
 )
 
-func (c *Client) ParseProjectUsageFromWebhook(payload []byte) (*cemodels.ProjectUsage, error) {
+func (c *Client) ParseProjectUsageFromWebhook(payload []byte) (*cemodels.ProjectUsage, *types.FeatureFlags, error) {
 	usageData := &APIWebhookRequest{}
 
 	err := json.Unmarshal(payload, usageData)
 
 	if err != nil {
-		return nil, err
+		return nil, nil, err
 	}
 
 	return &cemodels.ProjectUsage{
-		ProjectID:      usageData.ProjectID,
-		ResourceCPU:    usageData.CPU,
-		ResourceMemory: usageData.Memory * 1000,
-		Clusters:       usageData.Clusters,
-		Users:          usageData.Users,
-	}, nil
+			ProjectID:      usageData.ProjectID,
+			ResourceCPU:    usageData.CPU,
+			ResourceMemory: usageData.Memory * 1000,
+			Clusters:       usageData.Clusters,
+			Users:          usageData.Users,
+		}, &types.FeatureFlags{
+			PreviewEnvironmentsEnabled: usageData.PreviewEnvironmentsEnabled,
+			ManagedInfraEnabled:        usageData.ManagedInfraEnabled,
+			StacksEnabled:              usageData.StacksEnabled,
+			ManagedDatabasesEnabled:    usageData.ManagedDatabasesEnabled,
+		}, nil
 }

+ 5 - 0
ee/billing/types.go

@@ -22,4 +22,9 @@ type APIWebhookRequest struct {
 	Users    uint `json:"users" form:"required"`
 	CPU      uint `json:"cpu" form:"required"`
 	Memory   uint `json:"memory" form:"required"`
+
+	PreviewEnvironmentsEnabled string `json:"preview_environments_enabled,omitempty"`
+	ManagedInfraEnabled        string `json:"managed_infra_enabled,omitempty"`
+	StacksEnabled              string `json:"stacks_enabled,omitempty"`
+	ManagedDatabasesEnabled    string `json:"managed_databases_enabled,omitempty"`
 }

+ 4 - 3
internal/billing/billing.go

@@ -3,6 +3,7 @@ package billing
 import (
 	"fmt"
 
+	"github.com/porter-dev/porter/api/types"
 	"github.com/porter-dev/porter/internal/models"
 )
 
@@ -18,7 +19,7 @@ type BillingManager interface {
 
 	// ParseProjectUsageFromWebhook parses the project usage from a webhook payload sent
 	// from a billing agent
-	ParseProjectUsageFromWebhook(payload []byte) (*models.ProjectUsage, error)
+	ParseProjectUsageFromWebhook(payload []byte) (*models.ProjectUsage, *types.FeatureFlags, error)
 
 	// VerifySignature verifies the signature for a webhook
 	VerifySignature(signature string, body []byte) bool
@@ -35,8 +36,8 @@ func (n *NoopBillingManager) DeleteTeam(user *models.User, proj *models.Project)
 	return nil
 }
 
-func (n *NoopBillingManager) ParseProjectUsageFromWebhook(payload []byte) (*models.ProjectUsage, error) {
-	return nil, nil
+func (n *NoopBillingManager) ParseProjectUsageFromWebhook(payload []byte) (*models.ProjectUsage, *types.FeatureFlags, error) {
+	return nil, nil, nil
 }
 
 func (n *NoopBillingManager) VerifySignature(signature string, body []byte) bool {

+ 9 - 0
internal/repository/gorm/project.go

@@ -41,6 +41,15 @@ func (repo *ProjectRepository) CreateProjectRole(project *models.Project, role *
 	return role, nil
 }
 
+// UpdateProject updates an existing project
+func (repo *ProjectRepository) UpdateProject(project *models.Project) (*models.Project, error) {
+	if err := repo.db.Save(project).Error; err != nil {
+		return nil, err
+	}
+
+	return project, nil
+}
+
 func (repo *ProjectRepository) UpdateProjectRole(projID uint, role *models.Role) (*models.Role, error) {
 	foundRole := &models.Role{}
 

+ 1 - 0
internal/repository/project.go

@@ -11,6 +11,7 @@ type WriteProject func(project *models.Project) (*models.Project, error)
 type ProjectRepository interface {
 	CreateProject(project *models.Project) (*models.Project, error)
 	CreateProjectRole(project *models.Project, role *models.Role) (*models.Role, error)
+	UpdateProject(project *models.Project) (*models.Project, error)
 	UpdateProjectRole(projID uint, role *models.Role) (*models.Role, error)
 	ReadProject(id uint) (*models.Project, error)
 	ReadProjectRole(projID, userID uint) (*models.Role, error)

+ 4 - 0
internal/repository/test/project.go

@@ -60,6 +60,10 @@ func (repo *ProjectRepository) CreateProjectRole(project *models.Project, role *
 	return role, nil
 }
 
+func (repo *ProjectRepository) UpdateProject(project *models.Project) (*models.Project, error) {
+	panic("unimplemented")
+}
+
 // CreateProjectRole appends a role to the existing array of roles
 func (repo *ProjectRepository) UpdateProjectRole(projID uint, role *models.Role) (*models.Role, error) {
 	if !repo.canQuery {