merge main

This commit is contained in:
Ryan McKinley
2025-08-28 22:36:57 +03:00
18 changed files with 124 additions and 56 deletions
-5
View File
@@ -456,7 +456,6 @@ require (
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
github.com/jackc/puddle/v2 v2.2.2 // indirect
github.com/jaegertracing/jaeger v1.67.0 // indirect
github.com/jaegertracing/jaeger-idl v0.5.0 // indirect
github.com/jcmturner/aescts/v2 v2.0.0 // indirect
github.com/jcmturner/dnsutils/v2 v2.0.0 // indirect
@@ -518,9 +517,6 @@ require (
github.com/oklog/ulid v1.3.1 // indirect
github.com/oklog/ulid/v2 v2.1.0 // indirect
github.com/open-feature/go-sdk-contrib/providers/ofrep v0.1.5 // indirect
github.com/open-telemetry/opentelemetry-collector-contrib/internal/coreinternal v0.124.1 // indirect
github.com/open-telemetry/opentelemetry-collector-contrib/pkg/core/xidutils v0.124.1 // indirect
github.com/open-telemetry/opentelemetry-collector-contrib/pkg/translator/jaeger v0.124.1 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.1.1 // indirect
github.com/opentracing-contrib/go-stdlib v1.0.0 // indirect
@@ -586,7 +582,6 @@ require (
go.etcd.io/etcd/client/v3 v3.5.21 // indirect
go.mongodb.org/mongo-driver v1.17.3 // indirect
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
go.opentelemetry.io/collector/semconv v0.124.0 // indirect
go.opentelemetry.io/contrib/bridges/prometheus v0.61.0 // indirect
go.opentelemetry.io/contrib/detectors/gcp v1.36.0 // indirect
go.opentelemetry.io/contrib/exporters/autoexport v0.61.0 // indirect
-13
View File
@@ -1793,8 +1793,6 @@ github.com/jackc/pgx/v5 v5.7.5 h1:JHGfMnQY+IEtGM63d+NGMjoRpysB2JBwDr5fsngwmJs=
github.com/jackc/pgx/v5 v5.7.5/go.mod h1:aruU7o91Tc2q2cFp5h4uP3f6ztExVpyVv88Xl/8Vl8M=
github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo=
github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
github.com/jaegertracing/jaeger v1.67.0 h1:t0BiJZVW9D3Z16y3uHqKzV9bKFTusooTH1Kgr77xF2Q=
github.com/jaegertracing/jaeger v1.67.0/go.mod h1:tE/FEQfybCSdUbBgel51YaCSkc58O+Njih8oTl6j8vw=
github.com/jaegertracing/jaeger-idl v0.5.0 h1:zFXR5NL3Utu7MhPg8ZorxtCBjHrL3ReM1VoB65FOFGE=
github.com/jaegertracing/jaeger-idl v0.5.0/go.mod h1:ON90zFo9eoyXrt9F/KN8YeF3zxcnujaisMweFY/rg5k=
github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8=
@@ -2107,12 +2105,6 @@ github.com/open-feature/go-sdk-contrib/providers/go-feature-flag v0.2.3 h1:6jpO6
github.com/open-feature/go-sdk-contrib/providers/go-feature-flag v0.2.3/go.mod h1:dPUHjAIFzg+ci/wt6XxlNiiMkOh5Yw4SGyeRY0AFT0g=
github.com/open-feature/go-sdk-contrib/providers/ofrep v0.1.5 h1:ZdqlGnNwhWf3luhBQlIpbglvcCzjkcuEgOEhYhr5Emc=
github.com/open-feature/go-sdk-contrib/providers/ofrep v0.1.5/go.mod h1:jrD4UG3ZCzuwImKHlyuIN2iWeYjlOX5+zJ/sX45efuE=
github.com/open-telemetry/opentelemetry-collector-contrib/internal/coreinternal v0.124.1 h1:NrjsoVPxI6lmV8jPImDcMeqYh+97Y71f/HB5Sfpfe3I=
github.com/open-telemetry/opentelemetry-collector-contrib/internal/coreinternal v0.124.1/go.mod h1:AFMryJmht7dZxcAwc2sx/r4gxbriElWw49ugxKp2mcA=
github.com/open-telemetry/opentelemetry-collector-contrib/pkg/core/xidutils v0.124.1 h1:E1e96GTHmiAfIfeYfA5ZVnOxud3+vbisGp0gE1tfd4s=
github.com/open-telemetry/opentelemetry-collector-contrib/pkg/core/xidutils v0.124.1/go.mod h1:MOhFATtYSLad9nKunjh6uGf8nQUcWje2LPlhD2uu3do=
github.com/open-telemetry/opentelemetry-collector-contrib/pkg/translator/jaeger v0.124.1 h1:9c6L4xlAMqhOg5y54Bc2B5t0i49yz7v2I6I8RY4Z0/o=
github.com/open-telemetry/opentelemetry-collector-contrib/pkg/translator/jaeger v0.124.1/go.mod h1:6f0N58o0cOHC0ApSM/qrooVmQza1eQ7L53PDE91uO1Q=
github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
@@ -2554,13 +2546,8 @@ go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
go.opentelemetry.io/collector v0.124.0 h1:g/dfdGFhBcQI0ggGxTmGlJnJ6Yl6T2gVxQoIj4UfXCc=
go.opentelemetry.io/collector/pdata v1.30.0 h1:j3jyq9um436r6WzWySzexP2nLnFdmL5uVBYAlyr9nDM=
go.opentelemetry.io/collector/pdata v1.30.0/go.mod h1:0Bxu1ktuj4wE7PIASNSvd0SdBscQ1PLtYasymJ13/Cs=
go.opentelemetry.io/collector/pdata/pprofile v0.124.0 h1:ZjL9wKqzP4BHj0/F1jfGxs1Va8B7xmYayipZeNVoWJE=
go.opentelemetry.io/collector/pdata/pprofile v0.124.0/go.mod h1:1EN3Gw5LSI4fSVma/Yfv/6nqeuYgRTm1/kmG5nE5Oyo=
go.opentelemetry.io/collector/semconv v0.124.0 h1:YTdo3UFwNyDQCh9DiSm2rbzAgBuwn/9dNZ0rv454goA=
go.opentelemetry.io/collector/semconv v0.124.0/go.mod h1:te6VQ4zZJO5Lp8dM2XIhDxDiL45mwX0YAQQWRQ0Qr9U=
go.opentelemetry.io/contrib/bridges/prometheus v0.61.0 h1:RyrtJzu5MAmIcbRrwg75b+w3RlZCP0vJByDVzcpAe3M=
go.opentelemetry.io/contrib/bridges/prometheus v0.61.0/go.mod h1:tirr4p9NXbzjlbruiRGp53IzlYrDk5CO2fdHj0sSSaY=
go.opentelemetry.io/contrib/detectors/gcp v1.36.0 h1:F7q2tNlCaHY9nMKHR6XH9/qkp8FktLnIcy6jJNyOCQw=
@@ -301,6 +301,10 @@ export interface FeatureToggles {
*/
queryService?: boolean;
/**
* Adds datasource connections to the query service
*/
queryServiceWithConnections?: boolean;
/**
* Rewrite requests targeting /ds/query to the query service
*/
queryServiceRewrite?: boolean;
+2 -2
View File
@@ -5,9 +5,9 @@ import (
"net/http"
"path"
"github.com/grafana/grafana-plugin-sdk-go/backend"
"k8s.io/apimachinery/pkg/runtime/serializer"
"github.com/grafana/grafana-plugin-sdk-go/backend"
aggregationv0alpha1 "github.com/grafana/grafana/pkg/aggregator/apis/aggregation/v0alpha1"
"github.com/grafana/grafana/pkg/aggregator/apiserver/plugin/admission"
)
@@ -64,7 +64,7 @@ func (h *PluginHandler) registerRoutes() {
case aggregationv0alpha1.DataSourceProxyServiceType:
// TODO: implement in future PR
case aggregationv0alpha1.QueryServiceType:
h.mux.Handle(proxyPath("/namespaces/{namespace}/connections/{uid}/query"), h.QueryDataHandler())
h.mux.Handle(proxyPath("/namespaces/{namespace}/datasources/{uid}/query"), h.QueryDataHandler())
case aggregationv0alpha1.RouteServiceType:
// TODO: implement in future PR
case aggregationv0alpha1.StreamServiceType:
+3 -3
View File
@@ -6,15 +6,15 @@ import (
"fmt"
"net/http"
"github.com/grafana/grafana-plugin-sdk-go/backend"
data "github.com/grafana/grafana-plugin-sdk-go/experimental/apis/data/v0alpha1"
grafanasemconv "github.com/grafana/grafana/pkg/semconv"
semconv "go.opentelemetry.io/otel/semconv/v1.21.0"
"k8s.io/component-base/tracing"
"k8s.io/klog/v2"
"github.com/grafana/grafana-plugin-sdk-go/backend"
data "github.com/grafana/grafana-plugin-sdk-go/experimental/apis/data/v0alpha1"
aggregationv0alpha1 "github.com/grafana/grafana/pkg/aggregator/apis/aggregation/v0alpha1"
"github.com/grafana/grafana/pkg/aggregator/apiserver/util"
grafanasemconv "github.com/grafana/grafana/pkg/semconv"
)
func (h *PluginHandler) QueryDataHandler() http.HandlerFunc {
@@ -10,13 +10,14 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana-plugin-sdk-go/data"
datav0alpha1 "github.com/grafana/grafana-plugin-sdk-go/experimental/apis/data/v0alpha1"
"github.com/grafana/grafana/pkg/aggregator/apis/aggregation/v0alpha1"
"github.com/grafana/grafana/pkg/aggregator/apiserver/plugin/fakes"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestQueryDataHandler(t *testing.T) {
@@ -87,7 +88,7 @@ func TestQueryDataHandler(t *testing.T) {
buf := bytes.NewBuffer(nil)
assert.NoError(t, json.NewEncoder(buf).Encode(qdr))
req, err := http.NewRequest("POST", "/apis/testds.example.com/v1/namespaces/default/connections/123/query", buf)
req, err := http.NewRequest("POST", "/apis/testds.example.com/v1/namespaces/default/datasources/123/query", buf)
assert.NoError(t, err)
rr := httptest.NewRecorder()
@@ -113,7 +114,7 @@ func TestQueryDataHandler(t *testing.T) {
buf := bytes.NewBuffer(nil)
assert.NoError(t, json.NewEncoder(buf).Encode(qdr))
req, err := http.NewRequest("POST", "/apis/testds.example.com/v1/namespaces/default/connections/123/query", buf)
req, err := http.NewRequest("POST", "/apis/testds.example.com/v1/namespaces/default/datasources/123/query", buf)
assert.NoError(t, err)
rr := httptest.NewRecorder()
@@ -141,7 +142,7 @@ func TestQueryDataHandler(t *testing.T) {
buf := bytes.NewBuffer(nil)
assert.NoError(t, json.NewEncoder(buf).Encode(qdr))
req, err := http.NewRequest("POST", "/apis/testds.example.com/v1/namespaces/default/connections/abc/query", buf)
req, err := http.NewRequest("POST", "/apis/testds.example.com/v1/namespaces/default/datasources/abc/query", buf)
assert.NoError(t, err)
rr := httptest.NewRecorder()
@@ -165,7 +166,7 @@ func TestQueryDataHandler(t *testing.T) {
})
t.Run("should return delegate response if group does not match", func(t *testing.T) {
req, err := http.NewRequest("POST", "/apis/wrongds.example.com/v1/namespaces/default/connections/abc/query", bytes.NewBuffer(nil))
req, err := http.NewRequest("POST", "/apis/wrongds.example.com/v1/namespaces/default/datasources/abc/query", bytes.NewBuffer(nil))
assert.NoError(t, err)
rr := httptest.NewRecorder()
-1
View File
@@ -53,5 +53,4 @@ import (
_ "github.com/grafana/e2e"
_ "github.com/grafana/gofpdf"
_ "github.com/grafana/gomemcache/memcache"
_ "github.com/grafana/tempo/pkg/traceql"
)
+42
View File
@@ -0,0 +1,42 @@
package datasource
import (
"context"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apiserver/pkg/registry/rest"
query "github.com/grafana/grafana/pkg/apis/query/v0alpha1"
)
// Temporary noop storage that lets us map /connections/{name}/query
type noopREST struct{}
var (
_ rest.Storage = (*noopREST)(nil)
_ rest.Scoper = (*noopREST)(nil)
_ rest.Getter = (*noopREST)(nil)
_ rest.SingularNameProvider = (*noopREST)(nil)
)
func (r *noopREST) New() runtime.Object {
return &query.QueryDataResponse{}
}
func (r *noopREST) Destroy() {}
func (r *noopREST) NamespaceScoped() bool {
return true
}
func (r *noopREST) GetSingularName() string {
return "noop"
}
func (r *noopREST) Get(ctx context.Context, name string, options *metav1.GetOptions) (runtime.Object, error) {
return &metav1.Status{
Status: metav1.StatusSuccess,
Message: "noop",
}, nil
}
+20
View File
@@ -54,6 +54,26 @@ func (b *DataSourceAPIBuilder) PostProcessOpenAPI(oas *spec3.OpenAPI) (*spec3.Op
ds.Properties["apiVersion"] = *spec.StringProperty().WithEnum(b.GetGroupVersion().String())
ds.Properties["kind"] = *spec.StringProperty().WithEnum("DataSource")
// Mark connections as deprecated
delete(oas.Paths.Paths, root+"namespaces/{namespace}/connections/{name}")
query := oas.Paths.Paths[root+"namespaces/{namespace}/connections/{name}/query"]
for query == nil || query.Post == nil {
return nil, fmt.Errorf("missing temporary connection path")
}
query.Post.Tags = []string{"Connections (deprecated)"}
query.Post.Deprecated = true
query.Post.RequestBody = &spec3.RequestBody{
RequestBodyProps: spec3.RequestBodyProps{
Content: map[string]*spec3.MediaType{
"application/json": {
MediaTypeProps: spec3.MediaTypeProps{
Schema: spec.MapProperty(nil),
},
},
},
},
}
if b.schemaProvider == nil {
return oas, nil
}
+8 -5
View File
@@ -3,6 +3,7 @@ package datasource
import (
"context"
"encoding/json"
"maps"
"github.com/prometheus/client_golang/prometheus"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -230,10 +231,14 @@ func (b *DataSourceAPIBuilder) UpdateAPIGroupInfo(apiGroupInfo *genericapiserver
storage[ds.StoragePath("query")] = &subQueryREST{builder: b}
storage[ds.StoragePath("health")] = &subHealthREST{builder: b}
// TODO! only setup this endpoint if it is implemented
storage[ds.StoragePath("resource")] = &subResourceREST{builder: b}
// FIXME: temporarily register both "datasources" and "connections" query paths
// This lets us deploy both datasources/{uid}/query and connections/{uid}/query
// while we transition requests to the new path
storage["connections"] = &noopREST{} // hidden from openapi
storage["connections/query"] = storage[ds.StoragePath("query")] // deprecated in openapi
// Frontend proxy
if len(b.pluginJSON.Routes) > 0 {
storage[ds.StoragePath("proxy")] = &subProxyREST{pluginJSON: b.pluginJSON}
@@ -262,9 +267,7 @@ func (b *DataSourceAPIBuilder) getPluginContext(ctx context.Context, uid string)
func (b *DataSourceAPIBuilder) GetOpenAPIDefinitions() openapi.GetOpenAPIDefinitions {
return func(ref openapi.ReferenceCallback) map[string]openapi.OpenAPIDefinition {
defs := queryV0.GetOpenAPIDefinitions(ref) // required when running standalone
for k, v := range datasourceV0.GetOpenAPIDefinitions(ref) {
defs[k] = v
}
maps.Copy(defs, datasourceV0.GetOpenAPIDefinitions(ref))
return defs
}
}
@@ -26,6 +26,7 @@ var (
_ rest.Storage = (*subQueryREST)(nil)
_ rest.Connecter = (*subQueryREST)(nil)
_ rest.StorageMetadata = (*subQueryREST)(nil)
_ rest.Scoper = (*subQueryREST)(nil)
)
func (r *subQueryREST) New() runtime.Object {
@@ -35,6 +36,10 @@ func (r *subQueryREST) New() runtime.Object {
func (r *subQueryREST) Destroy() {}
func (r *subQueryREST) NamespaceScoped() bool {
return true
}
func (r *subQueryREST) ProducesMIMETypes(verb string) []string {
return []string{"application/json"} // and parquet!
}
@@ -18,36 +18,36 @@ func TestResourceRequest(t *testing.T) {
}{
{
desc: "no resource path",
url: "http://localhost:6443/apis/test.datasource.grafana.app/v0alpha1/namespaces/default/connections/abc",
url: "http://localhost:6443/apis/test.datasource.grafana.app/v0alpha1/namespaces/default/datasources/abc",
error: true,
},
{
desc: "root resource path",
url: "http://localhost:6443/apis/test.datasource.grafana.app/v0alpha1/namespaces/default/connections/abc/resource",
url: "http://localhost:6443/apis/test.datasource.grafana.app/v0alpha1/namespaces/default/datasources/abc/resource",
expectedPath: "",
expectedURL: "",
},
{
desc: "root resource path",
url: "http://localhost:6443/apis/test.datasource.grafana.app/v0alpha1/namespaces/default/connections/abc/resource/",
url: "http://localhost:6443/apis/test.datasource.grafana.app/v0alpha1/namespaces/default/datasources/abc/resource/",
expectedPath: "",
expectedURL: "",
},
{
desc: "resource sub path",
url: "http://localhost:6443/apis/test.datasource.grafana.app/v0alpha1/namespaces/default/connections/abc/resource/test",
url: "http://localhost:6443/apis/test.datasource.grafana.app/v0alpha1/namespaces/default/datasources/abc/resource/test",
expectedPath: "test",
expectedURL: "test",
},
{
desc: "resource sub path with colon",
url: "http://localhost:6443/apis/test.datasource.grafana.app/v0alpha1/namespaces/default/connections/abc/resource/test-*,*:test-*/_mapping",
url: "http://localhost:6443/apis/test.datasource.grafana.app/v0alpha1/namespaces/default/datasources/abc/resource/test-*,*:test-*/_mapping",
expectedPath: "test-*,*:test-*/_mapping",
expectedURL: "./test-%2A,%2A:test-%2A/_mapping",
},
{
desc: "resource sub path with query params",
url: "http://localhost:6443/apis/test.datasource.grafana.app/v0alpha1/namespaces/default/connections/abc/resource/test?k1=v1&k2=v2",
url: "http://localhost:6443/apis/test.datasource.grafana.app/v0alpha1/namespaces/default/datasources/abc/resource/test?k1=v1&k2=v2",
expectedPath: "test",
expectedURL: "test?k1=v1&k2=v2",
},
@@ -66,21 +66,8 @@ func AddQueriesToOpenAPI(options OASQueryOptions) error {
// Rewrite the query path
query := oas.Paths.Paths[root+options.QueryPath]
if query != nil && query.Post != nil {
query.Post.Tags = []string{"Query"}
query.Parameters = []*spec3.Parameter{
{
ParameterProps: spec3.ParameterProps{
Name: "namespace",
In: "path",
Description: "object name and auth scope, such as for teams and projects",
Example: "default",
Required: true,
Schema: spec.StringProperty().UniqueValues(),
},
},
}
query.Post.Tags = []string{"DataSource"}
query.Post.Description = options.QueryDescription
query.Post.Parameters = nil //
query.Post.RequestBody = &spec3.RequestBody{
RequestBodyProps: spec3.RequestBodyProps{
Content: map[string]*spec3.MediaType{
+1 -1
View File
@@ -179,7 +179,7 @@ func (b *QueryAPIBuilder) UpdateAPIGroupInfo(apiGroupInfo *genericapiserver.APIG
storage := map[string]rest.Storage{}
// Get a list of all datasource instances
if b.features.IsEnabledGlobally(featuremgmt.FlagGrafanaAPIServerWithExperimentalAPIs) {
if b.features.IsEnabledGlobally(featuremgmt.FlagQueryServiceWithConnections) {
// Eventually this would be backed either by search or reconciler pattern
storage[query.ConnectionResourceInfo.StoragePath()] = &connectionAccess{
connections: b.connections,
+7
View File
@@ -499,6 +499,13 @@ var (
Owner: grafanaDatasourcesCoreServicesSquad,
RequiresRestart: true, // Adds a route at startup
},
{
Name: "queryServiceWithConnections",
Description: "Adds datasource connections to the query service",
Stage: FeatureStageExperimental,
Owner: grafanaDatasourcesCoreServicesSquad,
RequiresRestart: true, // Adds a route at startup
},
{
Name: "queryServiceRewrite",
Description: "Rewrite requests targeting /ds/query to the query service",
+1
View File
@@ -65,6 +65,7 @@ dashboardSchemaValidationLogging,experimental,@grafana/grafana-app-platform-squa
scanRowInvalidDashboardParseFallbackEnabled,experimental,@grafana/search-and-storage,false,false,false
datasourceQueryTypes,experimental,@grafana/grafana-app-platform-squad,false,true,false
queryService,experimental,@grafana/grafana-datasources-core-services,false,true,false
queryServiceWithConnections,experimental,@grafana/grafana-datasources-core-services,false,true,false
queryServiceRewrite,experimental,@grafana/grafana-datasources-core-services,false,true,false
queryServiceFromUI,experimental,@grafana/grafana-datasources-core-services,false,false,true
queryServiceFromExplore,experimental,@grafana/grafana-datasources-core-services,false,false,true
1 Name Stage Owner requiresDevMode RequiresRestart FrontendOnly
65 scanRowInvalidDashboardParseFallbackEnabled experimental @grafana/search-and-storage false false false
66 datasourceQueryTypes experimental @grafana/grafana-app-platform-squad false true false
67 queryService experimental @grafana/grafana-datasources-core-services false true false
68 queryServiceWithConnections experimental @grafana/grafana-datasources-core-services false true false
69 queryServiceRewrite experimental @grafana/grafana-datasources-core-services false true false
70 queryServiceFromUI experimental @grafana/grafana-datasources-core-services false false true
71 queryServiceFromExplore experimental @grafana/grafana-datasources-core-services false false true
+4
View File
@@ -271,6 +271,10 @@ const (
// Register /apis/query.grafana.app/ -- will eventually replace /api/ds/query
FlagQueryService = "queryService"
// FlagQueryServiceWithConnections
// Adds datasource connections to the query service
FlagQueryServiceWithConnections = "queryServiceWithConnections"
// FlagQueryServiceRewrite
// Rewrite requests targeting /ds/query to the query service
FlagQueryServiceRewrite = "queryServiceRewrite"
+13
View File
@@ -2765,6 +2765,19 @@
"requiresRestart": true
}
},
{
"metadata": {
"name": "queryServiceWithConnections",
"resourceVersion": "1756367172351",
"creationTimestamp": "2025-08-28T07:46:12Z"
},
"spec": {
"description": "Adds datasource connections to the query service",
"stage": "experimental",
"codeowner": "@grafana/grafana-datasources-core-services",
"requiresRestart": true
}
},
{
"metadata": {
"name": "recordedQueriesMulti",