mirror of https://github.com/grafana/grafana.git
Scopes: Remove all duplicated types for single source of truth (#112100)
* apimachinery: Remove unused scope types * tsdb/loki: use scope types from apps/scope * promlib: use scope types from apps/scope
This commit is contained in:
parent
f4cd46504b
commit
3ad54c0c1e
|
|
@ -42,46 +42,3 @@ func (r ObjectReference) ToOwnerReference() metav1.OwnerReference {
|
|||
UID: r.UID,
|
||||
}
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
type Scope struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||
|
||||
Spec ScopeSpec `json:"spec,omitempty"`
|
||||
}
|
||||
|
||||
type ScopeSpec struct {
|
||||
Title string `json:"title"`
|
||||
// Provides a default path for the scope. This refers to a list of nodes in the selector. This is used to display the title next to the selected scope and expand the selector to the proper path.
|
||||
// This will override whichever is selected from in the selector.
|
||||
// The path is a list of node ids, starting at the direct parent of the selected node towards the root.
|
||||
// +listType=atomic
|
||||
DefaultPath []string `json:"defaultPath,omitempty"`
|
||||
|
||||
// +listType=atomic
|
||||
Filters []ScopeFilter `json:"filters,omitempty"`
|
||||
}
|
||||
|
||||
type ScopeFilter struct {
|
||||
Key string `json:"key"`
|
||||
Value string `json:"value"`
|
||||
// Values is used for operators that require multiple values (e.g. one-of and not-one-of).
|
||||
// +listType=atomic
|
||||
Values []string `json:"values,omitempty"`
|
||||
Operator FilterOperator `json:"operator"`
|
||||
}
|
||||
|
||||
// Type of the filter operator.
|
||||
// +enum
|
||||
type FilterOperator string
|
||||
|
||||
// Defines values for FilterOperator.
|
||||
const (
|
||||
FilterOperatorEquals FilterOperator = "equals"
|
||||
FilterOperatorNotEquals FilterOperator = "not-equals"
|
||||
FilterOperatorRegexMatch FilterOperator = "regex-match"
|
||||
FilterOperatorRegexNotMatch FilterOperator = "regex-not-match"
|
||||
FilterOperatorOneOf FilterOperator = "one-of"
|
||||
FilterOperatorNotOneOf FilterOperator = "not-one-of"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -7,10 +7,6 @@
|
|||
|
||||
package v0alpha1
|
||||
|
||||
import (
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *InlineSecureValue) DeepCopyInto(out *InlineSecureValue) {
|
||||
*out = *in
|
||||
|
|
@ -42,79 +38,3 @@ func (in *ObjectReference) DeepCopy() *ObjectReference {
|
|||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Scope) DeepCopyInto(out *Scope) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||
in.Spec.DeepCopyInto(&out.Spec)
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Scope.
|
||||
func (in *Scope) DeepCopy() *Scope {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(Scope)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *Scope) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ScopeFilter) DeepCopyInto(out *ScopeFilter) {
|
||||
*out = *in
|
||||
if in.Values != nil {
|
||||
in, out := &in.Values, &out.Values
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ScopeFilter.
|
||||
func (in *ScopeFilter) DeepCopy() *ScopeFilter {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ScopeFilter)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ScopeSpec) DeepCopyInto(out *ScopeSpec) {
|
||||
*out = *in
|
||||
if in.DefaultPath != nil {
|
||||
in, out := &in.DefaultPath, &out.DefaultPath
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.Filters != nil {
|
||||
in, out := &in.Filters, &out.Filters
|
||||
*out = make([]ScopeFilter, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ScopeSpec.
|
||||
func (in *ScopeSpec) DeepCopy() *ScopeSpec {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ScopeSpec)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,9 +17,6 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA
|
|||
return map[string]common.OpenAPIDefinition{
|
||||
"github.com/grafana/grafana/pkg/apimachinery/apis/common/v0alpha1.InlineSecureValue": InlineSecureValue{}.OpenAPIDefinition(),
|
||||
"github.com/grafana/grafana/pkg/apimachinery/apis/common/v0alpha1.ObjectReference": schema_apimachinery_apis_common_v0alpha1_ObjectReference(ref),
|
||||
"github.com/grafana/grafana/pkg/apimachinery/apis/common/v0alpha1.Scope": schema_apimachinery_apis_common_v0alpha1_Scope(ref),
|
||||
"github.com/grafana/grafana/pkg/apimachinery/apis/common/v0alpha1.ScopeFilter": schema_apimachinery_apis_common_v0alpha1_ScopeFilter(ref),
|
||||
"github.com/grafana/grafana/pkg/apimachinery/apis/common/v0alpha1.ScopeSpec": schema_apimachinery_apis_common_v0alpha1_ScopeSpec(ref),
|
||||
"github.com/grafana/grafana/pkg/apimachinery/apis/common/v0alpha1.Unstructured": Unstructured{}.OpenAPIDefinition(),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.APIGroup": schema_pkg_apis_meta_v1_APIGroup(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.APIGroupList": schema_pkg_apis_meta_v1_APIGroupList(ref),
|
||||
|
|
@ -139,162 +136,6 @@ func schema_apimachinery_apis_common_v0alpha1_ObjectReference(ref common.Referen
|
|||
}
|
||||
}
|
||||
|
||||
func schema_apimachinery_apis_common_v0alpha1_Scope(ref common.ReferenceCallback) common.OpenAPIDefinition {
|
||||
return common.OpenAPIDefinition{
|
||||
Schema: spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Type: []string{"object"},
|
||||
Properties: map[string]spec.Schema{
|
||||
"kind": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
"apiVersion": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
"metadata": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Default: map[string]interface{}{},
|
||||
Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"),
|
||||
},
|
||||
},
|
||||
"spec": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Default: map[string]interface{}{},
|
||||
Ref: ref("github.com/grafana/grafana/pkg/apimachinery/apis/common/v0alpha1.ScopeSpec"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Dependencies: []string{
|
||||
"github.com/grafana/grafana/pkg/apimachinery/apis/common/v0alpha1.ScopeSpec", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"},
|
||||
}
|
||||
}
|
||||
|
||||
func schema_apimachinery_apis_common_v0alpha1_ScopeFilter(ref common.ReferenceCallback) common.OpenAPIDefinition {
|
||||
return common.OpenAPIDefinition{
|
||||
Schema: spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Type: []string{"object"},
|
||||
Properties: map[string]spec.Schema{
|
||||
"key": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Default: "",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
"value": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Default: "",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
"values": {
|
||||
VendorExtensible: spec.VendorExtensible{
|
||||
Extensions: spec.Extensions{
|
||||
"x-kubernetes-list-type": "atomic",
|
||||
},
|
||||
},
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "Values is used for operators that require multiple values (e.g. one-of and not-one-of).",
|
||||
Type: []string{"array"},
|
||||
Items: &spec.SchemaOrArray{
|
||||
Schema: &spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Default: "",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"operator": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "Possible enum values:\n - `\"equals\"`\n - `\"not-equals\"`\n - `\"not-one-of\"`\n - `\"one-of\"`\n - `\"regex-match\"`\n - `\"regex-not-match\"`",
|
||||
Default: "",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
Enum: []interface{}{"equals", "not-equals", "not-one-of", "one-of", "regex-match", "regex-not-match"},
|
||||
},
|
||||
},
|
||||
},
|
||||
Required: []string{"key", "value", "operator"},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func schema_apimachinery_apis_common_v0alpha1_ScopeSpec(ref common.ReferenceCallback) common.OpenAPIDefinition {
|
||||
return common.OpenAPIDefinition{
|
||||
Schema: spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Type: []string{"object"},
|
||||
Properties: map[string]spec.Schema{
|
||||
"title": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Default: "",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
"defaultPath": {
|
||||
VendorExtensible: spec.VendorExtensible{
|
||||
Extensions: spec.Extensions{
|
||||
"x-kubernetes-list-type": "atomic",
|
||||
},
|
||||
},
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "Provides a default path for the scope. This refers to a list of nodes in the selector. This is used to display the title next to the selected scope and expand the selector to the proper path. This will override whichever is selected from in the selector. The path is a list of node ids, starting at the direct parent of the selected node towards the root.",
|
||||
Type: []string{"array"},
|
||||
Items: &spec.SchemaOrArray{
|
||||
Schema: &spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Default: "",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"filters": {
|
||||
VendorExtensible: spec.VendorExtensible{
|
||||
Extensions: spec.Extensions{
|
||||
"x-kubernetes-list-type": "atomic",
|
||||
},
|
||||
},
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Type: []string{"array"},
|
||||
Items: &spec.SchemaOrArray{
|
||||
Schema: &spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Default: map[string]interface{}{},
|
||||
Ref: ref("github.com/grafana/grafana/pkg/apimachinery/apis/common/v0alpha1.ScopeFilter"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Required: []string{"title"},
|
||||
},
|
||||
},
|
||||
Dependencies: []string{
|
||||
"github.com/grafana/grafana/pkg/apimachinery/apis/common/v0alpha1.ScopeFilter"},
|
||||
}
|
||||
}
|
||||
|
||||
func schema_pkg_apis_meta_v1_APIGroup(ref common.ReferenceCallback) common.OpenAPIDefinition {
|
||||
return common.OpenAPIDefinition{
|
||||
Schema: spec.Schema{
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ go 1.25.2
|
|||
require (
|
||||
github.com/grafana/dskit v0.0.0-20250908063411-6b6da59b5cc4
|
||||
github.com/grafana/grafana-plugin-sdk-go v0.279.0
|
||||
github.com/grafana/grafana/apps/scope v0.0.0-20251007093103-792853df9134
|
||||
github.com/json-iterator/go v1.1.12
|
||||
github.com/prometheus/client_golang v1.23.2
|
||||
github.com/prometheus/common v0.66.1
|
||||
|
|
@ -54,6 +55,7 @@ require (
|
|||
github.com/google/go-cmp v0.7.0 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/gorilla/mux v1.8.1 // indirect
|
||||
github.com/grafana/grafana/pkg/apimachinery v0.0.0-20251007081214-26e147d01f0a // indirect
|
||||
github.com/grafana/otel-profiling-go v0.5.1 // indirect
|
||||
github.com/grafana/pyroscope-go/godeltaprof v0.1.8 // indirect
|
||||
github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc // indirect
|
||||
|
|
@ -91,10 +93,9 @@ require (
|
|||
github.com/prometheus/client_model v0.6.2 // indirect
|
||||
github.com/prometheus/procfs v0.16.1 // indirect
|
||||
github.com/rivo/uniseg v0.4.7 // indirect
|
||||
github.com/rogpeppe/go-internal v1.14.1 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/smartystreets/goconvey v1.8.1 // indirect
|
||||
github.com/spf13/pflag v1.0.10 // indirect
|
||||
github.com/stretchr/objx v0.5.2 // indirect
|
||||
github.com/ugorji/go/codec v1.2.11 // indirect
|
||||
github.com/unknwon/bra v0.0.0-20200517080246-1e3013ecaff8 // indirect
|
||||
github.com/unknwon/com v1.0.1 // indirect
|
||||
|
|
|
|||
|
|
@ -134,6 +134,10 @@ github.com/grafana/dskit v0.0.0-20250908063411-6b6da59b5cc4 h1:jSojuc7njleS3UOz2
|
|||
github.com/grafana/dskit v0.0.0-20250908063411-6b6da59b5cc4/go.mod h1:VahT+GtfQIM+o8ht2StR6J9g+Ef+C2Vokh5uuSmOD/4=
|
||||
github.com/grafana/grafana-plugin-sdk-go v0.279.0 h1:/KCrsZkj9pEGwIGovqAz1A8rjI2A2YT+ZpvgfZN0LAA=
|
||||
github.com/grafana/grafana-plugin-sdk-go v0.279.0/go.mod h1:/7oGN6Z7DGTGaLHhgIYrRr6Wvmdsb3BLw5hL4Kbjy88=
|
||||
github.com/grafana/grafana/apps/scope v0.0.0-20251007093103-792853df9134 h1:xly75v5lFNR37q+wXnwA5yU/fPW9IOSYbhFpt4tQyt8=
|
||||
github.com/grafana/grafana/apps/scope v0.0.0-20251007093103-792853df9134/go.mod h1:zijsUNa1zi476JJIR2Lcm/Paz1nRCno9XCp6hbS6G9o=
|
||||
github.com/grafana/grafana/pkg/apimachinery v0.0.0-20251007081214-26e147d01f0a h1:L7xgV9mP6MRF3L2/vDOjNR7heaBPbXPMGTDN9/jXSFQ=
|
||||
github.com/grafana/grafana/pkg/apimachinery v0.0.0-20251007081214-26e147d01f0a/go.mod h1:OK8NwS87D5YphchOcAsiIWk/feMZ0EzfAGME1Kff860=
|
||||
github.com/grafana/otel-profiling-go v0.5.1 h1:stVPKAFZSa7eGiqbYuG25VcqYksR6iWvF3YH66t4qL8=
|
||||
github.com/grafana/otel-profiling-go v0.5.1/go.mod h1:ftN/t5A/4gQI19/8MoWurBEtC6gFw8Dns1sJZ9W4Tls=
|
||||
github.com/grafana/pyroscope-go/godeltaprof v0.1.8 h1:iwOtYXeeVSAeYefJNaxDytgjKtUuKQbJqgAIjlnicKg=
|
||||
|
|
@ -278,6 +282,7 @@ github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3A
|
|||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
|
||||
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import (
|
|||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend/gtime"
|
||||
sdkapi "github.com/grafana/grafana-plugin-sdk-go/experimental/apis/data/v0alpha1"
|
||||
scope "github.com/grafana/grafana/apps/scope/pkg/apis/scope/v0alpha1"
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
|
||||
|
|
@ -68,47 +69,15 @@ type PrometheusQueryProperties struct {
|
|||
LegendFormat string `json:"legendFormat,omitempty"`
|
||||
|
||||
// A set of filters applied to apply to the query
|
||||
Scopes []ScopeSpec `json:"scopes,omitempty"`
|
||||
Scopes []scope.ScopeSpec `json:"scopes,omitempty"`
|
||||
|
||||
// Additional Ad-hoc filters that take precedence over Scope on conflict.
|
||||
AdhocFilters []ScopeFilter `json:"adhocFilters,omitempty"`
|
||||
AdhocFilters []scope.ScopeFilter `json:"adhocFilters,omitempty"`
|
||||
|
||||
// Group By parameters to apply to aggregate expressions in the query
|
||||
GroupByKeys []string `json:"groupByKeys,omitempty"`
|
||||
}
|
||||
|
||||
// ScopeSpec is a hand copy of the ScopeSpec struct from pkg/apis/scope/v0alpha1/types.go
|
||||
// to avoid import (temp fix). This also has metadata.name inlined.
|
||||
type ScopeSpec struct {
|
||||
Name string `json:"name"` // This is the identifier from metadata.name of the scope model.
|
||||
Title string `json:"title"`
|
||||
DefaultPath []string `json:"defaultPath,omitempty"`
|
||||
Filters []ScopeFilter `json:"filters,omitempty"`
|
||||
}
|
||||
|
||||
// ScopeFilter is a hand copy of the ScopeFilter struct from pkg/apis/scope/v0alpha1/types.go
|
||||
// to avoid import (temp fix)
|
||||
type ScopeFilter struct {
|
||||
Key string `json:"key"`
|
||||
Value string `json:"value"`
|
||||
// Values is used for operators that require multiple values (e.g. one-of and not-one-of).
|
||||
Values []string `json:"values,omitempty"`
|
||||
Operator FilterOperator `json:"operator"`
|
||||
}
|
||||
|
||||
// FilterOperator is a hand copy of the ScopeFilter struct from pkg/apis/scope/v0alpha1/types.go
|
||||
type FilterOperator string
|
||||
|
||||
// Hand copy of enum from pkg/apis/scope/v0alpha1/types.go
|
||||
const (
|
||||
FilterOperatorEquals FilterOperator = "equals"
|
||||
FilterOperatorNotEquals FilterOperator = "not-equals"
|
||||
FilterOperatorRegexMatch FilterOperator = "regex-match"
|
||||
FilterOperatorRegexNotMatch FilterOperator = "regex-not-match"
|
||||
FilterOperatorOneOf FilterOperator = "one-of"
|
||||
FilterOperatorNotOneOf FilterOperator = "not-one-of"
|
||||
)
|
||||
|
||||
// Internal interval and range variables
|
||||
const (
|
||||
varInterval = "$__interval"
|
||||
|
|
@ -175,7 +144,7 @@ type Query struct {
|
|||
ExemplarQuery bool
|
||||
UtcOffsetSec int64
|
||||
|
||||
Scopes []ScopeSpec
|
||||
Scopes []scope.ScopeSpec
|
||||
}
|
||||
|
||||
// This internal query struct is just like QueryModel, except it does not include:
|
||||
|
|
@ -217,7 +186,7 @@ func Parse(ctx context.Context, log glog.Logger, span trace.Span, query backend.
|
|||
)
|
||||
|
||||
if enableScope {
|
||||
var scopeFilters []ScopeFilter
|
||||
var scopeFilters []scope.ScopeFilter
|
||||
for _, scope := range model.Scopes {
|
||||
scopeFilters = append(scopeFilters, scope.Filters...)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@
|
|||
"description": "Additional Ad-hoc filters that take precedence over Scope on conflict.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"description": "ScopeFilter is a hand copy of the ScopeFilter struct from pkg/apis/scope/v0alpha1/types.go to avoid import (temp fix)",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"key",
|
||||
|
|
@ -36,7 +35,6 @@
|
|||
"type": "string"
|
||||
},
|
||||
"values": {
|
||||
"description": "Values is used for operators that require multiple values (e.g. one-of and not-one-of).",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
|
|
@ -184,10 +182,8 @@
|
|||
"description": "A set of filters applied to apply to the query",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"description": "ScopeSpec is a hand copy of the ScopeSpec struct from pkg/apis/scope/v0alpha1/types.go to avoid import (temp fix).",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"name",
|
||||
"title"
|
||||
],
|
||||
"properties": {
|
||||
|
|
@ -200,7 +196,6 @@
|
|||
"filters": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"description": "ScopeFilter is a hand copy of the ScopeFilter struct from pkg/apis/scope/v0alpha1/types.go to avoid import (temp fix)",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"key",
|
||||
|
|
@ -218,7 +213,6 @@
|
|||
"type": "string"
|
||||
},
|
||||
"values": {
|
||||
"description": "Values is used for operators that require multiple values (e.g. one-of and not-one-of).",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
|
|
@ -228,10 +222,6 @@
|
|||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"name": {
|
||||
"description": "This is the identifier from metadata.name of the scope model.",
|
||||
"type": "string"
|
||||
},
|
||||
"title": {
|
||||
"type": "string"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,7 +28,6 @@
|
|||
"description": "Additional Ad-hoc filters that take precedence over Scope on conflict.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"description": "ScopeFilter is a hand copy of the ScopeFilter struct from pkg/apis/scope/v0alpha1/types.go to avoid import (temp fix)",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"key",
|
||||
|
|
@ -46,7 +45,6 @@
|
|||
"type": "string"
|
||||
},
|
||||
"values": {
|
||||
"description": "Values is used for operators that require multiple values (e.g. one-of and not-one-of).",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
|
|
@ -194,10 +192,8 @@
|
|||
"description": "A set of filters applied to apply to the query",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"description": "ScopeSpec is a hand copy of the ScopeSpec struct from pkg/apis/scope/v0alpha1/types.go to avoid import (temp fix).",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"name",
|
||||
"title"
|
||||
],
|
||||
"properties": {
|
||||
|
|
@ -210,7 +206,6 @@
|
|||
"filters": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"description": "ScopeFilter is a hand copy of the ScopeFilter struct from pkg/apis/scope/v0alpha1/types.go to avoid import (temp fix)",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"key",
|
||||
|
|
@ -228,7 +223,6 @@
|
|||
"type": "string"
|
||||
},
|
||||
"values": {
|
||||
"description": "Values is used for operators that require multiple values (e.g. one-of and not-one-of).",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
|
|
@ -238,10 +232,6 @@
|
|||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"name": {
|
||||
"description": "This is the identifier from metadata.name of the scope model.",
|
||||
"type": "string"
|
||||
},
|
||||
"title": {
|
||||
"type": "string"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
{
|
||||
"metadata": {
|
||||
"name": "default",
|
||||
"resourceVersion": "1758739325095",
|
||||
"resourceVersion": "1759831574256",
|
||||
"creationTimestamp": "2024-03-25T13:19:04Z"
|
||||
},
|
||||
"spec": {
|
||||
|
|
@ -21,7 +21,6 @@
|
|||
"description": "Additional Ad-hoc filters that take precedence over Scope on conflict.",
|
||||
"items": {
|
||||
"additionalProperties": false,
|
||||
"description": "ScopeFilter is a hand copy of the ScopeFilter struct from pkg/apis/scope/v0alpha1/types.go to avoid import (temp fix)",
|
||||
"properties": {
|
||||
"key": {
|
||||
"type": "string"
|
||||
|
|
@ -33,7 +32,6 @@
|
|||
"type": "string"
|
||||
},
|
||||
"values": {
|
||||
"description": "Values is used for operators that require multiple values (e.g. one-of and not-one-of).",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
|
|
@ -103,7 +101,6 @@
|
|||
"description": "A set of filters applied to apply to the query",
|
||||
"items": {
|
||||
"additionalProperties": false,
|
||||
"description": "ScopeSpec is a hand copy of the ScopeSpec struct from pkg/apis/scope/v0alpha1/types.go to avoid import (temp fix).",
|
||||
"properties": {
|
||||
"defaultPath": {
|
||||
"items": {
|
||||
|
|
@ -114,7 +111,6 @@
|
|||
"filters": {
|
||||
"items": {
|
||||
"additionalProperties": false,
|
||||
"description": "ScopeFilter is a hand copy of the ScopeFilter struct from pkg/apis/scope/v0alpha1/types.go to avoid import (temp fix)",
|
||||
"properties": {
|
||||
"key": {
|
||||
"type": "string"
|
||||
|
|
@ -126,7 +122,6 @@
|
|||
"type": "string"
|
||||
},
|
||||
"values": {
|
||||
"description": "Values is used for operators that require multiple values (e.g. one-of and not-one-of).",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
|
|
@ -142,16 +137,11 @@
|
|||
},
|
||||
"type": "array"
|
||||
},
|
||||
"name": {
|
||||
"description": "This is the identifier from metadata.name of the scope model.",
|
||||
"type": "string"
|
||||
},
|
||||
"title": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"name",
|
||||
"title"
|
||||
],
|
||||
"type": "object"
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import (
|
|||
"fmt"
|
||||
"strings"
|
||||
|
||||
scope "github.com/grafana/grafana/apps/scope/pkg/apis/scope/v0alpha1"
|
||||
"github.com/prometheus/common/model"
|
||||
"github.com/prometheus/prometheus/model/labels"
|
||||
"github.com/prometheus/prometheus/promql/parser"
|
||||
|
|
@ -15,7 +16,7 @@ func init() {
|
|||
}
|
||||
|
||||
// ApplyFiltersAndGroupBy takes a raw promQL expression, converts the filters into PromQL matchers, and applies these matchers to the parsed expression. It also applies the group by clause to any aggregate expressions in the parsed expression.
|
||||
func ApplyFiltersAndGroupBy(rawExpr string, scopeFilters, adHocFilters []ScopeFilter, groupBy []string) (string, error) {
|
||||
func ApplyFiltersAndGroupBy(rawExpr string, scopeFilters, adHocFilters []scope.ScopeFilter, groupBy []string) (string, error) {
|
||||
expr, err := parser.ParseExpr(rawExpr)
|
||||
if err != nil {
|
||||
return "", err
|
||||
|
|
@ -76,7 +77,7 @@ func ApplyFiltersAndGroupBy(rawExpr string, scopeFilters, adHocFilters []ScopeFi
|
|||
return expr.String(), nil
|
||||
}
|
||||
|
||||
func FiltersToMatchers(scopeFilters, adhocFilters []ScopeFilter) ([]*labels.Matcher, error) {
|
||||
func FiltersToMatchers(scopeFilters, adhocFilters []scope.ScopeFilter) ([]*labels.Matcher, error) {
|
||||
filterMap := make(map[string]*labels.Matcher)
|
||||
|
||||
// scope filters are applied first
|
||||
|
|
@ -115,25 +116,25 @@ func FiltersToMatchers(scopeFilters, adhocFilters []ScopeFilter) ([]*labels.Matc
|
|||
return matchers, nil
|
||||
}
|
||||
|
||||
func filterToMatcher(f ScopeFilter) (*labels.Matcher, error) {
|
||||
func filterToMatcher(f scope.ScopeFilter) (*labels.Matcher, error) {
|
||||
var mt labels.MatchType
|
||||
switch f.Operator {
|
||||
case FilterOperatorEquals:
|
||||
case scope.FilterOperatorEquals:
|
||||
mt = labels.MatchEqual
|
||||
case FilterOperatorNotEquals:
|
||||
case scope.FilterOperatorNotEquals:
|
||||
mt = labels.MatchNotEqual
|
||||
case FilterOperatorRegexMatch:
|
||||
case scope.FilterOperatorRegexMatch:
|
||||
mt = labels.MatchRegexp
|
||||
case FilterOperatorRegexNotMatch:
|
||||
case scope.FilterOperatorRegexNotMatch:
|
||||
mt = labels.MatchNotRegexp
|
||||
case FilterOperatorOneOf:
|
||||
case scope.FilterOperatorOneOf:
|
||||
mt = labels.MatchRegexp
|
||||
case FilterOperatorNotOneOf:
|
||||
case scope.FilterOperatorNotOneOf:
|
||||
mt = labels.MatchNotRegexp
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown operator %q", f.Operator)
|
||||
}
|
||||
if f.Operator == FilterOperatorOneOf || f.Operator == FilterOperatorNotOneOf {
|
||||
if f.Operator == scope.FilterOperatorOneOf || f.Operator == scope.FilterOperatorNotOneOf {
|
||||
if len(f.Values) > 0 {
|
||||
return labels.NewMatcher(mt, f.Key, strings.Join(f.Values, "|"))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package models
|
|||
import (
|
||||
"testing"
|
||||
|
||||
scope "github.com/grafana/grafana/apps/scope/pkg/apis/scope/v0alpha1"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
|
|
@ -10,8 +11,8 @@ func TestApplyQueryFiltersAndGroupBy_Filters(t *testing.T) {
|
|||
tests := []struct {
|
||||
name string
|
||||
query string
|
||||
adhocFilters []ScopeFilter
|
||||
scopeFilters []ScopeFilter
|
||||
adhocFilters []scope.ScopeFilter
|
||||
scopeFilters []scope.ScopeFilter
|
||||
expected string
|
||||
expectErr bool
|
||||
}{
|
||||
|
|
@ -30,8 +31,8 @@ func TestApplyQueryFiltersAndGroupBy_Filters(t *testing.T) {
|
|||
{
|
||||
name: "Adhoc filter with existing filter",
|
||||
query: `http_requests_total{job="prometheus"}`,
|
||||
adhocFilters: []ScopeFilter{
|
||||
{Key: "method", Value: "get", Operator: FilterOperatorEquals},
|
||||
adhocFilters: []scope.ScopeFilter{
|
||||
{Key: "method", Value: "get", Operator: scope.FilterOperatorEquals},
|
||||
},
|
||||
expected: `http_requests_total{job="prometheus",method="get"}`,
|
||||
expectErr: false,
|
||||
|
|
@ -39,9 +40,9 @@ func TestApplyQueryFiltersAndGroupBy_Filters(t *testing.T) {
|
|||
{
|
||||
name: "Adhoc filter with no existing filter",
|
||||
query: `http_requests_total`,
|
||||
adhocFilters: []ScopeFilter{
|
||||
{Key: "method", Value: "get", Operator: FilterOperatorEquals},
|
||||
{Key: "job", Value: "prometheus", Operator: FilterOperatorEquals},
|
||||
adhocFilters: []scope.ScopeFilter{
|
||||
{Key: "method", Value: "get", Operator: scope.FilterOperatorEquals},
|
||||
{Key: "job", Value: "prometheus", Operator: scope.FilterOperatorEquals},
|
||||
},
|
||||
expected: `http_requests_total{job="prometheus",method="get"}`,
|
||||
expectErr: false,
|
||||
|
|
@ -49,8 +50,8 @@ func TestApplyQueryFiltersAndGroupBy_Filters(t *testing.T) {
|
|||
{
|
||||
name: "Scope filter",
|
||||
query: `http_requests_total{job="prometheus"}`,
|
||||
scopeFilters: []ScopeFilter{
|
||||
{Key: "status", Value: "200", Operator: FilterOperatorEquals},
|
||||
scopeFilters: []scope.ScopeFilter{
|
||||
{Key: "status", Value: "200", Operator: scope.FilterOperatorEquals},
|
||||
},
|
||||
expected: `http_requests_total{job="prometheus",status="200"}`,
|
||||
expectErr: false,
|
||||
|
|
@ -58,11 +59,11 @@ func TestApplyQueryFiltersAndGroupBy_Filters(t *testing.T) {
|
|||
{
|
||||
name: "Adhoc and Scope filter no existing filter",
|
||||
query: `http_requests_total`,
|
||||
scopeFilters: []ScopeFilter{
|
||||
{Key: "status", Value: "200", Operator: FilterOperatorEquals},
|
||||
scopeFilters: []scope.ScopeFilter{
|
||||
{Key: "status", Value: "200", Operator: scope.FilterOperatorEquals},
|
||||
},
|
||||
adhocFilters: []ScopeFilter{
|
||||
{Key: "job", Value: "prometheus", Operator: FilterOperatorEquals},
|
||||
adhocFilters: []scope.ScopeFilter{
|
||||
{Key: "job", Value: "prometheus", Operator: scope.FilterOperatorEquals},
|
||||
},
|
||||
expected: `http_requests_total{job="prometheus",status="200"}`,
|
||||
expectErr: false,
|
||||
|
|
@ -70,11 +71,11 @@ func TestApplyQueryFiltersAndGroupBy_Filters(t *testing.T) {
|
|||
{
|
||||
name: "Adhoc and Scope filter conflict - adhoc wins (if not oneOf or notOneOf)",
|
||||
query: `http_requests_total{job="prometheus"}`,
|
||||
scopeFilters: []ScopeFilter{
|
||||
{Key: "status", Value: "404", Operator: FilterOperatorEquals},
|
||||
scopeFilters: []scope.ScopeFilter{
|
||||
{Key: "status", Value: "404", Operator: scope.FilterOperatorEquals},
|
||||
},
|
||||
adhocFilters: []ScopeFilter{
|
||||
{Key: "status", Value: "200", Operator: FilterOperatorEquals},
|
||||
adhocFilters: []scope.ScopeFilter{
|
||||
{Key: "status", Value: "200", Operator: scope.FilterOperatorEquals},
|
||||
},
|
||||
expected: `http_requests_total{job="prometheus",status="200"}`,
|
||||
expectErr: false,
|
||||
|
|
@ -82,8 +83,8 @@ func TestApplyQueryFiltersAndGroupBy_Filters(t *testing.T) {
|
|||
{
|
||||
name: "Adhoc filters with more complex expression",
|
||||
query: `capacity_bytes{job="prometheus"} + available_bytes{job="grafana"} / 1024`,
|
||||
adhocFilters: []ScopeFilter{
|
||||
{Key: "job", Value: "alloy", Operator: FilterOperatorEquals},
|
||||
adhocFilters: []scope.ScopeFilter{
|
||||
{Key: "job", Value: "alloy", Operator: scope.FilterOperatorEquals},
|
||||
},
|
||||
expected: `capacity_bytes{job="alloy"} + available_bytes{job="alloy"} / 1024`,
|
||||
expectErr: false,
|
||||
|
|
@ -91,8 +92,8 @@ func TestApplyQueryFiltersAndGroupBy_Filters(t *testing.T) {
|
|||
{
|
||||
name: "OneOf Operator is combined into a single regex filter",
|
||||
query: `http_requests_total{job="prometheus"}`,
|
||||
scopeFilters: []ScopeFilter{
|
||||
{Key: "status", Values: []string{"404", "400"}, Operator: FilterOperatorOneOf},
|
||||
scopeFilters: []scope.ScopeFilter{
|
||||
{Key: "status", Values: []string{"404", "400"}, Operator: scope.FilterOperatorOneOf},
|
||||
},
|
||||
expected: `http_requests_total{job="prometheus",status=~"404|400"}`,
|
||||
expectErr: false,
|
||||
|
|
@ -100,8 +101,8 @@ func TestApplyQueryFiltersAndGroupBy_Filters(t *testing.T) {
|
|||
{
|
||||
name: "using __name__ as part of the query",
|
||||
query: `{__name__="http_requests_total"}`,
|
||||
scopeFilters: []ScopeFilter{
|
||||
{Key: "namespace", Value: "istio", Operator: FilterOperatorEquals},
|
||||
scopeFilters: []scope.ScopeFilter{
|
||||
{Key: "namespace", Value: "istio", Operator: scope.FilterOperatorEquals},
|
||||
},
|
||||
expected: `{__name__="http_requests_total",namespace="istio"}`,
|
||||
expectErr: false,
|
||||
|
|
@ -109,9 +110,9 @@ func TestApplyQueryFiltersAndGroupBy_Filters(t *testing.T) {
|
|||
{
|
||||
name: "merge scopes filters into using OR if they share filter key",
|
||||
query: `http_requests_total{}`,
|
||||
scopeFilters: []ScopeFilter{
|
||||
{Key: "namespace", Value: "default", Operator: FilterOperatorEquals},
|
||||
{Key: "namespace", Value: "kube-system", Operator: FilterOperatorEquals},
|
||||
scopeFilters: []scope.ScopeFilter{
|
||||
{Key: "namespace", Value: "default", Operator: scope.FilterOperatorEquals},
|
||||
{Key: "namespace", Value: "kube-system", Operator: scope.FilterOperatorEquals},
|
||||
},
|
||||
expected: `http_requests_total{namespace=~"default|kube-system"}`,
|
||||
expectErr: false,
|
||||
|
|
@ -119,12 +120,12 @@ func TestApplyQueryFiltersAndGroupBy_Filters(t *testing.T) {
|
|||
{
|
||||
name: "adhoc filters win over scope filters if they share filter key",
|
||||
query: `http_requests_total{}`,
|
||||
scopeFilters: []ScopeFilter{
|
||||
{Key: "namespace", Value: "default", Operator: FilterOperatorEquals},
|
||||
{Key: "namespace", Value: "kube-system", Operator: FilterOperatorEquals},
|
||||
scopeFilters: []scope.ScopeFilter{
|
||||
{Key: "namespace", Value: "default", Operator: scope.FilterOperatorEquals},
|
||||
{Key: "namespace", Value: "kube-system", Operator: scope.FilterOperatorEquals},
|
||||
},
|
||||
adhocFilters: []ScopeFilter{
|
||||
{Key: "namespace", Value: "adhoc-wins", Operator: FilterOperatorEquals},
|
||||
adhocFilters: []scope.ScopeFilter{
|
||||
{Key: "namespace", Value: "adhoc-wins", Operator: scope.FilterOperatorEquals},
|
||||
},
|
||||
expected: `http_requests_total{namespace="adhoc-wins"}`,
|
||||
expectErr: false,
|
||||
|
|
@ -149,8 +150,8 @@ func TestApplyQueryFiltersAndGroupBy_Filters_utf8(t *testing.T) {
|
|||
tests := []struct {
|
||||
name string
|
||||
query string
|
||||
adhocFilters []ScopeFilter
|
||||
scopeFilters []ScopeFilter
|
||||
adhocFilters []scope.ScopeFilter
|
||||
scopeFilters []scope.ScopeFilter
|
||||
expected string
|
||||
expectErr bool
|
||||
}{
|
||||
|
|
@ -276,8 +277,8 @@ func TestApplyQueryFiltersAndGroupBy(t *testing.T) {
|
|||
tests := []struct {
|
||||
name string
|
||||
query string
|
||||
adhocFilters []ScopeFilter
|
||||
scopeFilters []ScopeFilter
|
||||
adhocFilters []scope.ScopeFilter
|
||||
scopeFilters []scope.ScopeFilter
|
||||
groupby []string
|
||||
expected string
|
||||
expectErr bool
|
||||
|
|
@ -286,11 +287,11 @@ func TestApplyQueryFiltersAndGroupBy(t *testing.T) {
|
|||
{
|
||||
name: "Adhoc filters with more complex expression",
|
||||
query: `sum(capacity_bytes{job="prometheus"} + available_bytes{job="grafana"}) / 1024`,
|
||||
adhocFilters: []ScopeFilter{
|
||||
{Key: "job", Value: "alloy", Operator: FilterOperatorEquals},
|
||||
adhocFilters: []scope.ScopeFilter{
|
||||
{Key: "job", Value: "alloy", Operator: scope.FilterOperatorEquals},
|
||||
},
|
||||
scopeFilters: []ScopeFilter{
|
||||
{Key: "vol", Value: "/", Operator: FilterOperatorEquals},
|
||||
scopeFilters: []scope.ScopeFilter{
|
||||
{Key: "vol", Value: "/", Operator: scope.FilterOperatorEquals},
|
||||
},
|
||||
groupby: []string{"job"},
|
||||
expected: `sum by (job) (capacity_bytes{job="alloy",vol="/"} + available_bytes{job="alloy",vol="/"}) / 1024`,
|
||||
|
|
@ -316,8 +317,8 @@ func TestApplyQueryFiltersAndGroupBy_utf8(t *testing.T) {
|
|||
tests := []struct {
|
||||
name string
|
||||
query string
|
||||
adhocFilters []ScopeFilter
|
||||
scopeFilters []ScopeFilter
|
||||
adhocFilters []scope.ScopeFilter
|
||||
scopeFilters []scope.ScopeFilter
|
||||
groupby []string
|
||||
expected string
|
||||
expectErr bool
|
||||
|
|
@ -325,11 +326,11 @@ func TestApplyQueryFiltersAndGroupBy_utf8(t *testing.T) {
|
|||
{
|
||||
name: "Adhoc filters with more complex expression and utf8 metric name",
|
||||
query: `sum({"capacity_bytes", job="prometheus"} + {"available_bytes", job="grafana"}) / 1024`,
|
||||
adhocFilters: []ScopeFilter{
|
||||
{Key: "job", Value: "alloy", Operator: FilterOperatorEquals},
|
||||
adhocFilters: []scope.ScopeFilter{
|
||||
{Key: "job", Value: "alloy", Operator: scope.FilterOperatorEquals},
|
||||
},
|
||||
scopeFilters: []ScopeFilter{
|
||||
{Key: "vol", Value: "/", Operator: FilterOperatorEquals},
|
||||
scopeFilters: []scope.ScopeFilter{
|
||||
{Key: "vol", Value: "/", Operator: scope.FilterOperatorEquals},
|
||||
},
|
||||
groupby: []string{"job"},
|
||||
expected: `sum by (job) ({__name__="capacity_bytes",job="alloy",vol="/"} + {__name__="available_bytes",job="alloy",vol="/"}) / 1024`,
|
||||
|
|
@ -338,11 +339,11 @@ func TestApplyQueryFiltersAndGroupBy_utf8(t *testing.T) {
|
|||
{
|
||||
name: "Adhoc filters with more complex expression with utf8 label",
|
||||
query: `sum(capacity_bytes{job="prometheus", "utf8.label"="value"} + available_bytes{job="grafana"}) / 1024`,
|
||||
adhocFilters: []ScopeFilter{
|
||||
{Key: "job", Value: "alloy", Operator: FilterOperatorEquals},
|
||||
adhocFilters: []scope.ScopeFilter{
|
||||
{Key: "job", Value: "alloy", Operator: scope.FilterOperatorEquals},
|
||||
},
|
||||
scopeFilters: []ScopeFilter{
|
||||
{Key: "vol", Value: "/", Operator: FilterOperatorEquals},
|
||||
scopeFilters: []scope.ScopeFilter{
|
||||
{Key: "vol", Value: "/", Operator: scope.FilterOperatorEquals},
|
||||
},
|
||||
groupby: []string{"job"},
|
||||
expected: `sum by (job) (capacity_bytes{"utf8.label"="value",job="alloy",vol="/"} + available_bytes{job="alloy",vol="/"}) / 1024`,
|
||||
|
|
@ -351,11 +352,11 @@ func TestApplyQueryFiltersAndGroupBy_utf8(t *testing.T) {
|
|||
{
|
||||
name: "Adhoc filters with more complex expression with utf8 metric and label",
|
||||
query: `sum({"capacity_bytes", job="prometheus", "utf8.label"="value"} + available_bytes{job="grafana"}) / 1024`,
|
||||
adhocFilters: []ScopeFilter{
|
||||
{Key: "job", Value: "alloy", Operator: FilterOperatorEquals},
|
||||
adhocFilters: []scope.ScopeFilter{
|
||||
{Key: "job", Value: "alloy", Operator: scope.FilterOperatorEquals},
|
||||
},
|
||||
scopeFilters: []ScopeFilter{
|
||||
{Key: "vol", Value: "/", Operator: FilterOperatorEquals},
|
||||
scopeFilters: []scope.ScopeFilter{
|
||||
{Key: "vol", Value: "/", Operator: scope.FilterOperatorEquals},
|
||||
},
|
||||
groupby: []string{"job"},
|
||||
expected: `sum by (job) ({"utf8.label"="value",__name__="capacity_bytes",job="alloy",vol="/"} + available_bytes{job="alloy",vol="/"}) / 1024`,
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import (
|
|||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend/log"
|
||||
"github.com/grafana/grafana-plugin-sdk-go/data/utils/maputil"
|
||||
scope "github.com/grafana/grafana/apps/scope/pkg/apis/scope/v0alpha1"
|
||||
"github.com/prometheus/prometheus/promql/parser"
|
||||
|
||||
"github.com/grafana/grafana/pkg/promlib/client"
|
||||
|
|
@ -116,8 +117,8 @@ type SuggestionRequest struct {
|
|||
|
||||
Queries []string `json:"queries"`
|
||||
|
||||
Scopes []models.ScopeFilter `json:"scopes"`
|
||||
AdhocFilters []models.ScopeFilter `json:"adhocFilters"`
|
||||
Scopes []scope.ScopeFilter `json:"scopes"`
|
||||
AdhocFilters []scope.ScopeFilter `json:"adhocFilters"`
|
||||
|
||||
// Start and End are proxied directly to the prometheus endpoint (which is rfc3339 | unix_timestamp)
|
||||
Start string `json:"start"`
|
||||
|
|
|
|||
|
|
@ -11,10 +11,10 @@ import (
|
|||
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend/log"
|
||||
scope "github.com/grafana/grafana/apps/scope/pkg/apis/scope/v0alpha1"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/grafana/grafana/pkg/promlib/models"
|
||||
"github.com/grafana/grafana/pkg/promlib/resource"
|
||||
)
|
||||
|
||||
|
|
@ -151,11 +151,11 @@ func TestResource_GetSuggestionsWithEmptyQueriesButFilters(t *testing.T) {
|
|||
// Create a request with empty queries but with filters
|
||||
suggestionReq := resource.SuggestionRequest{
|
||||
Queries: []string{}, // Empty queries
|
||||
Scopes: []models.ScopeFilter{
|
||||
{Key: "job", Operator: models.FilterOperatorEquals, Value: "testjob"},
|
||||
Scopes: []scope.ScopeFilter{
|
||||
{Key: "job", Operator: scope.FilterOperatorEquals, Value: "testjob"},
|
||||
},
|
||||
AdhocFilters: []models.ScopeFilter{
|
||||
{Key: "instance", Operator: models.FilterOperatorEquals, Value: "localhost:9090"},
|
||||
AdhocFilters: []scope.ScopeFilter{
|
||||
{Key: "instance", Operator: scope.FilterOperatorEquals, Value: "localhost:9090"},
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -21,8 +21,8 @@ import (
|
|||
"go.opentelemetry.io/otel/trace"
|
||||
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend/httpclient"
|
||||
scope "github.com/grafana/grafana/apps/scope/pkg/apis/scope/v0alpha1"
|
||||
|
||||
"github.com/grafana/grafana/pkg/promlib/models"
|
||||
"github.com/grafana/grafana/pkg/tsdb/loki/kinds/dataquery"
|
||||
)
|
||||
|
||||
|
|
@ -73,9 +73,9 @@ type datasourceInfo struct {
|
|||
|
||||
type QueryJSONModel struct {
|
||||
dataquery.LokiDataQuery
|
||||
Direction *string `json:"direction,omitempty"`
|
||||
SupportingQueryType *string `json:"supportingQueryType"`
|
||||
Scopes []models.ScopeFilter `json:"scopes"`
|
||||
Direction *string `json:"direction,omitempty"`
|
||||
SupportingQueryType *string `json:"supportingQueryType"`
|
||||
Scopes []scope.ScopeFilter `json:"scopes"`
|
||||
}
|
||||
|
||||
type ResponseOpts struct {
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||
scope "github.com/grafana/grafana/apps/scope/pkg/apis/scope/v0alpha1"
|
||||
"github.com/grafana/grafana/pkg/promlib/models"
|
||||
"github.com/grafana/grafana/pkg/tsdb/loki/kinds/dataquery"
|
||||
"github.com/grafana/loki/v3/pkg/logql/syntax"
|
||||
|
|
@ -21,8 +22,8 @@ type SuggestionRequest struct {
|
|||
|
||||
Query string `json:"query"`
|
||||
|
||||
Scopes []models.ScopeFilter `json:"scopes"`
|
||||
AdhocFilters []models.ScopeFilter `json:"adhocFilters"`
|
||||
Scopes []scope.ScopeFilter `json:"scopes"`
|
||||
AdhocFilters []scope.ScopeFilter `json:"adhocFilters"`
|
||||
|
||||
// Start and End are proxied directly to the prometheus endpoint (which is rfc3339 | unix_timestamp)
|
||||
Start string `json:"start"`
|
||||
|
|
@ -79,7 +80,7 @@ func GetSuggestions(ctx context.Context, lokiAPI *LokiAPI, req *backend.CallReso
|
|||
}
|
||||
|
||||
// ApplyScopes applies the given scope filters to the given raw expression.
|
||||
func ApplyScopes(rawExpr string, scopeFilters []models.ScopeFilter) (string, error) {
|
||||
func ApplyScopes(rawExpr string, scopeFilters []scope.ScopeFilter) (string, error) {
|
||||
if len(scopeFilters) == 0 {
|
||||
return rawExpr, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ package loki
|
|||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/grafana/grafana/pkg/promlib/models"
|
||||
scope "github.com/grafana/grafana/apps/scope/pkg/apis/scope/v0alpha1"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
|
|
@ -14,7 +14,7 @@ func TestInjectScopesIntoLokiQuery(t *testing.T) {
|
|||
tests := []struct {
|
||||
name string
|
||||
query string
|
||||
scopeFilters []models.ScopeFilter
|
||||
scopeFilters []scope.ScopeFilter
|
||||
expected string
|
||||
expectErr bool
|
||||
}{
|
||||
|
|
@ -33,8 +33,8 @@ func TestInjectScopesIntoLokiQuery(t *testing.T) {
|
|||
{
|
||||
name: "scopes with existing filter",
|
||||
query: `{namespace="default"} |= "an unexpected error"`,
|
||||
scopeFilters: []models.ScopeFilter{
|
||||
{Key: "cluster", Value: "us-central-1", Operator: models.FilterOperatorEquals},
|
||||
scopeFilters: []scope.ScopeFilter{
|
||||
{Key: "cluster", Value: "us-central-1", Operator: scope.FilterOperatorEquals},
|
||||
},
|
||||
expected: `{namespace="default", cluster="us-central-1"} |= "an unexpected error"`,
|
||||
expectErr: false,
|
||||
|
|
@ -42,8 +42,8 @@ func TestInjectScopesIntoLokiQuery(t *testing.T) {
|
|||
{
|
||||
name: "scopes without existing label matchers",
|
||||
query: `{} |= "an unexpected error"`,
|
||||
scopeFilters: []models.ScopeFilter{
|
||||
{Key: "cluster", Value: "us-central-1", Operator: models.FilterOperatorEquals},
|
||||
scopeFilters: []scope.ScopeFilter{
|
||||
{Key: "cluster", Value: "us-central-1", Operator: scope.FilterOperatorEquals},
|
||||
},
|
||||
expected: `{cluster="us-central-1"} |= "an unexpected error"`,
|
||||
expectErr: false,
|
||||
|
|
@ -51,9 +51,9 @@ func TestInjectScopesIntoLokiQuery(t *testing.T) {
|
|||
{
|
||||
name: "scopes with multiple filters",
|
||||
query: `{} |= "an unexpected error"`,
|
||||
scopeFilters: []models.ScopeFilter{
|
||||
{Key: "cluster", Value: "us-central-1", Operator: models.FilterOperatorEquals},
|
||||
{Key: "namespace", Value: "default", Operator: models.FilterOperatorEquals},
|
||||
scopeFilters: []scope.ScopeFilter{
|
||||
{Key: "cluster", Value: "us-central-1", Operator: scope.FilterOperatorEquals},
|
||||
{Key: "namespace", Value: "default", Operator: scope.FilterOperatorEquals},
|
||||
},
|
||||
expected: `{cluster="us-central-1", namespace="default"} |= "an unexpected error"`,
|
||||
expectErr: false,
|
||||
|
|
@ -61,8 +61,8 @@ func TestInjectScopesIntoLokiQuery(t *testing.T) {
|
|||
{
|
||||
name: "metric query with scopes filters",
|
||||
query: `count_over_time({} |= "error" [1m])`,
|
||||
scopeFilters: []models.ScopeFilter{
|
||||
{Key: "namespace", Value: "default", Operator: models.FilterOperatorEquals},
|
||||
scopeFilters: []scope.ScopeFilter{
|
||||
{Key: "namespace", Value: "default", Operator: scope.FilterOperatorEquals},
|
||||
},
|
||||
expected: `count_over_time({namespace="default"} |= "error"[1m])`,
|
||||
expectErr: false,
|
||||
|
|
@ -70,9 +70,9 @@ func TestInjectScopesIntoLokiQuery(t *testing.T) {
|
|||
{
|
||||
name: "multi range metric query operation",
|
||||
query: `count_over_time({} |= "error" [1m])/count_over_time({} [1m])`,
|
||||
scopeFilters: []models.ScopeFilter{
|
||||
{Key: "cluster", Value: "us-central-1", Operator: models.FilterOperatorEquals},
|
||||
{Key: "namespace", Value: "default", Operator: models.FilterOperatorEquals},
|
||||
scopeFilters: []scope.ScopeFilter{
|
||||
{Key: "cluster", Value: "us-central-1", Operator: scope.FilterOperatorEquals},
|
||||
{Key: "namespace", Value: "default", Operator: scope.FilterOperatorEquals},
|
||||
},
|
||||
expected: `(count_over_time({cluster="us-central-1", namespace="default"} |= "error"[1m]) / count_over_time({cluster="us-central-1", namespace="default"}[1m]))`,
|
||||
expectErr: false,
|
||||
|
|
@ -80,9 +80,9 @@ func TestInjectScopesIntoLokiQuery(t *testing.T) {
|
|||
{
|
||||
name: "multi range metric query operation with existing label matchers",
|
||||
query: `count_over_time({a="bar"} |= "error" [1m])/count_over_time({a="bar"} [1m])`,
|
||||
scopeFilters: []models.ScopeFilter{
|
||||
{Key: "cluster", Value: "us-central-1", Operator: models.FilterOperatorEquals},
|
||||
{Key: "namespace", Value: "default", Operator: models.FilterOperatorEquals},
|
||||
scopeFilters: []scope.ScopeFilter{
|
||||
{Key: "cluster", Value: "us-central-1", Operator: scope.FilterOperatorEquals},
|
||||
{Key: "namespace", Value: "default", Operator: scope.FilterOperatorEquals},
|
||||
},
|
||||
expected: `(count_over_time({a="bar", cluster="us-central-1", namespace="default"} |= "error"[1m]) / count_over_time({a="bar", cluster="us-central-1", namespace="default"}[1m]))`,
|
||||
expectErr: false,
|
||||
|
|
|
|||
|
|
@ -3,7 +3,8 @@ package loki
|
|||
import (
|
||||
"time"
|
||||
|
||||
"github.com/grafana/grafana/pkg/promlib/models"
|
||||
scope "github.com/grafana/grafana/apps/scope/pkg/apis/scope/v0alpha1"
|
||||
|
||||
"github.com/grafana/grafana/pkg/tsdb/loki/kinds/dataquery"
|
||||
)
|
||||
|
||||
|
|
@ -40,5 +41,5 @@ type lokiQuery struct {
|
|||
End time.Time
|
||||
RefID string
|
||||
SupportingQueryType SupportingQueryType
|
||||
Scopes []models.ScopeFilter
|
||||
Scopes []scope.ScopeFilter
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue