stringmapproperty.go 2.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. package filter
  2. import (
  3. "fmt"
  4. "strings"
  5. "github.com/opencost/opencost/pkg/log"
  6. )
  7. const unallocatedSuffix = "__unallocated__"
  8. type StringMapPropertied interface {
  9. StringMapProperty(string) (map[string]string, error)
  10. }
  11. // StringMapOperation is an enum that represents operations that can be performed
  12. // when filtering (equality, inequality, etc.)
  13. type StringMapOperation string
  14. const (
  15. // StringMapHasKey passes if the map has the provided key
  16. StringMapHasKey StringMapOperation = "stringmapcontains"
  17. StringMapStartsWith = "stringmapstartswith"
  18. // StringMapEquals when the given key and value match
  19. StringMapEquals = "stringmapequals"
  20. )
  21. // StringMapProperty is the lowest-level type of filter. It represents
  22. // a filter operation (equality, inequality, etc.) on a property that contains a string map
  23. type StringMapProperty[T StringMapPropertied] struct {
  24. Field string
  25. Op StringMapOperation
  26. Key string
  27. Value string
  28. }
  29. func (smp StringMapProperty[T]) String() string {
  30. return fmt.Sprintf(`(%s %s[%s] "%s")`, smp.Op, smp.Field, smp.Key, smp.Value)
  31. }
  32. func (smp StringMapProperty[T]) Matches(that T) bool {
  33. thatMap, err := that.StringMapProperty(smp.Field)
  34. if err != nil {
  35. log.Errorf("Filter: StringMapProperty: could not retrieve field %s: %s", smp.Field, err.Error())
  36. return false
  37. }
  38. valueToCompare, keyIsPresent := thatMap[smp.Key]
  39. switch smp.Op {
  40. case StringMapHasKey:
  41. return keyIsPresent
  42. case StringMapEquals:
  43. // namespace:"__unallocated__" should match a.Properties.Namespace = ""
  44. // label[app]:"__unallocated__" should match _, ok := Labels[app]; !ok
  45. if !keyIsPresent || valueToCompare == "" {
  46. return smp.Value == unallocatedSuffix
  47. }
  48. if valueToCompare == smp.Value {
  49. return true
  50. }
  51. case StringMapStartsWith:
  52. if !keyIsPresent {
  53. return false
  54. }
  55. // We don't need special __unallocated__ logic here because a query
  56. // asking for "__unallocated__" won't have a wildcard and unallocated
  57. // properties are the empty string.
  58. return strings.HasPrefix(valueToCompare, smp.Value)
  59. default:
  60. log.Errorf("Filter: StringMapProperty: Unhandled filter op. This is a filter implementation error and requires immediate patching. Op: %s", smp.Op)
  61. return false
  62. }
  63. return false
  64. }