module.go 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. package usd
  2. import (
  3. "context"
  4. "embed"
  5. "fmt"
  6. "io"
  7. "github.com/opencost/opencost/core/pkg/pricing"
  8. "github.com/opencost/opencost/core/pkg/reader"
  9. "github.com/opencost/opencost/core/pkg/unit"
  10. )
  11. // PricingModule must satisfy the pricing.PricingModule interface
  12. var _ pricing.PricingModule = (*PricingModule)(nil)
  13. //go:embed *.jsonl
  14. var embeddedFS embed.FS
  15. type PricingModule struct{}
  16. // NewPricingModule creates a new USD pricing module backed by embedded JSONL files.
  17. func NewPricingModule() (*PricingModule, error) {
  18. return &PricingModule{}, nil
  19. }
  20. func (pm *PricingModule) newNodeReader() (reader.Reader[*pricing.NodePricing], error) {
  21. f, err := embeddedFS.Open("nodes.jsonl")
  22. if err != nil {
  23. return nil, fmt.Errorf("opening embedded nodes.jsonl: %w", err)
  24. }
  25. return reader.NewJSONLinesReader[*pricing.NodePricing](f), nil
  26. }
  27. func (pm *PricingModule) newPVReader() (reader.Reader[*pricing.PersistentVolumePricing], error) {
  28. f, err := embeddedFS.Open("persistentvolumes.jsonl")
  29. if err != nil {
  30. return nil, fmt.Errorf("opening embedded persistentvolumes.jsonl: %w", err)
  31. }
  32. return reader.NewJSONLinesReader[*pricing.PersistentVolumePricing](f), nil
  33. }
  34. func (pm *PricingModule) NewNodePricingReader(ctx context.Context) (reader.Reader[*pricing.NodePricing], error) {
  35. return pm.newNodeReader()
  36. }
  37. func (pm *PricingModule) NewPersistentVolumePricingReader(ctx context.Context) (reader.Reader[*pricing.PersistentVolumePricing], error) {
  38. return pm.newPVReader()
  39. }
  40. func (pm *PricingModule) NewClusterPricingReader(ctx context.Context) (reader.Reader[*pricing.ClusterPricing], error) {
  41. return nil, fmt.Errorf("cluster pricing not yet implemented")
  42. }
  43. func (pm *PricingModule) NewNetworkPricingReader(ctx context.Context) (reader.Reader[*pricing.NetworkPricing], error) {
  44. return nil, fmt.Errorf("network pricing not yet implemented")
  45. }
  46. func (pm *PricingModule) NewServicePricingReader(ctx context.Context) (reader.Reader[*pricing.ServicePricing], error) {
  47. return nil, fmt.Errorf("service pricing not yet implemented")
  48. }
  49. func (pm *PricingModule) GetPricingSet(ctx context.Context) (*pricing.PricingSet, error) {
  50. ps := &pricing.PricingSet{}
  51. nodeReader, err := pm.newNodeReader()
  52. if err != nil {
  53. return nil, err
  54. }
  55. defer nodeReader.Close()
  56. dst := make([]*pricing.NodePricing, 64)
  57. for {
  58. n, err := nodeReader.Read(ctx, dst)
  59. ps.NodePricing = append(ps.NodePricing, dst[:n]...)
  60. if err == io.EOF {
  61. break
  62. }
  63. if err != nil {
  64. return nil, err
  65. }
  66. }
  67. pvReader, err := pm.newPVReader()
  68. if err != nil {
  69. return nil, err
  70. }
  71. defer pvReader.Close()
  72. pvDst := make([]*pricing.PersistentVolumePricing, 64)
  73. for {
  74. n, err := pvReader.Read(ctx, pvDst)
  75. ps.PersistentVolumePricing = append(ps.PersistentVolumePricing, pvDst[:n]...)
  76. if err == io.EOF {
  77. break
  78. }
  79. if err != nil {
  80. return nil, err
  81. }
  82. }
  83. return ps, nil
  84. }
  85. func (pm *PricingModule) SourceKind() string {
  86. return "public"
  87. }
  88. func (pm *PricingModule) SourceName() string {
  89. return "public-usd"
  90. }
  91. func (pm *PricingModule) Checksum(ctx context.Context) (string, error) {
  92. ps, err := pm.GetPricingSet(ctx)
  93. if err != nil {
  94. return "", err
  95. }
  96. return ps.Checksum()
  97. }
  98. // Currency returns USD
  99. func Currency() unit.Currency {
  100. return unit.USD
  101. }