plan.go 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. package billing
  2. import (
  3. "net/http"
  4. "github.com/porter-dev/porter/api/server/handlers"
  5. "github.com/porter-dev/porter/api/server/shared"
  6. "github.com/porter-dev/porter/api/server/shared/apierrors"
  7. "github.com/porter-dev/porter/api/server/shared/config"
  8. "github.com/porter-dev/porter/api/types"
  9. "github.com/porter-dev/porter/internal/models"
  10. "github.com/porter-dev/porter/internal/telemetry"
  11. )
  12. // ListPlansHandler is a handler for getting customer plans
  13. type ListPlansHandler struct {
  14. handlers.PorterHandlerWriter
  15. }
  16. // NewListPlansHandler will create a new ListPlansHandler
  17. func NewListPlansHandler(
  18. config *config.Config,
  19. writer shared.ResultWriter,
  20. ) *ListPlansHandler {
  21. return &ListPlansHandler{
  22. PorterHandlerWriter: handlers.NewDefaultPorterHandler(config, nil, writer),
  23. }
  24. }
  25. func (c *ListPlansHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  26. ctx, span := telemetry.NewSpan(r.Context(), "serve-list-plans")
  27. defer span.End()
  28. proj, _ := ctx.Value(types.ProjectScope).(*models.Project)
  29. telemetry.WithAttributes(span,
  30. telemetry.AttributeKV{Key: "lago-config-exists", Value: c.Config().BillingManager.LagoConfigLoaded},
  31. telemetry.AttributeKV{Key: "lago-enabled", Value: proj.GetFeatureFlag(models.LagoEnabled, c.Config().LaunchDarklyClient)},
  32. )
  33. if !c.Config().BillingManager.LagoConfigLoaded || !proj.GetFeatureFlag(models.LagoEnabled, c.Config().LaunchDarklyClient) {
  34. c.WriteResult(w, r, "")
  35. return
  36. }
  37. plan, err := c.Config().BillingManager.LagoClient.GetCustomeActivePlan(ctx, proj.ID, proj.EnableSandbox)
  38. if err != nil {
  39. err := telemetry.Error(ctx, span, err, "error getting active subscription")
  40. c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
  41. return
  42. }
  43. telemetry.WithAttributes(span,
  44. telemetry.AttributeKV{Key: "subscription_id", Value: plan.ID},
  45. )
  46. c.WriteResult(w, r, plan)
  47. }
  48. // ListCreditsHandler is a handler for getting available credits
  49. type ListCreditsHandler struct {
  50. handlers.PorterHandlerWriter
  51. }
  52. // NewListCreditsHandler will create a new ListCreditsHandler
  53. func NewListCreditsHandler(
  54. config *config.Config,
  55. writer shared.ResultWriter,
  56. ) *ListCreditsHandler {
  57. return &ListCreditsHandler{
  58. PorterHandlerWriter: handlers.NewDefaultPorterHandler(config, nil, writer),
  59. }
  60. }
  61. func (c *ListCreditsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  62. ctx, span := telemetry.NewSpan(r.Context(), "serve-list-credits")
  63. defer span.End()
  64. proj, _ := ctx.Value(types.ProjectScope).(*models.Project)
  65. telemetry.WithAttributes(span,
  66. telemetry.AttributeKV{Key: "lago-config-exists", Value: c.Config().BillingManager.LagoConfigLoaded},
  67. telemetry.AttributeKV{Key: "lago-enabled", Value: proj.GetFeatureFlag(models.LagoEnabled, c.Config().LaunchDarklyClient)},
  68. )
  69. if !c.Config().BillingManager.LagoConfigLoaded || !proj.GetFeatureFlag(models.LagoEnabled, c.Config().LaunchDarklyClient) {
  70. c.WriteResult(w, r, "")
  71. return
  72. }
  73. credits, err := c.Config().BillingManager.LagoClient.ListCustomerCredits(ctx, proj.ID, proj.EnableSandbox)
  74. if err != nil {
  75. err := telemetry.Error(ctx, span, err, "error listing credits")
  76. c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
  77. return
  78. }
  79. c.WriteResult(w, r, credits)
  80. }
  81. // ListCustomerUsageHandler returns customer usage aggregations like CPU and RAM hours.
  82. type ListCustomerUsageHandler struct {
  83. handlers.PorterHandlerReadWriter
  84. }
  85. // NewListCustomerUsageHandler returns a new ListCustomerUsageHandler
  86. func NewListCustomerUsageHandler(
  87. config *config.Config,
  88. decoderValidator shared.RequestDecoderValidator,
  89. writer shared.ResultWriter,
  90. ) *ListCustomerUsageHandler {
  91. return &ListCustomerUsageHandler{
  92. PorterHandlerReadWriter: handlers.NewDefaultPorterHandler(config, decoderValidator, writer),
  93. }
  94. }
  95. func (c *ListCustomerUsageHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  96. ctx, span := telemetry.NewSpan(r.Context(), "serve-list-customer-usage")
  97. defer span.End()
  98. proj, _ := ctx.Value(types.ProjectScope).(*models.Project)
  99. telemetry.WithAttributes(span,
  100. telemetry.AttributeKV{Key: "lago-config-exists", Value: c.Config().BillingManager.LagoConfigLoaded},
  101. telemetry.AttributeKV{Key: "lago-enabled", Value: proj.GetFeatureFlag(models.LagoEnabled, c.Config().LaunchDarklyClient)},
  102. )
  103. if !c.Config().BillingManager.LagoConfigLoaded || !proj.GetFeatureFlag(models.LagoEnabled, c.Config().LaunchDarklyClient) {
  104. c.WriteResult(w, r, "")
  105. return
  106. }
  107. req := &types.ListCustomerUsageRequest{}
  108. if ok := c.DecodeAndValidate(w, r, req); !ok {
  109. err := telemetry.Error(ctx, span, nil, "error decoding list customer usage request")
  110. c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusBadRequest))
  111. return
  112. }
  113. plan, err := c.Config().BillingManager.LagoClient.GetCustomeActivePlan(ctx, proj.ID, proj.EnableSandbox)
  114. if err != nil {
  115. err := telemetry.Error(ctx, span, err, "error getting active subscription")
  116. c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
  117. return
  118. }
  119. telemetry.WithAttributes(span,
  120. telemetry.AttributeKV{Key: "subscription_id", Value: plan.ID},
  121. )
  122. usage, err := c.Config().BillingManager.LagoClient.ListCustomerUsage(ctx, plan.CustomerID, plan.ID, req.CurrentPeriod, req.PreviousPeriods)
  123. if err != nil {
  124. err := telemetry.Error(ctx, span, err, "error listing customer usage")
  125. c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
  126. return
  127. }
  128. c.WriteResult(w, r, usage)
  129. }