price.go 1012 B

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849
  1. package pricing
  2. import (
  3. "sort"
  4. "strconv"
  5. "strings"
  6. "github.com/opencost/opencost/core/pkg/unit"
  7. )
  8. type Price struct {
  9. Unit unit.Unit `json:"unit" yaml:"unit"`
  10. Price float64 `json:"price" yaml:"price"`
  11. }
  12. type Prices map[Resource]Price
  13. func (p Prices) String() string {
  14. return p.canonical()
  15. }
  16. // canonical returns a deterministic string representation of the prices,
  17. // independent of map iteration order. It is used to make pricing checksums
  18. // sensitive to price values (not just properties).
  19. func (p Prices) canonical() string {
  20. if len(p) == 0 {
  21. return ""
  22. }
  23. resources := make([]string, 0, len(p))
  24. for r := range p {
  25. resources = append(resources, string(r))
  26. }
  27. sort.Strings(resources)
  28. var b strings.Builder
  29. for _, r := range resources {
  30. price := p[Resource(r)]
  31. b.WriteString(r)
  32. b.WriteByte('[')
  33. b.WriteString(string(price.Unit))
  34. b.WriteByte(']')
  35. b.WriteByte('=')
  36. b.WriteString(strconv.FormatFloat(price.Price, 'f', -1, 64))
  37. b.WriteByte(';')
  38. }
  39. return b.String()
  40. }