nodematcher.go 2.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. package opencost
  2. import (
  3. "fmt"
  4. "github.com/opencost/opencost/core/pkg/filter/ast"
  5. "github.com/opencost/opencost/core/pkg/filter/matcher"
  6. nfilter "github.com/opencost/opencost/core/pkg/filter/node"
  7. "github.com/opencost/opencost/core/pkg/filter/transform"
  8. )
  9. // NodeMatcher is a matcher implementation for Node instances,
  10. // compiled using the matcher.MatchCompiler.
  11. type NodeMatcher matcher.Matcher[*Node]
  12. // NewNodeMatchCompiler creates a new instance of a
  13. // matcher.MatchCompiler[Node] which can be used to compile filter.Filter
  14. // ASTs into matcher.Matcher[Node] implementations.
  15. //
  16. // If the label config is nil, the compiler will fail to compile alias filters
  17. // if any are present in the AST.
  18. func NewNodeMatchCompiler() *matcher.MatchCompiler[*Node] {
  19. passes := []transform.CompilerPass{}
  20. passes = append(passes,
  21. transform.PrometheusKeySanitizePass(),
  22. transform.UnallocatedReplacementPass(),
  23. )
  24. return matcher.NewMatchCompiler(
  25. nodeFieldMap,
  26. nodeSliceFieldMap,
  27. nodeMapFieldMap,
  28. passes...,
  29. )
  30. }
  31. // Maps fields from an asset to a string value based on an identifier
  32. func nodeFieldMap(n *Node, identifier ast.Identifier) (string, error) {
  33. if identifier.Field == nil {
  34. return "", fmt.Errorf("cannot map field from identifier with nil field")
  35. }
  36. if n == nil {
  37. return "", fmt.Errorf("cannot map field for nil Node")
  38. }
  39. // Check special fields before defaulting to properties-based fields
  40. switch nfilter.NodeField(identifier.Field.Name) {
  41. case nfilter.FieldLabel:
  42. labels := n.GetLabels()
  43. if labels == nil {
  44. return "", nil
  45. }
  46. return labels[identifier.Key], nil
  47. }
  48. props := n.GetProperties()
  49. if props == nil {
  50. return "", fmt.Errorf("cannot map field for Node with nil props")
  51. }
  52. switch nfilter.NodeField(identifier.Field.Name) {
  53. case nfilter.FieldName:
  54. return props.Name, nil
  55. case nfilter.FieldNodeType:
  56. return n.NodeType, nil
  57. case nfilter.FieldClusterID:
  58. return props.Cluster, nil
  59. case nfilter.FieldProvider:
  60. return props.Provider, nil
  61. case nfilter.FieldProviderID:
  62. return props.ProviderID, nil
  63. }
  64. return "", fmt.Errorf("Failed to find string identifier on Node: %s", identifier.Field.Name)
  65. }
  66. // Maps slice fields from an asset to a []string value based on an identifier
  67. func nodeSliceFieldMap(n *Node, identifier ast.Identifier) ([]string, error) {
  68. return nil, fmt.Errorf("Nodes have no slice fields")
  69. }
  70. // Maps map fields from an Node to a map[string]string value based on an identifier
  71. func nodeMapFieldMap(n *Node, identifier ast.Identifier) (map[string]string, error) {
  72. if n == nil {
  73. return nil, fmt.Errorf("cannot get map field for nil Node")
  74. }
  75. switch nfilter.NodeField(identifier.Field.Name) {
  76. case nfilter.FieldLabel:
  77. return n.GetLabels(), nil
  78. }
  79. return nil, fmt.Errorf("Failed to find map[string]string identifier on Node: %s", identifier.Field.Name)
  80. }