Просмотр исходного кода

Filters v2: Full support for filter fields

Expanded enums and Matches() for:
- Node
- Controller kind
- Controller name
- Pod
- Container
- Annotations
Michael Dresser 4 лет назад
Родитель
Сommit
8bc047368e
2 измененных файлов с 127 добавлено и 5 удалено
  1. 34 5
      pkg/kubecost/allocationfilter.go
  2. 93 0
      pkg/kubecost/allocationfilter_test.go

+ 34 - 5
pkg/kubecost/allocationfilter.go

@@ -4,22 +4,32 @@ package kubecost
 // that can be filtered on (namespace, label, etc.)
 type FilterField int
 
+// If you add a FilterField, MAKE SURE TO UPDATE ALL FILTER IMPLEMENTATIONS! Go
+// does not enforce exhaustive pattern matching on "enum" types.
 const (
 	FilterClusterID FilterField = iota
+	FilterNode
 	FilterNamespace
-	// ControllerKind
-	// ControllerName
-	// Pod
-	// Container
+	FilterControllerKind
+	FilterControllerName
+	FilterPod
+	FilterContainer
+
+	// Filtering based on label aliases (team, department, etc.) should be a
+	// responsibility of the query handler. By the time it reaches this
+	// structured representation, we shouldn't have to be aware of what is
+	// aliased to what.
 
 	FilterLabel
-	// Annotation
+	FilterAnnotation
 )
 
 // FilterOp is an enum that represents operations that can be performed
 // when filtering (equality, inequality, etc.)
 type FilterOp int
 
+// If you add a FilterOp, MAKE SURE TO UPDATE ALL FILTER IMPLEMENTATIONS! Go
+// does not enforce exhaustive pattern matching on "enum" types.
 const (
 	FilterEquals FilterOp = iota
 
@@ -91,8 +101,18 @@ func (filter AllocationFilterCondition) Matches(a *Allocation) bool {
 	switch filter.Field {
 	case FilterClusterID:
 		valueToCompare = a.Properties.Cluster
+	case FilterNode:
+		valueToCompare = a.Properties.Node
 	case FilterNamespace:
 		valueToCompare = a.Properties.Namespace
+	case FilterControllerKind:
+		valueToCompare = a.Properties.ControllerKind
+	case FilterControllerName:
+		valueToCompare = a.Properties.Controller
+	case FilterPod:
+		valueToCompare = a.Properties.Pod
+	case FilterContainer:
+		valueToCompare = a.Properties.Container
 	// Comes from GetAnnotation/LabelFilterFunc in KCM
 	case FilterLabel:
 		val, ok := a.Properties.Labels[filter.Key]
@@ -102,6 +122,15 @@ func (filter AllocationFilterCondition) Matches(a *Allocation) bool {
 			return false
 		}
 
+		valueToCompare = val
+	case FilterAnnotation:
+		val, ok := a.Properties.Annotations[filter.Key]
+
+		// TODO: What about annotation != ?
+		if !ok {
+			return false
+		}
+
 		valueToCompare = val
 	default:
 		// TODO: log an error here? this should never happen

+ 93 - 0
pkg/kubecost/allocationfilter_test.go

@@ -27,6 +27,21 @@ func Test_AllocationFilterCondition_Matches(t *testing.T) {
 
 			expected: true,
 		},
+		{
+			name: "Node Equals -> true",
+			a: &Allocation{
+				Properties: &AllocationProperties{
+					Node: "node123",
+				},
+			},
+			filter: AllocationFilterCondition{
+				Field: FilterNode,
+				Op:    FilterEquals,
+				Value: "node123",
+			},
+
+			expected: true,
+		},
 		{
 			name: "Namespace NotEquals -> false",
 			a: &Allocation{
@@ -42,6 +57,66 @@ func Test_AllocationFilterCondition_Matches(t *testing.T) {
 
 			expected: false,
 		},
+		{
+			name: "ControllerKind Equals -> true",
+			a: &Allocation{
+				Properties: &AllocationProperties{
+					ControllerKind: "deployment", // We generally store controller kinds as all lowercase
+				},
+			},
+			filter: AllocationFilterCondition{
+				Field: FilterControllerKind,
+				Op:    FilterEquals,
+				Value: "deployment",
+			},
+
+			expected: true,
+		},
+		{
+			name: "ControllerName Equals -> true",
+			a: &Allocation{
+				Properties: &AllocationProperties{
+					Controller: "kc-cost-analyzer",
+				},
+			},
+			filter: AllocationFilterCondition{
+				Field: FilterControllerName,
+				Op:    FilterEquals,
+				Value: "kc-cost-analyzer",
+			},
+
+			expected: true,
+		},
+		{
+			name: "Pod (with UID) Equals -> true",
+			a: &Allocation{
+				Properties: &AllocationProperties{
+					Pod: "pod-123 UID-ABC",
+				},
+			},
+			filter: AllocationFilterCondition{
+				Field: FilterPod,
+				Op:    FilterEquals,
+				Value: "pod-123 UID-ABC",
+			},
+
+			expected: true,
+		},
+		{
+			name: "Container Equals -> true",
+			a: &Allocation{
+				Properties: &AllocationProperties{
+					Container: "cost-model",
+				},
+			},
+			filter: AllocationFilterCondition{
+				Field: FilterContainer,
+				Op:    FilterEquals,
+				Value: "cost-model",
+			},
+
+			expected: true,
+		},
 		{
 			name: `label[app]="foo" -> true`,
 			a: &Allocation{
@@ -60,6 +135,24 @@ func Test_AllocationFilterCondition_Matches(t *testing.T) {
 
 			expected: true,
 		},
+		{
+			name: `annotation[prom_modified_name]="testing123" -> true`,
+			a: &Allocation{
+				Properties: &AllocationProperties{
+					Annotations: map[string]string{
+						"prom_modified_name": "testing123",
+					},
+				},
+			},
+			filter: AllocationFilterCondition{
+				Field: FilterAnnotation,
+				Op:    FilterEquals,
+				Key:   "prom_modified_name",
+				Value: "testing123",
+			},
+
+			expected: true,
+		},
 		{
 			name: `namespace unallocated -> true`,
 			a: &Allocation{