Skip to content

Commit

Permalink
Metronome business logic (#4497)
Browse files Browse the repository at this point in the history
Metronome business logic and a fix to the customer creation logic
  • Loading branch information
MauAraujo authored Apr 4, 2024
1 parent f31144c commit ef7e3fe
Show file tree
Hide file tree
Showing 27 changed files with 751 additions and 370 deletions.
4 changes: 2 additions & 2 deletions api/server/handlers/billing/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ func (c *CreateBillingHandler) ServeHTTP(w http.ResponseWriter, r *http.Request)

proj, _ := ctx.Value(types.ProjectScope).(*models.Project)

clientSecret, err := c.Config().BillingManager.CreatePaymentMethod(ctx, proj)
clientSecret, err := c.Config().BillingManager.StripeClient.CreatePaymentMethod(ctx, proj.BillingID)
if err != nil {
err := telemetry.Error(ctx, span, err, "error creating payment method")
c.HandleAPIError(w, r, apierrors.NewErrInternal(fmt.Errorf("error creating payment method: %w", err)))
Expand Down Expand Up @@ -81,7 +81,7 @@ func (c *SetDefaultBillingHandler) ServeHTTP(w http.ResponseWriter, r *http.Requ
return
}

err := c.Config().BillingManager.SetDefaultPaymentMethod(ctx, paymentMethodID, proj)
err := c.Config().BillingManager.StripeClient.SetDefaultPaymentMethod(ctx, paymentMethodID, proj.BillingID)
if err != nil {
err := telemetry.Error(ctx, span, err, "error setting default payment method")
c.HandleAPIError(w, r, apierrors.NewErrInternal(fmt.Errorf("error setting default payment method: %w", err)))
Expand Down
48 changes: 48 additions & 0 deletions api/server/handlers/billing/credits.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package billing

import (
"net/http"

"github.com/porter-dev/porter/api/server/handlers"
"github.com/porter-dev/porter/api/server/shared"
"github.com/porter-dev/porter/api/server/shared/apierrors"
"github.com/porter-dev/porter/api/server/shared/config"
"github.com/porter-dev/porter/api/types"
"github.com/porter-dev/porter/internal/models"
"github.com/porter-dev/porter/internal/telemetry"
)

// GetCreditsHandler is a handler for getting available credits
type GetCreditsHandler struct {
handlers.PorterHandlerWriter
}

// NewGetCreditsHandler will create a new GetCreditsHandler
func NewGetCreditsHandler(
config *config.Config,
writer shared.ResultWriter,
) *GetCreditsHandler {
return &GetCreditsHandler{
PorterHandlerWriter: handlers.NewDefaultPorterHandler(config, nil, writer),
}
}

func (c *GetCreditsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
ctx, span := telemetry.NewSpan(r.Context(), "get-credits-endpoint")
defer span.End()

proj, _ := ctx.Value(types.ProjectScope).(*models.Project)

if !proj.GetFeatureFlag(models.MetronomeEnabled, c.Config().LaunchDarklyClient) {
c.WriteResult(w, r, "")
}

credits, err := c.Config().BillingManager.MetronomeClient.GetCustomerCredits(proj.UsageID)
if err != nil {
err := telemetry.Error(ctx, span, err, "error getting credits")
c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
return
}

c.WriteResult(w, r, credits)
}
103 changes: 0 additions & 103 deletions api/server/handlers/billing/customer.go

This file was deleted.

2 changes: 1 addition & 1 deletion api/server/handlers/billing/delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ func (c *DeleteBillingHandler) ServeHTTP(w http.ResponseWriter, r *http.Request)
return
}

err := c.Config().BillingManager.DeletePaymentMethod(ctx, paymentMethodID)
err := c.Config().BillingManager.StripeClient.DeletePaymentMethod(ctx, paymentMethodID)
if err != nil {
err := telemetry.Error(ctx, span, err, "error deleting payment method")
c.HandleAPIError(w, r, apierrors.NewErrInternal(fmt.Errorf("error deleting payment method: %w", err)))
Expand Down
47 changes: 47 additions & 0 deletions api/server/handlers/billing/key.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package billing

import (
"net/http"

"github.com/porter-dev/porter/api/server/handlers"
"github.com/porter-dev/porter/api/server/shared"
"github.com/porter-dev/porter/api/server/shared/config"
"github.com/porter-dev/porter/api/types"
"github.com/porter-dev/porter/internal/models"
"github.com/porter-dev/porter/internal/telemetry"
)

// GetPublishableKeyHandler will return the configured publishable key
type GetPublishableKeyHandler struct {
handlers.PorterHandlerReadWriter
}

// NewGetPublishableKeyHandler will return the publishable key
func NewGetPublishableKeyHandler(
config *config.Config,
decoderValidator shared.RequestDecoderValidator,
writer shared.ResultWriter,
) *GetPublishableKeyHandler {
return &GetPublishableKeyHandler{
PorterHandlerReadWriter: handlers.NewDefaultPorterHandler(config, decoderValidator, writer),
}
}

func (c *GetPublishableKeyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
ctx, span := telemetry.NewSpan(r.Context(), "get-publishable-key-endpoint")
defer span.End()

proj, _ := ctx.Value(types.ProjectScope).(*models.Project)

// There is no easy way to pass environment variables to the frontend,
// so for now pass via the backend. This is acceptable because the key is
// meant to be public
publishableKey := c.Config().BillingManager.StripeClient.GetPublishableKey(ctx)

telemetry.WithAttributes(span,
telemetry.AttributeKV{Key: "project-id", Value: proj.ID},
telemetry.AttributeKV{Key: "customer-id", Value: proj.BillingID},
)

c.WriteResult(w, r, publishableKey)
}
48 changes: 46 additions & 2 deletions api/server/handlers/billing/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"fmt"
"net/http"

"github.com/google/uuid"
"github.com/porter-dev/porter/api/server/handlers"
"github.com/porter-dev/porter/api/server/shared"
"github.com/porter-dev/porter/api/server/shared/apierrors"
Expand Down Expand Up @@ -39,7 +40,7 @@ func (c *ListBillingHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {

proj, _ := ctx.Value(types.ProjectScope).(*models.Project)

paymentMethods, err := c.Config().BillingManager.ListPaymentMethod(ctx, proj)
paymentMethods, err := c.Config().BillingManager.StripeClient.ListPaymentMethod(ctx, proj.BillingID)
if err != nil {
err := telemetry.Error(ctx, span, err, "error listing payment method")
c.HandleAPIError(w, r, apierrors.NewErrInternal(fmt.Errorf("error listing payment method: %w", err)))
Expand All @@ -64,8 +65,51 @@ func (c *CheckPaymentEnabledHandler) ServeHTTP(w http.ResponseWriter, r *http.Re
defer span.End()

proj, _ := ctx.Value(types.ProjectScope).(*models.Project)
user, _ := ctx.Value(types.UserScope).(*models.User)

paymentEnabled, err := c.Config().BillingManager.CheckPaymentEnabled(ctx, proj)
// Create billing customer for project and set the billing ID if it doesn't exist
var shouldUpdate bool
if proj.BillingID == "" {
billingID, err := c.Config().BillingManager.StripeClient.CreateCustomer(ctx, user.Email, proj.ID, proj.Name)
if err != nil {
err = telemetry.Error(ctx, span, err, "error creating billing customer")
c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
return
}
proj.BillingID = billingID
shouldUpdate = true

telemetry.WithAttributes(span,
telemetry.AttributeKV{Key: "billing-id", Value: proj.BillingID},
)
}

if proj.UsageID == uuid.Nil {
customerID, customerPlanID, err := c.Config().BillingManager.MetronomeClient.CreateCustomerWithPlan(user.CompanyName, proj.Name, proj.ID, proj.BillingID, c.Config().ServerConf.PorterCloudPlanID)
if err != nil {
err = telemetry.Error(ctx, span, err, "error creating Metronome customer")
c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
}
proj.UsageID = customerID
proj.UsagePlanID = customerPlanID
shouldUpdate = true

telemetry.WithAttributes(span,
telemetry.AttributeKV{Key: "usage-id", Value: proj.UsageID},
telemetry.AttributeKV{Key: "usage-plan-id", Value: proj.UsagePlanID},
)
}

if shouldUpdate {
_, err := c.Repo().Project().UpdateProject(proj)
if err != nil {
err := telemetry.Error(ctx, span, err, "error updating project")
c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
return
}
}

paymentEnabled, err := c.Config().BillingManager.StripeClient.CheckPaymentEnabled(ctx, proj.BillingID)
if err != nil {
err := telemetry.Error(ctx, span, err, "error checking if payment enabled")
c.HandleAPIError(w, r, apierrors.NewErrInternal(fmt.Errorf("error checking if payment enabled: %w", err)))
Expand Down
13 changes: 7 additions & 6 deletions api/server/handlers/cluster/install_agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,11 +106,13 @@ func (c *InstallAgentHandler) ServeHTTP(w http.ResponseWriter, r *http.Request)

porterAgentValues := map[string]interface{}{
"agent": map[string]interface{}{
"porterHost": c.Config().ServerConf.ServerURL,
"porterPort": "443",
"porterToken": encoded,
"clusterID": fmt.Sprintf("%d", cluster.ID),
"projectID": fmt.Sprintf("%d", proj.ID),
"porterHost": c.Config().ServerConf.ServerURL,
"porterPort": "443",
"porterToken": encoded,
"clusterID": fmt.Sprintf("%d", cluster.ID),
"projectID": fmt.Sprintf("%d", proj.ID),
"prometheusURL": c.Config().ServerConf.PrometheusUrl,
"metronomeKey": c.Config().ServerConf.MetronomeAPIKey,
},
"loki": map[string]interface{}{},
}
Expand Down Expand Up @@ -185,7 +187,6 @@ func checkAndDeleteOlderAgent(k8sAgent *kubernetes.Agent, helmAgent *helm.Agent)
}

_, err = helmAgent.UninstallChart(context.Background(), "porter-agent")

if err != nil {
return err
}
Expand Down
Loading

0 comments on commit ef7e3fe

Please sign in to comment.