usage.go 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. package usage
  2. import (
  3. "time"
  4. "github.com/porter-dev/porter/api/server/shared/config/env"
  5. "github.com/porter-dev/porter/internal/adapter"
  6. "github.com/porter-dev/porter/internal/models"
  7. "github.com/porter-dev/porter/internal/oauth"
  8. "github.com/porter-dev/porter/internal/repository"
  9. "github.com/porter-dev/porter/internal/usage"
  10. "golang.org/x/oauth2"
  11. "gorm.io/gorm"
  12. rgorm "github.com/porter-dev/porter/internal/repository/gorm"
  13. )
  14. type UsageTracker struct {
  15. db *gorm.DB
  16. repo repository.Repository
  17. doConf *oauth2.Config
  18. }
  19. type UsageTrackerOpts struct {
  20. DBConf *env.DBConf
  21. DOClientID string
  22. DOClientSecret string
  23. DOScopes []string
  24. ServerURL string
  25. }
  26. const stepSize = 100
  27. func NewUsageTracker(opts *UsageTrackerOpts) (*UsageTracker, error) {
  28. db, err := adapter.New(opts.DBConf)
  29. if err != nil {
  30. return nil, err
  31. }
  32. var key [32]byte
  33. for i, b := range []byte(opts.DBConf.EncryptionKey) {
  34. key[i] = b
  35. }
  36. repo := rgorm.NewRepository(db, &key)
  37. doConf := oauth.NewDigitalOceanClient(&oauth.Config{
  38. ClientID: opts.DOClientID,
  39. ClientSecret: opts.DOClientSecret,
  40. Scopes: opts.DOScopes,
  41. BaseURL: opts.ServerURL,
  42. })
  43. return &UsageTracker{db, repo, doConf}, nil
  44. }
  45. type UsageTrackerResponse struct {
  46. ResourceCPU uint
  47. ResourceMemory uint
  48. Exceeded bool
  49. ExceededSince *time.Time
  50. Project *models.Project
  51. }
  52. func (u *UsageTracker) GetProjectUsage() (map[uint]*UsageTrackerResponse, error) {
  53. res := make(map[uint]*UsageTrackerResponse)
  54. // get the count of the projects
  55. var count int64
  56. if err := u.db.Model(&models.Project{}).Count(&count).Error; err != nil {
  57. return nil, err
  58. }
  59. // iterate (count / stepSize) + 1 times using Limit and Offset
  60. for i := 0; i < (int(count)/stepSize)+1; i++ {
  61. projects := []*models.Project{}
  62. if err := u.db.Order("id asc").Offset(i * stepSize).Limit(stepSize).Find(&projects).Error; err != nil {
  63. return nil, err
  64. }
  65. // go through each project
  66. for _, project := range projects {
  67. _, _, cache, err := usage.GetUsage(&usage.GetUsageOpts{
  68. Repo: u.repo,
  69. DOConf: u.doConf,
  70. Project: project,
  71. })
  72. if err != nil {
  73. continue
  74. }
  75. res[project.ID] = &UsageTrackerResponse{
  76. ResourceCPU: cache.ResourceCPU,
  77. ResourceMemory: cache.ResourceMemory,
  78. Exceeded: cache.Exceeded,
  79. ExceededSince: cache.ExceededSince,
  80. Project: project,
  81. }
  82. }
  83. }
  84. return res, nil
  85. }