usage.go 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  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. CPULimit uint
  47. CPUUsage uint
  48. MemoryLimit uint
  49. MemoryUsage uint
  50. Exceeded bool
  51. ExceededSince *time.Time
  52. Project *models.Project
  53. }
  54. func (u *UsageTracker) GetProjectUsage() (map[uint]*UsageTrackerResponse, error) {
  55. res := make(map[uint]*UsageTrackerResponse)
  56. // get the count of the projects
  57. var count int64
  58. if err := u.db.Model(&models.Project{}).Count(&count).Error; err != nil {
  59. return nil, err
  60. }
  61. // iterate (count / stepSize) + 1 times using Limit and Offset
  62. for i := 0; i < (int(count)/stepSize)+1; i++ {
  63. projects := []*models.Project{}
  64. if err := u.db.Order("id asc").Offset(i * stepSize).Limit(stepSize).Find(&projects).Error; err != nil {
  65. return nil, err
  66. }
  67. // go through each project
  68. for _, project := range projects {
  69. _, limit, cache, err := usage.GetUsage(&usage.GetUsageOpts{
  70. Repo: u.repo,
  71. DOConf: u.doConf,
  72. Project: project,
  73. })
  74. if err != nil {
  75. continue
  76. }
  77. res[project.ID] = &UsageTrackerResponse{
  78. CPUUsage: cache.ResourceCPU,
  79. CPULimit: limit.ResourceCPU,
  80. MemoryUsage: cache.ResourceMemory,
  81. MemoryLimit: limit.ResourceMemory,
  82. Exceeded: cache.Exceeded,
  83. ExceededSince: cache.ExceededSince,
  84. Project: project,
  85. }
  86. }
  87. }
  88. return res, nil
  89. }