cloudcostmatcher.go 2.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. package opencost
  2. import (
  3. "fmt"
  4. "github.com/opencost/opencost/core/pkg/filter/ast"
  5. ccfilter "github.com/opencost/opencost/core/pkg/filter/cloudcost"
  6. "github.com/opencost/opencost/core/pkg/filter/matcher"
  7. "github.com/opencost/opencost/core/pkg/filter/transform"
  8. )
  9. // CloudCostMatcher is a matcher implementation for CloudCost instances,
  10. // compiled using the matcher.MatchCompiler for cloud costs.
  11. type CloudCostMatcher matcher.Matcher[*CloudCost]
  12. // NewCloudCostMatchCompiler creates a new instance of a
  13. // matcher.MatchCompiler[*CloudCost] which can be used to compile filter.Filter
  14. // ASTs into matcher.Matcher[*CloudCost] implementations.
  15. //
  16. // If storage interfaces every support querying natively by alias (e.g. if a
  17. // data store contained a "product" attribute on an CloudCost row), that should
  18. // be handled by a purpose-built AST compiler.
  19. func NewCloudCostMatchCompiler() *matcher.MatchCompiler[*CloudCost] {
  20. passes := []transform.CompilerPass{}
  21. passes = append(passes,
  22. transform.UnallocatedReplacementPass(),
  23. )
  24. return matcher.NewMatchCompiler(
  25. cloudCostFieldMap,
  26. cloudCostSliceFieldMap,
  27. cloudCostMapFieldMap,
  28. passes...,
  29. )
  30. }
  31. // Maps fields from a cloud cost to a string value based on an identifier
  32. func cloudCostFieldMap(cc *CloudCost, identifier ast.Identifier) (string, error) {
  33. if cc == nil {
  34. return "", fmt.Errorf("cannot map to nil cloud cost")
  35. }
  36. if cc.Properties == nil {
  37. return "", fmt.Errorf("cannot map to nil properties")
  38. }
  39. if identifier.Field == nil {
  40. return "", fmt.Errorf("cannot map field from identifier with nil field")
  41. }
  42. switch ccfilter.CloudCostField(identifier.Field.Name) {
  43. case ccfilter.FieldInvoiceEntityID:
  44. return cc.Properties.InvoiceEntityID, nil
  45. case ccfilter.FieldAccountID:
  46. return cc.Properties.AccountID, nil
  47. case ccfilter.FieldProvider:
  48. return cc.Properties.Provider, nil
  49. case ccfilter.FieldProviderID:
  50. return cc.Properties.ProviderID, nil
  51. case ccfilter.FieldCategory:
  52. return cc.Properties.Category, nil
  53. case ccfilter.FieldService:
  54. return cc.Properties.Service, nil
  55. case ccfilter.FieldLabel:
  56. return cc.Properties.Labels[identifier.Key], nil
  57. }
  58. return "", fmt.Errorf("Failed to find string identifier on CloudCost: %s", identifier.Field.Name)
  59. }
  60. // Maps slice fields from an asset to a []string value based on an identifier
  61. func cloudCostSliceFieldMap(cc *CloudCost, identifier ast.Identifier) ([]string, error) {
  62. return nil, fmt.Errorf("Cloud Cost have no slice fields")
  63. }
  64. // Maps map fields from a cloud cost to a map[string]string value based on an identifier
  65. func cloudCostMapFieldMap(cc *CloudCost, identifier ast.Identifier) (map[string]string, error) {
  66. switch ccfilter.CloudCostField(identifier.Field.Name) {
  67. case ccfilter.FieldLabel:
  68. return cc.Properties.Labels, nil
  69. }
  70. return nil, fmt.Errorf("Failed to find map[string]string identifier on CloudCost: %s", identifier.Field.Name)
  71. }