ソースを参照

Resource Quota filters (#3481)

Niko Kovacevic 5 ヶ月 前
コミット
13cdac689c

+ 1 - 0
core/pkg/filter/allocation/fields.go

@@ -15,6 +15,7 @@ const (
 	FieldClusterID      AllocationField = AllocationField(fieldstrings.FieldClusterID)
 	FieldNode           AllocationField = AllocationField(fieldstrings.FieldNode)
 	FieldNamespace      AllocationField = AllocationField(fieldstrings.FieldNamespace)
+	FieldNamespaceLabel AllocationField = AllocationField(fieldstrings.FieldNamespaceLabel)
 	FieldControllerKind AllocationField = AllocationField(fieldstrings.FieldControllerKind)
 	FieldControllerName AllocationField = AllocationField(fieldstrings.FieldControllerName)
 	FieldPod            AllocationField = AllocationField(fieldstrings.FieldPod)

+ 1 - 0
core/pkg/filter/allocation/parser.go

@@ -22,6 +22,7 @@ var allocationFilterFields []*ast.Field = []*ast.Field{
 	ast.NewMapField(FieldLabel),
 	ast.NewMapField(FieldAnnotation),
 	ast.NewMapField(FieldNodeLabel),
+	ast.NewMapField(FieldNamespaceLabel),
 }
 
 // fieldMap is a lazily loaded mapping from AllocationField to ast.Field

+ 4 - 0
core/pkg/filter/allocation/parser_test.go

@@ -26,6 +26,10 @@ func TestParse(t *testing.T) {
 			name:  "Single",
 			input: `namespace: "kubecost"`,
 		},
+		{
+			name:  "Single: namespace label",
+			input: `namespaceLabel[app]:"kubecost"`,
+		},
 		{
 			name:  "Single Group",
 			input: `(namespace: "kubecost")`,

+ 6 - 0
core/pkg/filter/fieldstrings/fieldstrings.go

@@ -3,7 +3,10 @@ package fieldstrings
 // These strings are the central source of filter fields across all types of
 // filters. Many filter types share fields; defining common consts means that
 // there should be no drift between types.
+// filter=uid:"1234-5678"
 const (
+	FieldUID string = "uid"
+
 	FieldClusterID      string = "cluster"
 	FieldNode           string = "node"
 	FieldNamespace      string = "namespace"
@@ -16,6 +19,9 @@ const (
 	FieldLabel          string = "label"
 	FieldAnnotation     string = "annotation"
 	FieldNodeLabel      string = "nodeLabel"
+	FieldNamespaceLabel string = "namespaceLabel"
+
+	FieldResourceQuota string = "resourcequota"
 
 	FieldName       string = "name"
 	FieldType       string = "assetType"

+ 17 - 0
core/pkg/filter/resourcequota/fields.go

@@ -0,0 +1,17 @@
+package resourcequota
+
+import (
+	"github.com/opencost/opencost/core/pkg/filter/fieldstrings"
+)
+
+type ResourceQuotaField string
+
+// If you add a ResourceQuotaField, make sure to update field maps to return the correct
+// Asset value does not enforce exhaustive pattern matching on "enum" types.
+const (
+	FieldClusterID      ResourceQuotaField = ResourceQuotaField(fieldstrings.FieldClusterID)
+	FieldResourceQuota  ResourceQuotaField = ResourceQuotaField(fieldstrings.FieldResourceQuota)
+	FieldNamespace      ResourceQuotaField = ResourceQuotaField(fieldstrings.FieldNamespace)
+	FieldNamespaceLabel ResourceQuotaField = ResourceQuotaField(fieldstrings.FieldNamespaceLabel)
+	FieldUID            ResourceQuotaField = ResourceQuotaField(fieldstrings.FieldUID)
+)

+ 38 - 0
core/pkg/filter/resourcequota/parser.go

@@ -0,0 +1,38 @@
+package resourcequota
+
+import "github.com/opencost/opencost/core/pkg/filter/ast"
+
+var resourceQuotaFilterFields []*ast.Field = []*ast.Field{
+	ast.NewField(FieldClusterID),
+	ast.NewField(FieldResourceQuota),
+	ast.NewField(FieldNamespace),
+	ast.NewMapField(FieldNamespaceLabel),
+	ast.NewField(FieldUID),
+}
+
+// fieldMap is a lazily loaded mapping from ResourceQuotaField to ast.Field
+var fieldMap map[ResourceQuotaField]*ast.Field
+
+func init() {
+	fieldMap = make(map[ResourceQuotaField]*ast.Field, len(resourceQuotaFilterFields))
+	for _, f := range resourceQuotaFilterFields {
+		ff := *f
+		fieldMap[ResourceQuotaField(ff.Name)] = &ff
+	}
+}
+
+// DefaultFieldByName returns only default resource quota filter fields by name.
+func DefaultFieldByName(field ResourceQuotaField) *ast.Field {
+	if af, ok := fieldMap[field]; ok {
+		afcopy := *af
+		return &afcopy
+	}
+
+	return nil
+}
+
+// NewResourceQuotaFilterParser creates a new `ast.FilterParser` implementation
+// which uses resource quota specific fields
+func NewResourceQuotaFilterParser() ast.FilterParser {
+	return ast.NewFilterParser(resourceQuotaFilterFields)
+}

+ 43 - 0
core/pkg/filter/resourcequota/parser_test.go

@@ -0,0 +1,43 @@
+package resourcequota
+
+import (
+	"testing"
+
+	"github.com/opencost/opencost/core/pkg/filter/ast"
+)
+
+func TestDefaultFieldByName(t *testing.T) {
+	var rqField ResourceQuotaField
+	var astf *ast.Field
+
+	rqField = FieldResourceQuota
+	astf = DefaultFieldByName(rqField)
+	if astf.Name != "resourcequota" {
+		t.Errorf("expected %s; received %s", "resourcequota", astf.Name)
+	}
+
+	rqField = FieldClusterID
+	astf = DefaultFieldByName(rqField)
+	if astf.Name != "cluster" {
+		t.Errorf("expected %s; received %s", "cluster", astf.Name)
+	}
+
+	rqField = FieldNamespace
+	astf = DefaultFieldByName(rqField)
+	if astf.Name != "namespace" {
+		t.Errorf("expected %s; received %s", "namespace", astf.Name)
+	}
+
+	rqField = FieldNamespaceLabel
+	astf = DefaultFieldByName(rqField)
+	if astf.Name != "namespaceLabel" {
+		t.Errorf("expected %s; received %s", "namespaceLabel", astf.Name)
+	}
+
+	rqField = FieldUID
+	astf = DefaultFieldByName(rqField)
+	if astf.Name != "uid" {
+		t.Errorf("expected %s; received %s", "uid", astf.Name)
+	}
+
+}

+ 1 - 0
core/pkg/opencost/allocationprops.go

@@ -85,6 +85,7 @@ const (
 	AllocationServiceProp                           = "service"
 	AllocationLabelProp                             = "label"
 	AllocationAnnotationProp                        = "annotation"
+	AllocationNamespaceLabelProp                    = "namespaceLabel"
 	AllocationDeploymentProp                        = "deployment"
 	AllocationStatefulSetProp                       = "statefulset"
 	AllocationDaemonSetProp                         = "daemonset"