Jelajahi Sumber

Add AllocationFilter support for services contains

Existing allocation filtering allows users to filterServices=a,b,c which
becomes a "slice contains" operation because Properties.Services is a
[]string. This commit adds FilterServices (Field) and FilterContains(Op)
to support this type of filter.

Unallocated behavior is based on existing GetServiceFilterFunc (in KCM).
Michael Dresser 4 tahun lalu
induk
melakukan
b2b32c98d0
2 mengubah file dengan 81 tambahan dan 1 penghapusan
  1. 21 1
      pkg/kubecost/allocationfilter.go
  2. 60 0
      pkg/kubecost/allocationfilter_test.go

+ 21 - 1
pkg/kubecost/allocationfilter.go

@@ -24,6 +24,8 @@ const (
 
 	FilterLabel      = "label"
 	FilterAnnotation = "annotation"
+
+	FilterServices = "services"
 )
 
 // FilterOp is an enum that represents operations that can be performed
@@ -35,6 +37,7 @@ type FilterOp string
 const (
 	FilterEquals    FilterOp = "equals"
 	FilterNotEquals          = "notequals"
+	FilterContains           = "contains"
 )
 
 // AllocationFilter represents anything that can be used to filter an
@@ -94,7 +97,8 @@ func (filter AllocationFilterCondition) Matches(a *Allocation) bool {
 	}
 
 	// The Allocation's value for the field to compare
-	var valueToCompare string
+	// We use an interface{} so this can contain the services []string slice
+	var valueToCompare interface{}
 
 	// toCompareMissing will be true if the value to be compared is missing in
 	// the Allocation. For example, if we're filtering based on the value of
@@ -136,6 +140,8 @@ func (filter AllocationFilterCondition) Matches(a *Allocation) bool {
 		} else {
 			valueToCompare = val
 		}
+	case FilterServices:
+		valueToCompare = a.Properties.Services
 	default:
 		log.Errorf("Allocation Filter: Unhandled filter field. This is a filter implementation error and requires immediate patching. Field: %s", filter.Field)
 		return false
@@ -169,6 +175,20 @@ func (filter AllocationFilterCondition) Matches(a *Allocation) bool {
 		if valueToCompare != filter.Value {
 			return true
 		}
+	case FilterContains:
+		if stringSlice, ok := valueToCompare.([]string); ok {
+			if len(stringSlice) == 0 {
+				return filter.Value == UnallocatedSuffix
+			}
+
+			for _, s := range stringSlice {
+				if s == filter.Value {
+					return true
+				}
+			}
+		} else {
+			log.Warnf("Allocation Filter: invalid 'contains' call for non-list filter value")
+		}
 	default:
 		log.Errorf("Allocation Filter: Unhandled filter op. This is a filter implementation error and requires immediate patching. Op: %s", filter.Op)
 		return false

+ 60 - 0
pkg/kubecost/allocationfilter_test.go

@@ -319,6 +319,66 @@ func Test_AllocationFilterCondition_Matches(t *testing.T) {
 				Value: UnallocatedSuffix,
 			},
 
+			expected: true,
+		},
+		{
+			name: `services contains -> true`,
+			a: &Allocation{
+				Properties: &AllocationProperties{
+					Services: []string{"serv1", "serv2"},
+				},
+			},
+			filter: AllocationFilterCondition{
+				Field: FilterServices,
+				Op:    FilterContains,
+				Value: "serv2",
+			},
+
+			expected: true,
+		},
+		{
+			name: `services contains -> false`,
+			a: &Allocation{
+				Properties: &AllocationProperties{
+					Services: []string{"serv1", "serv2"},
+				},
+			},
+			filter: AllocationFilterCondition{
+				Field: FilterServices,
+				Op:    FilterContains,
+				Value: "serv3",
+			},
+
+			expected: false,
+		},
+		{
+			name: `services contains unallocated -> false`,
+			a: &Allocation{
+				Properties: &AllocationProperties{
+					Services: []string{"serv1", "serv2"},
+				},
+			},
+			filter: AllocationFilterCondition{
+				Field: FilterServices,
+				Op:    FilterContains,
+				Value: UnallocatedSuffix,
+			},
+
+			expected: false,
+		},
+		{
+			name: `services contains unallocated -> true`,
+			a: &Allocation{
+				Properties: &AllocationProperties{
+					Services: []string{},
+				},
+			},
+			filter: AllocationFilterCondition{
+				Field: FilterServices,
+				Op:    FilterContains,
+				Value: UnallocatedSuffix,
+			},
+
 			expected: true,
 		},
 	}