diff --git a/docs/sources/setup-grafana/configure-grafana/feature-toggles/index.md b/docs/sources/setup-grafana/configure-grafana/feature-toggles/index.md index 3e9224b01b9..1c89be2d4f8 100644 --- a/docs/sources/setup-grafana/configure-grafana/feature-toggles/index.md +++ b/docs/sources/setup-grafana/configure-grafana/feature-toggles/index.md @@ -173,6 +173,7 @@ Experimental features might be changed or removed without prior notice. | `promQLScope` | In-development feature that will allow injection of labels into prometheus queries. | | `nodeGraphDotLayout` | Changed the layout algorithm for the node graph | | `newPDFRendering` | New implementation for the dashboard to PDF rendering | +| `kubernetesAggregator` | Enable grafana aggregator | ## Development feature toggles diff --git a/packages/grafana-data/src/types/featureToggles.gen.ts b/packages/grafana-data/src/types/featureToggles.gen.ts index 59acae823fa..64109324df6 100644 --- a/packages/grafana-data/src/types/featureToggles.gen.ts +++ b/packages/grafana-data/src/types/featureToggles.gen.ts @@ -176,4 +176,5 @@ export interface FeatureToggles { nodeGraphDotLayout?: boolean; groupToNestedTableTransformation?: boolean; newPDFRendering?: boolean; + kubernetesAggregator?: boolean; } diff --git a/pkg/registry/apis/service/register.go b/pkg/registry/apis/service/register.go index f7366b3badf..2d55353e2b6 100644 --- a/pkg/registry/apis/service/register.go +++ b/pkg/registry/apis/service/register.go @@ -26,6 +26,10 @@ func NewServiceAPIBuilder() *ServiceAPIBuilder { } func RegisterAPIService(features featuremgmt.FeatureToggles, apiregistration builder.APIRegistrar) *ServiceAPIBuilder { + if !features.IsEnabledGlobally(featuremgmt.FlagKubernetesAggregator) { + return nil // skip registration unless opting into aggregator mode + } + builder := NewServiceAPIBuilder() apiregistration.RegisterAPI(NewServiceAPIBuilder()) return builder diff --git a/pkg/services/apiserver/README.md b/pkg/services/apiserver/README.md index 2a4ead58fd9..98df14b6dc1 100644 --- a/pkg/services/apiserver/README.md +++ b/pkg/services/apiserver/README.md @@ -4,7 +4,6 @@ ```ini [feature_toggles] -grafanaAPIServer = true kubernetesPlaylists = true ``` @@ -51,6 +50,10 @@ data/grafana-apiserver └── hi.json ``` +## Enable aggregation + +See [aggregator/README.md](./aggregator/README.md) for more information. + ### `kubectl` access For kubectl to work, grafana needs to run over https. To simplify development, you can use: @@ -59,7 +62,6 @@ For kubectl to work, grafana needs to run over https. To simplify development, app_mode = development [feature_toggles] -grafanaAPIServer = true grafanaAPIServerEnsureKubectlAccess = true kubernetesPlaylists = true ``` diff --git a/pkg/services/apiserver/aggregator/README.md b/pkg/services/apiserver/aggregator/README.md index 3ba1df70605..bf8a6a5a21b 100644 --- a/pkg/services/apiserver/aggregator/README.md +++ b/pkg/services/apiserver/aggregator/README.md @@ -15,10 +15,13 @@ roll out features for each service without downtime. To read more about the concept, see [here](https://kubernetes.io/docs/tasks/extend-kubernetes/setup-extension-api-server/). -Note that, this aggregation will be a totally internal detail to Grafana. External fully functional APIServers that -may themselves act as parent API Servers to Grafana will never be made aware of them. Any of the `APIService` -related to Grafana Groups registered in a real K8s environment will take the address of Grafana's -parent server (which will bundle grafana-aggregator). +Note that this aggregation will be a totally internal detail to Grafana. External fully functional API Servers that +may themselves act as parent API Servers to Grafana will never be made aware of internal Grafana API Servers. +Thus, any `APIService` objects corresponding to Grafana's API groups will take the address of +Grafana's main API Server (the one that bundles grafana-aggregator). + +Also, note that the single binary OSS offering of Grafana doesn't make use of the aggregator component at all, instead +opting for local installation of all the Grafana API groups. ### kube-aggregator versus grafana-aggregator @@ -41,7 +44,65 @@ live under that instead. ### Gotchas (Pay Attention) -1. `grafana-aggregator` uses file storage under `data/grafana-aggregator` (`apiregistration.k8s.io`, -`service.grafana.app`) and `data/grafana-apiextensions` (`apiextensions.k8s.io`). -2. Since `grafana-aggregator` outputs configuration (TLS and kubeconfig) that is used in the invocation of aggregated - servers, ensure you start the aggregated service after launching the aggregator during local development. +1. `grafana-aggregator` uses file storage under `data/grafana-apiserver` (`apiregistration.k8s.io`, +`service.grafana.app`). Thus, any restarts will still have any prior configured aggregation in effect. +2. During local development, ensure you start the aggregated service after launching the aggregator. This is +so you have TLS and kubeconfig available for use with example aggregated api servers. +3. Ensure you have `grafanaAPIServerWithExperimentalAPIs = false` in your custom.ini. Otherwise, the example +service the following guide uses for the aggregation test is bundled as a `Local` `APIService` and will cause +configuration overwrites on startup. + +## Testing aggregation locally + +1. Generate the PKI using `openssl` (for development purposes, we will use the CN of `system:masters`): + ```shell + ./hack/make-aggregator-pki.sh + ``` +2. Configure the aggregator: + ```ini + [feature_toggles] + grafanaAPIServerEnsureKubectlAccess = true + ; disable the experimental APIs flag to disable bundling of the example service locally + grafanaAPIServerWithExperimentalAPIs = false + kubernetesAggregator = true + + [grafana-apiserver] + proxy_client_cert_file = ./data/grafana-aggregator/client.crt + proxy_client_key_file = ./data/grafana-aggregator/client.key + ``` +3. Start the server + ```shell + make run + ``` +4. In another tab, apply the manifests: + ```shell + export KUBECONFIG=$PWD/data/grafana-apiserver/grafana.kubeconfig + kubectl apply -f ./pkg/services/apiserver/aggregator/examples/ + # SAMPLE OUTPUT + # apiservice.apiregistration.k8s.io/v0alpha1.example.grafana.app created + # externalname.service.grafana.app/example-apiserver created + + kubectl get apiservice + # SAMPLE OUTPUT + # NAME SERVICE AVAILABLE AGE + # v0alpha1.example.grafana.app grafana/example-apiserver False (FailedDiscoveryCheck) 29m + ``` +5. In another tab, start the example microservice that will be aggregated by the parent apiserver: + ```shell + go run ./pkg/cmd/grafana apiserver \ + --runtime-config=example.grafana.app/v0alpha1=true \ + --secure-port 7443 \ + --client-ca-file=$PWD/data/grafana-aggregator/ca.crt + ``` +6. After 10 seconds, check `APIService` again. It should report as available. + ```shell + export KUBECONFIG=$PWD/data/grafana-apiserver/grafana.kubeconfig + kubectl get apiservice + # SAMPLE OUTPUT + # NAME SERVICE AVAILABLE AGE + # v0alpha1.example.grafana.app grafana/example-apiserver True 30m + ``` +7. For tear down of the above test: + ```shell + kubectl delete -f ./pkg/services/apiserver/aggregator/examples/ + ``` diff --git a/pkg/services/apiserver/aggregator/aggregator.go b/pkg/services/apiserver/aggregator/aggregator.go index b62e106446e..df68b6b39f3 100644 --- a/pkg/services/apiserver/aggregator/aggregator.go +++ b/pkg/services/apiserver/aggregator/aggregator.go @@ -104,9 +104,7 @@ func CreateAggregatorServer(aggregatorConfig *aggregatorapiserver.Config, shared } err = aggregatorServer.GenericAPIServer.AddPostStartHook("grafana-apiserver-autoregistration", func(context genericapiserver.PostStartHookContext) error { - go func() { - autoRegistrationController.Run(5, context.StopCh) - }() + go autoRegistrationController.Run(5, context.StopCh) return nil }) if err != nil { @@ -198,16 +196,20 @@ func makeAPIServiceAvailableHealthCheck(name string, apiServices []*v1.APIServic } // Watch add/update events for APIServices - _, _ = apiServiceInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{ + _, err := apiServiceInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{ AddFunc: func(obj interface{}) { handleAPIServiceChange(obj.(*v1.APIService)) }, UpdateFunc: func(old, new interface{}) { handleAPIServiceChange(new.(*v1.APIService)) }, }) + if err != nil { + klog.Errorf("Failed to watch APIServices for health check: %v", err) + } // Don't return healthy until the pending list is empty return healthz.NamedCheck(name, func(r *http.Request) error { pendingServiceNamesLock.RLock() defer pendingServiceNamesLock.RUnlock() if pendingServiceNames.Len() > 0 { + klog.Error("APIServices not yet available", "services", pendingServiceNames.List()) return fmt.Errorf("missing APIService: %v", pendingServiceNames.List()) } return nil diff --git a/pkg/services/apiserver/aggregator/examples/apiservice.yaml b/pkg/services/apiserver/aggregator/examples/apiservice.yaml new file mode 100644 index 00000000000..23aedac6226 --- /dev/null +++ b/pkg/services/apiserver/aggregator/examples/apiservice.yaml @@ -0,0 +1,14 @@ +apiVersion: apiregistration.k8s.io/v1 +kind: APIService +metadata: + name: v0alpha1.example.grafana.app +spec: + version: v0alpha1 + insecureSkipTLSVerify: true + group: example.grafana.app + groupPriorityMinimum: 1000 + versionPriority: 15 + service: + name: example-apiserver + namespace: grafana + port: 7443 \ No newline at end of file diff --git a/pkg/services/apiserver/aggregator/examples/externalname.yaml b/pkg/services/apiserver/aggregator/examples/externalname.yaml new file mode 100644 index 00000000000..1cd09d38566 --- /dev/null +++ b/pkg/services/apiserver/aggregator/examples/externalname.yaml @@ -0,0 +1,7 @@ +apiVersion: service.grafana.app/v0alpha1 +kind: ExternalName +metadata: + name: example-apiserver + namespace: grafana +spec: + host: localhost \ No newline at end of file diff --git a/pkg/services/apiserver/auth/authorizer/provider.go b/pkg/services/apiserver/auth/authorizer/provider.go index f8ab2a79d0f..5cd92982e40 100644 --- a/pkg/services/apiserver/auth/authorizer/provider.go +++ b/pkg/services/apiserver/auth/authorizer/provider.go @@ -4,7 +4,9 @@ import ( "context" "k8s.io/apimachinery/pkg/runtime/schema" + k8suser "k8s.io/apiserver/pkg/authentication/user" "k8s.io/apiserver/pkg/authorization/authorizer" + "k8s.io/apiserver/pkg/authorization/authorizerfactory" "k8s.io/apiserver/pkg/authorization/union" orgsvc "github.com/grafana/grafana/pkg/services/org" @@ -21,6 +23,7 @@ type GrafanaAuthorizer struct { func NewGrafanaAuthorizer(cfg *setting.Cfg, orgService orgsvc.Service) *GrafanaAuthorizer { authorizers := []authorizer.Authorizer{ &impersonationAuthorizer{}, + authorizerfactory.NewPrivilegedGroups(k8suser.SystemPrivilegedGroup), } // In Hosted grafana, the StackID replaces the orgID as a valid namespace diff --git a/pkg/services/apiserver/config.go b/pkg/services/apiserver/config.go index 3cc6fc82d07..dbd6abfa3e9 100644 --- a/pkg/services/apiserver/config.go +++ b/pkg/services/apiserver/config.go @@ -29,20 +29,25 @@ func applyGrafanaConfig(cfg *setting.Cfg, features featuremgmt.FeatureToggles, o host := fmt.Sprintf("%s:%d", ip, port) - o.RecommendedOptions.Etcd.StorageConfig.Transport.ServerList = cfg.SectionWithEnvOverrides("grafana-apiserver").Key("etcd_servers").Strings(",") + apiserverCfg := cfg.SectionWithEnvOverrides("grafana-apiserver") + + o.RecommendedOptions.Etcd.StorageConfig.Transport.ServerList = apiserverCfg.Key("etcd_servers").Strings(",") o.RecommendedOptions.SecureServing.BindAddress = ip o.RecommendedOptions.SecureServing.BindPort = port o.RecommendedOptions.Authentication.RemoteKubeConfigFileOptional = true o.RecommendedOptions.Authorization.RemoteKubeConfigFileOptional = true + o.AggregatorOptions.ProxyClientCertFile = apiserverCfg.Key("proxy_client_cert_file").MustString("") + o.AggregatorOptions.ProxyClientKeyFile = apiserverCfg.Key("proxy_client_key_file").MustString("") + o.RecommendedOptions.Admission = nil o.RecommendedOptions.CoreAPI = nil - o.StorageOptions.StorageType = options.StorageType(cfg.SectionWithEnvOverrides("grafana-apiserver").Key("storage_type").MustString(string(options.StorageTypeLegacy))) + o.StorageOptions.StorageType = options.StorageType(apiserverCfg.Key("storage_type").MustString(string(options.StorageTypeLegacy))) o.StorageOptions.DataPath = filepath.Join(cfg.DataPath, "grafana-apiserver") o.ExtraOptions.DevMode = features.IsEnabledGlobally(featuremgmt.FlagGrafanaAPIServerEnsureKubectlAccess) o.ExtraOptions.ExternalAddress = host o.ExtraOptions.APIURL = apiURL - o.ExtraOptions.Verbosity = defaultLogLevel + o.ExtraOptions.Verbosity = apiserverCfg.Key("log_level").MustInt(defaultLogLevel) } diff --git a/pkg/services/apiserver/endpoints/responsewriter/responsewriter.go b/pkg/services/apiserver/endpoints/responsewriter/responsewriter.go new file mode 100644 index 00000000000..6e635203cfa --- /dev/null +++ b/pkg/services/apiserver/endpoints/responsewriter/responsewriter.go @@ -0,0 +1,132 @@ +package responsewriter + +import ( + "bufio" + "fmt" + "io" + "net/http" + + "k8s.io/apiserver/pkg/endpoints/responsewriter" + "k8s.io/klog/v2" +) + +var _ responsewriter.CloseNotifierFlusher = (*ResponseAdapter)(nil) +var _ http.ResponseWriter = (*ResponseAdapter)(nil) +var _ io.ReadCloser = (*ResponseAdapter)(nil) + +func WrapHandler(handler http.Handler) func(req *http.Request) (*http.Response, error) { + // ignore the lint error because the response is passed directly to the client, + // so the client will be responsible for closing the response body. + //nolint:bodyclose + return func(req *http.Request) (*http.Response, error) { + w := NewAdapter(req) + resp := w.Response() + go func() { + handler.ServeHTTP(w, req) + if err := w.CloseWriter(); err != nil { + klog.Errorf("error closing writer: %v", err) + } + }() + return resp, nil + } +} + +// ResponseAdapter is an implementation of [http.ResponseWriter] that allows conversion to a [http.Response]. +type ResponseAdapter struct { + req *http.Request + res *http.Response + reader io.ReadCloser + writer io.WriteCloser + buffered *bufio.ReadWriter +} + +// NewAdapter returns an initialized [ResponseAdapter]. +func NewAdapter(req *http.Request) *ResponseAdapter { + r, w := io.Pipe() + writer := bufio.NewWriter(w) + reader := bufio.NewReader(r) + buffered := bufio.NewReadWriter(reader, writer) + return &ResponseAdapter{ + req: req, + res: &http.Response{ + Proto: req.Proto, + ProtoMajor: req.ProtoMajor, + ProtoMinor: req.ProtoMinor, + Header: make(http.Header), + }, + reader: r, + writer: w, + buffered: buffered, + } +} + +// Header implements [http.ResponseWriter]. +// It returns the response headers to mutate within a handler. +func (ra *ResponseAdapter) Header() http.Header { + return ra.res.Header +} + +// Write implements [http.ResponseWriter]. +func (ra *ResponseAdapter) Write(buf []byte) (int, error) { + return ra.buffered.Write(buf) +} + +// Read implements [io.Reader]. +func (ra *ResponseAdapter) Read(buf []byte) (int, error) { + return ra.buffered.Read(buf) +} + +// WriteHeader implements [http.ResponseWriter]. +func (ra *ResponseAdapter) WriteHeader(code int) { + ra.res.StatusCode = code + ra.res.Status = fmt.Sprintf("%03d %s", code, http.StatusText(code)) +} + +// Flush implements [http.Flusher]. +func (ra *ResponseAdapter) Flush() { + if ra.buffered.Writer.Buffered() == 0 { + return + } + + if err := ra.buffered.Writer.Flush(); err != nil { + klog.Error("Error flushing response buffer: ", "error", err) + } +} + +// Response returns the [http.Response] generated by the [http.Handler]. +func (ra *ResponseAdapter) Response() *http.Response { + // make sure to set the status code to 200 if the request is a watch + // this is to ensure that client-go uses a streamwatcher: + // https://github.com/kubernetes/client-go/blob/76174b8af8cfd938018b04198595d65b48a69334/rest/request.go#L737 + if ra.res.StatusCode == 0 && ra.req.URL.Query().Get("watch") == "true" { + ra.WriteHeader(http.StatusOK) + } + ra.res.Body = ra + return ra.res +} + +// Decorate implements [responsewriter.UserProvidedDecorator]. +func (ra *ResponseAdapter) Unwrap() http.ResponseWriter { + return ra +} + +// CloseNotify implements [http.CloseNotifier]. +func (ra *ResponseAdapter) CloseNotify() <-chan bool { + ch := make(chan bool) + go func() { + <-ra.req.Context().Done() + ch <- true + }() + return ch +} + +// Close implements [io.Closer]. +func (ra *ResponseAdapter) Close() error { + return ra.reader.Close() +} + +// CloseWriter should be called after the http.Handler has returned. +func (ra *ResponseAdapter) CloseWriter() error { + ra.Flush() + return ra.writer.Close() +} diff --git a/pkg/services/apiserver/endpoints/responsewriter/responsewriter_test.go b/pkg/services/apiserver/endpoints/responsewriter/responsewriter_test.go new file mode 100644 index 00000000000..a2c0c5eace8 --- /dev/null +++ b/pkg/services/apiserver/endpoints/responsewriter/responsewriter_test.go @@ -0,0 +1,136 @@ +package responsewriter_test + +import ( + "io" + "math/rand" + "net/http" + "testing" + "time" + + grafanaresponsewriter "github.com/grafana/grafana/pkg/services/apiserver/endpoints/responsewriter" + "github.com/stretchr/testify/require" +) + +func TestResponseAdapter(t *testing.T) { + t.Run("should handle synchronous write", func(t *testing.T) { + client := &http.Client{ + Transport: &roundTripperFunc{ + ready: make(chan struct{}), + // ignore the lint error because the response is passed directly to the client, + // so the client will be responsible for closing the response body. + //nolint:bodyclose + fn: grafanaresponsewriter.WrapHandler(http.HandlerFunc(syncHandler)), + }, + } + close(client.Transport.(*roundTripperFunc).ready) + req, err := http.NewRequest("GET", "http://localhost/test", nil) + require.NoError(t, err) + + resp, err := client.Do(req) + require.NoError(t, err) + + defer func() { + err := resp.Body.Close() + require.NoError(t, err) + }() + + bodyBytes, err := io.ReadAll(resp.Body) + require.NoError(t, err) + require.Equal(t, "OK", string(bodyBytes)) + }) + + t.Run("should handle synchronous write", func(t *testing.T) { + generateRandomStrings(10) + client := &http.Client{ + Transport: &roundTripperFunc{ + ready: make(chan struct{}), + // ignore the lint error because the response is passed directly to the client, + // so the client will be responsible for closing the response body. + //nolint:bodyclose + fn: grafanaresponsewriter.WrapHandler(http.HandlerFunc(asyncHandler)), + }, + } + close(client.Transport.(*roundTripperFunc).ready) + req, err := http.NewRequest("GET", "http://localhost/test?watch=true", nil) + require.NoError(t, err) + + resp, err := client.Do(req) + require.NoError(t, err) + + defer func() { + err := resp.Body.Close() + require.NoError(t, err) + }() + + // ensure that watch request is a 200 + require.Equal(t, http.StatusOK, resp.StatusCode) + + // limit to 100 bytes to test the reader buffer + buf := make([]byte, 100) + // holds the read bytes between iterations + cache := []byte{} + + for i := 0; i < 10; { + n, err := resp.Body.Read(buf) + require.NoError(t, err) + if n == 0 { + continue + } + cache = append(cache, buf[:n]...) + + if len(cache) >= len(randomStrings[i]) { + str := cache[:len(randomStrings[i])] + require.Equal(t, randomStrings[i], string(str)) + cache = cache[len(randomStrings[i]):] + i++ + } + } + }) +} + +func syncHandler(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + _, _ = w.Write([]byte("OK")) +} + +func asyncHandler(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + for _, s := range randomStrings { + time.Sleep(100 * time.Millisecond) + // write the current iteration + _, _ = w.Write([]byte(s)) + w.(http.Flusher).Flush() + } +} + +var randomStrings = []string{} + +func generateRandomStrings(n int) { + for i := 0; i < n; i++ { + randomString := generateRandomString(1000 * (i + 1)) + randomStrings = append(randomStrings, randomString) + } +} + +func generateRandomString(n int) string { + gen := rand.New(rand.NewSource(time.Now().UnixNano())) + var chars = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") + b := make([]rune, n) + for i := range b { + b[i] = chars[gen.Intn(len(chars))] + } + return string(b) +} + +type roundTripperFunc struct { + ready chan struct{} + fn func(req *http.Request) (*http.Response, error) +} + +func (f *roundTripperFunc) RoundTrip(req *http.Request) (*http.Response, error) { + if f.fn == nil { + <-f.ready + } + res, err := f.fn(req) + return res, err +} diff --git a/pkg/services/apiserver/options/aggregator.go b/pkg/services/apiserver/options/aggregator.go index 51c67cea117..33c210ae538 100644 --- a/pkg/services/apiserver/options/aggregator.go +++ b/pkg/services/apiserver/options/aggregator.go @@ -97,6 +97,9 @@ func (o *AggregatorServerOptions) ApplyTo(aggregatorConfig *aggregatorapiserver. } genericConfig.MergedResourceConfig = mergedResourceConfig + aggregatorConfig.ExtraConfig.ProxyClientCertFile = o.ProxyClientCertFile + aggregatorConfig.ExtraConfig.ProxyClientKeyFile = o.ProxyClientKeyFile + namer := openapinamer.NewDefinitionNamer(aggregatorscheme.Scheme) genericConfig.OpenAPIV3Config = genericapiserver.DefaultOpenAPIV3Config(o.getMergedOpenAPIDefinitions, namer) genericConfig.OpenAPIV3Config.Info.Title = "Kubernetes" diff --git a/pkg/services/apiserver/options/options.go b/pkg/services/apiserver/options/options.go index c9b6d5450b7..32a07be624f 100644 --- a/pkg/services/apiserver/options/options.go +++ b/pkg/services/apiserver/options/options.go @@ -75,6 +75,9 @@ func (o *Options) Validate() []error { func (o *Options) ApplyTo(serverConfig *genericapiserver.RecommendedConfig) error { serverConfig.AggregatedDiscoveryGroupManager = aggregated.NewResourceManager("apis") + // avoid picking up an in-cluster service account token + o.RecommendedOptions.Authentication.SkipInClusterLookup = true + if err := o.ExtraOptions.ApplyTo(serverConfig); err != nil { return err } @@ -87,12 +90,8 @@ func (o *Options) ApplyTo(serverConfig *genericapiserver.RecommendedConfig) erro return err } - if o.ExtraOptions.DevMode { - // NOTE: Only consider authn for dev mode - resolves the failure due to missing extension apiserver auth-config - // in parent k8s - if err := o.RecommendedOptions.Authentication.ApplyTo(&serverConfig.Authentication, serverConfig.SecureServing, serverConfig.OpenAPIConfig); err != nil { - return err - } + if err := o.RecommendedOptions.Authentication.ApplyTo(&serverConfig.Authentication, serverConfig.SecureServing, serverConfig.OpenAPIConfig); err != nil { + return err } if !o.ExtraOptions.DevMode { diff --git a/pkg/services/apiserver/service.go b/pkg/services/apiserver/service.go index 7e85e8704b1..8233c4bd51c 100644 --- a/pkg/services/apiserver/service.go +++ b/pkg/services/apiserver/service.go @@ -4,7 +4,6 @@ import ( "context" "fmt" "net/http" - "net/http/httptest" "path" "github.com/grafana/dskit/services" @@ -26,8 +25,10 @@ import ( "github.com/grafana/grafana/pkg/middleware" "github.com/grafana/grafana/pkg/modules" "github.com/grafana/grafana/pkg/registry" + "github.com/grafana/grafana/pkg/services/apiserver/aggregator" "github.com/grafana/grafana/pkg/services/apiserver/auth/authorizer" "github.com/grafana/grafana/pkg/services/apiserver/builder" + grafanaresponsewriter "github.com/grafana/grafana/pkg/services/apiserver/endpoints/responsewriter" grafanaapiserveroptions "github.com/grafana/grafana/pkg/services/apiserver/options" entitystorage "github.com/grafana/grafana/pkg/services/apiserver/storage/entity" filestorage "github.com/grafana/grafana/pkg/services/apiserver/storage/file" @@ -189,12 +190,17 @@ func (s *service) start(ctx context.Context) error { groupVersions := make([]schema.GroupVersion, 0, len(builders)) // Install schemas - for _, b := range builders { + for i, b := range builders { groupVersions = append(groupVersions, b.GetGroupVersion()) if err := b.InstallSchema(Scheme); err != nil { return err } + if s.features.IsEnabledGlobally(featuremgmt.FlagKubernetesAggregator) { + // set the priority for the group+version + aggregator.APIVersionPriorities[b.GetGroupVersion()] = aggregator.Priority{Group: 15000, Version: int32(i + 1)} + } + auth := b.GetAuthorizer() if auth != nil { s.authorizer.Register(b.GetGroupVersion(), auth) @@ -216,7 +222,7 @@ func (s *service) start(ctx context.Context) error { serverConfig.Authorization.Authorizer = s.authorizer serverConfig.TracerProvider = s.tracing.GetTracerProvider() - // setup loopback transport + // setup loopback transport for the aggregator server transport := &roundTripperFunc{ready: make(chan struct{})} serverConfig.LoopbackClientConfig.Transport = transport serverConfig.LoopbackClientConfig.TLSClientConfig = clientrest.TLSClientConfig{} @@ -283,41 +289,100 @@ func (s *service) start(ctx context.Context) error { return err } + // dual writing is only enabled when the storage type is not legacy. + // this is needed to support setting a default RESTOptionsGetter for new APIs that don't + // support the legacy storage type. dualWriteEnabled := o.StorageOptions.StorageType != grafanaapiserveroptions.StorageTypeLegacy - // Install the API Group+version + // Install the API group+version err = builder.InstallAPIs(Scheme, Codecs, server, serverConfig.RESTOptionsGetter, builders, dualWriteEnabled) if err != nil { return err } - // set the transport function and signal that it's ready - transport.fn = func(req *http.Request) (*http.Response, error) { - w := newWrappedResponseWriter() - resp := responsewriter.WrapForHTTP1Or2(w) - server.Handler.ServeHTTP(resp, req) - return w.Result(), nil - } - close(transport.ready) + // stash the options for later use + s.options = o - // only write kubeconfig in dev mode - if o.ExtraOptions.DevMode { - if err := ensureKubeConfig(server.LoopbackClientConfig, o.StorageOptions.DataPath); err != nil { + var runningServer *genericapiserver.GenericAPIServer + if s.features.IsEnabledGlobally(featuremgmt.FlagKubernetesAggregator) { + runningServer, err = s.startAggregator(transport, serverConfig, server) + if err != nil { + return err + } + } else { + runningServer, err = s.startCoreServer(transport, serverConfig, server) + if err != nil { return err } } - // Used by the proxy wrapper registered in ProvideService - s.handler = server.Handler - s.restConfig = server.LoopbackClientConfig - s.options = o + // only write kubeconfig in dev mode + if o.ExtraOptions.DevMode { + if err := ensureKubeConfig(runningServer.LoopbackClientConfig, o.StorageOptions.DataPath); err != nil { + return err + } + } + + // used by the proxy wrapper registered in ProvideService + s.handler = runningServer.Handler + // used by local clients to make requests to the server + s.restConfig = runningServer.LoopbackClientConfig + + return nil +} + +func (s *service) startCoreServer( + transport *roundTripperFunc, + serverConfig *genericapiserver.RecommendedConfig, + server *genericapiserver.GenericAPIServer, +) (*genericapiserver.GenericAPIServer, error) { + // setup the loopback transport and signal that it's ready. + // ignore the lint error because the response is passed directly to the client, + // so the client will be responsible for closing the response body. + // nolint:bodyclose + transport.fn = grafanaresponsewriter.WrapHandler(server.Handler) + close(transport.ready) prepared := server.PrepareRun() + go func() { + s.stoppedCh <- prepared.Run(s.stopCh) + }() + + return server, nil +} + +func (s *service) startAggregator( + transport *roundTripperFunc, + serverConfig *genericapiserver.RecommendedConfig, + server *genericapiserver.GenericAPIServer, +) (*genericapiserver.GenericAPIServer, error) { + aggregatorConfig, aggregatorInformers, err := aggregator.CreateAggregatorConfig(s.options, *serverConfig) + if err != nil { + return nil, err + } + + aggregatorServer, err := aggregator.CreateAggregatorServer(aggregatorConfig, aggregatorInformers, server) + if err != nil { + return nil, err + } + + // setup the loopback transport for the aggregator server and signal that it's ready + // ignore the lint error because the response is passed directly to the client, + // so the client will be responsible for closing the response body. + // nolint:bodyclose + transport.fn = grafanaresponsewriter.WrapHandler(aggregatorServer.GenericAPIServer.Handler) + close(transport.ready) + + prepared, err := aggregatorServer.PrepareRun() + if err != nil { + return nil, err + } go func() { s.stoppedCh <- prepared.Run(s.stopCh) }() - return nil + + return aggregatorServer.GenericAPIServer, nil } func (s *service) GetDirectRestConfig(c *contextmodel.ReqContext) *clientrest.Config { @@ -325,9 +390,8 @@ func (s *service) GetDirectRestConfig(c *contextmodel.ReqContext) *clientrest.Co Transport: &roundTripperFunc{ fn: func(req *http.Request) (*http.Response, error) { ctx := appcontext.WithUser(req.Context(), c.SignedInUser) - w := httptest.NewRecorder() - s.handler.ServeHTTP(w, req.WithContext(ctx)) - return w.Result(), nil + wrapped := grafanaresponsewriter.WrapHandler(s.handler) + return wrapped(req.WithContext(ctx)) }, }, } @@ -367,24 +431,3 @@ func (f *roundTripperFunc) RoundTrip(req *http.Request) (*http.Response, error) } return f.fn(req) } - -var _ http.ResponseWriter = (*wrappedResponseWriter)(nil) -var _ responsewriter.UserProvidedDecorator = (*wrappedResponseWriter)(nil) - -type wrappedResponseWriter struct { - *httptest.ResponseRecorder -} - -func newWrappedResponseWriter() *wrappedResponseWriter { - w := httptest.NewRecorder() - return &wrappedResponseWriter{w} -} - -func (w *wrappedResponseWriter) Unwrap() http.ResponseWriter { - return w.ResponseRecorder -} - -func (w *wrappedResponseWriter) CloseNotify() <-chan bool { - // TODO: this is probably not the right thing to do here - return make(<-chan bool) -} diff --git a/pkg/services/apiserver/storage/file/file.go b/pkg/services/apiserver/storage/file/file.go index 12d376b448c..20f9b5c9c31 100644 --- a/pkg/services/apiserver/storage/file/file.go +++ b/pkg/services/apiserver/storage/file/file.go @@ -12,6 +12,7 @@ import ( "path/filepath" "reflect" "strings" + "sync" "time" "github.com/bwmarrin/snowflake" @@ -57,8 +58,16 @@ var ErrFileNotExists = fmt.Errorf("file doesn't exist") // ErrNamespaceNotExists means the directory for the namespace doesn't actually exist. var ErrNamespaceNotExists = errors.New("namespace does not exist") +var ( + node *snowflake.Node + once sync.Once +) + func getResourceVersion() (*uint64, error) { - node, err := snowflake.NewNode(1) + var err error + once.Do(func() { + node, err = snowflake.NewNode(1) + }) if err != nil { return nil, err } diff --git a/pkg/services/featuremgmt/registry.go b/pkg/services/featuremgmt/registry.go index ed59e97e789..9d9f60edccd 100644 --- a/pkg/services/featuremgmt/registry.go +++ b/pkg/services/featuremgmt/registry.go @@ -1176,6 +1176,13 @@ var ( Stage: FeatureStageExperimental, Owner: grafanaSharingSquad, }, + { + Name: "kubernetesAggregator", + Description: "Enable grafana aggregator", + Stage: FeatureStageExperimental, + Owner: grafanaAppPlatformSquad, + RequiresRestart: true, + }, } ) diff --git a/pkg/services/featuremgmt/toggles_gen.csv b/pkg/services/featuremgmt/toggles_gen.csv index 2c7f35fe410..ad0575f2234 100644 --- a/pkg/services/featuremgmt/toggles_gen.csv +++ b/pkg/services/featuremgmt/toggles_gen.csv @@ -157,3 +157,4 @@ promQLScope,experimental,@grafana/observability-metrics,false,false,false nodeGraphDotLayout,experimental,@grafana/observability-traces-and-profiling,false,false,true groupToNestedTableTransformation,preview,@grafana/dataviz-squad,false,false,true newPDFRendering,experimental,@grafana/sharing-squad,false,false,false +kubernetesAggregator,experimental,@grafana/grafana-app-platform-squad,false,true,false diff --git a/pkg/services/featuremgmt/toggles_gen.go b/pkg/services/featuremgmt/toggles_gen.go index 7456a13c927..8c6f3f2c0f2 100644 --- a/pkg/services/featuremgmt/toggles_gen.go +++ b/pkg/services/featuremgmt/toggles_gen.go @@ -638,4 +638,8 @@ const ( // FlagNewPDFRendering // New implementation for the dashboard to PDF rendering FlagNewPDFRendering = "newPDFRendering" + + // FlagKubernetesAggregator + // Enable grafana aggregator + FlagKubernetesAggregator = "kubernetesAggregator" ) diff --git a/pkg/services/featuremgmt/toggles_gen.json b/pkg/services/featuremgmt/toggles_gen.json index cf6e9db6a5f..4d3bf331c0c 100644 --- a/pkg/services/featuremgmt/toggles_gen.json +++ b/pkg/services/featuremgmt/toggles_gen.json @@ -3,90 +3,11 @@ "apiVersion": "featuretoggle.grafana.app/v0alpha1", "metadata": {}, "items": [ - { - "metadata": { - "name": "disableEnvelopeEncryption", - "resourceVersion": "1653393600000", - "creationTimestamp": "2022-05-24T12:00:00Z" - }, - "spec": { - "description": "Disable envelope encryption (emergency only)", - "stage": "GA", - "codeowner": "@grafana/grafana-as-code", - "hideFromAdminPage": true - } - }, - { - "metadata": { - "name": "live-service-web-worker", - "resourceVersion": "1636459200000", - "creationTimestamp": "2021-11-09T12:00:00Z" - }, - "spec": { - "description": "This will use a webworker thread to processes events rather than the main thread", - "stage": "experimental", - "codeowner": "@grafana/grafana-app-platform-squad", - "frontend": true - } - }, - { - "metadata": { - "name": "queryOverLive", - "resourceVersion": "1641384000000", - "creationTimestamp": "2022-01-05T12:00:00Z" - }, - "spec": { - "description": "Use Grafana Live WebSocket to execute backend queries", - "stage": "experimental", - "codeowner": "@grafana/grafana-app-platform-squad", - "frontend": true - } - }, - { - "metadata": { - "name": "panelTitleSearch", - "resourceVersion": "1644926400000", - "creationTimestamp": "2022-02-15T12:00:00Z" - }, - "spec": { - "description": "Search for dashboards using panel title", - "stage": "preview", - "codeowner": "@grafana/grafana-app-platform-squad", - "hideFromAdminPage": true - } - }, - { - "metadata": { - "name": "publicDashboards", - "resourceVersion": "1649332800000", - "creationTimestamp": "2022-04-07T12:00:00Z" - }, - "spec": { - "description": "[Deprecated] Public dashboards are now enabled by default; to disable them, use the configuration setting. This feature toggle will be removed in the next major version.", - "stage": "GA", - "codeowner": "@grafana/sharing-squad", - "allowSelfServe": true - } - }, - { - "metadata": { - "name": "publicDashboardsEmailSharing", - "resourceVersion": "1671624000000", - "creationTimestamp": "2022-12-21T12:00:00Z" - }, - "spec": { - "description": "Enables public dashboard sharing to be restricted to only allowed emails", - "stage": "preview", - "codeowner": "@grafana/sharing-squad", - "hideFromAdminPage": true, - "hideFromDocs": true - } - }, { "metadata": { "name": "lokiExperimentalStreaming", - "resourceVersion": "1687176000000", - "creationTimestamp": "2023-06-19T12:00:00Z" + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" }, "spec": { "description": "Support new streaming approach for loki (prototype, needs special loki build)", @@ -96,693 +17,83 @@ }, { "metadata": { - "name": "featureHighlights", - "resourceVersion": "1643889600000", - "creationTimestamp": "2022-02-03T12:00:00Z" + "name": "enablePluginsTracingByDefault", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" }, "spec": { - "description": "Highlight Grafana Enterprise features", - "stage": "GA", - "codeowner": "@grafana/grafana-as-code", - "allowSelfServe": true - } - }, - { - "metadata": { - "name": "migrationLocking", - "resourceVersion": "1644926400000", - "creationTimestamp": "2022-02-15T12:00:00Z" - }, - "spec": { - "description": "Lock database during migrations", - "stage": "preview", - "codeowner": "@grafana/backend-platform" - } - }, - { - "metadata": { - "name": "storage", - "resourceVersion": "1647518400000", - "creationTimestamp": "2022-03-17T12:00:00Z" - }, - "spec": { - "description": "Configurable storage for dashboards, datasources, and resources", + "description": "Enable plugin tracing for all external plugins", "stage": "experimental", - "codeowner": "@grafana/grafana-app-platform-squad" - } - }, - { - "metadata": { - "name": "correlations", - "resourceVersion": "1663329600000", - "creationTimestamp": "2022-09-16T12:00:00Z" - }, - "spec": { - "description": "Correlations page", - "stage": "GA", - "codeowner": "@grafana/explore-squad", - "allowSelfServe": true - } - }, - { - "metadata": { - "name": "exploreContentOutline", - "resourceVersion": "1699012800000", - "creationTimestamp": "2023-11-03T12:00:00Z" - }, - "spec": { - "description": "Content outline sidebar", - "stage": "GA", - "codeowner": "@grafana/explore-squad", - "frontend": true, - "allowSelfServe": true - } - }, - { - "metadata": { - "name": "datasourceQueryMultiStatus", - "resourceVersion": "1651579200000", - "creationTimestamp": "2022-05-03T12:00:00Z" - }, - "spec": { - "description": "Introduce HTTP 207 Multi Status for api/ds/query", - "stage": "experimental", - "codeowner": "@grafana/plugins-platform-backend" - } - }, - { - "metadata": { - "name": "traceToMetrics", - "resourceVersion": "1646654400000", - "creationTimestamp": "2022-03-07T12:00:00Z" - }, - "spec": { - "description": "Enable trace to metrics links", - "stage": "experimental", - "codeowner": "@grafana/observability-traces-and-profiling", - "frontend": true - } - }, - { - "metadata": { - "name": "autoMigrateOldPanels", - "resourceVersion": "1654948800000", - "creationTimestamp": "2022-06-11T12:00:00Z" - }, - "spec": { - "description": "Migrate old angular panels to supported versions (graph, table-old, worldmap, etc)", - "stage": "preview", - "codeowner": "@grafana/dataviz-squad", - "frontend": true - } - }, - { - "metadata": { - "name": "disableAngular", - "resourceVersion": "1679572800000", - "creationTimestamp": "2023-03-23T12:00:00Z" - }, - "spec": { - "description": "Dynamic flag to disable angular at runtime. The preferred method is to set `angular_support_enabled` to `false` in the [security] settings, which allows you to change the state at runtime.", - "stage": "preview", - "codeowner": "@grafana/dataviz-squad", - "frontend": true, - "hideFromAdminPage": true - } - }, - { - "metadata": { - "name": "canvasPanelNesting", - "resourceVersion": "1653998400000", - "creationTimestamp": "2022-05-31T12:00:00Z" - }, - "spec": { - "description": "Allow elements nesting", - "stage": "experimental", - "codeowner": "@grafana/dataviz-squad", - "frontend": true, - "hideFromAdminPage": true - } - }, - { - "metadata": { - "name": "newVizTooltips", - "resourceVersion": "1699012800000", - "creationTimestamp": "2023-11-03T12:00:00Z" - }, - "spec": { - "description": "New visualizations tooltips UX", - "stage": "preview", - "codeowner": "@grafana/dataviz-squad", - "frontend": true - } - }, - { - "metadata": { - "name": "scenes", - "resourceVersion": "1657195200000", - "creationTimestamp": "2022-07-07T12:00:00Z" - }, - "spec": { - "description": "Experimental framework to build interactive dashboards", - "stage": "experimental", - "codeowner": "@grafana/dashboards-squad", - "frontend": true - } - }, - { - "metadata": { - "name": "disableSecretsCompatibility", - "resourceVersion": "1657713600000", - "creationTimestamp": "2022-07-13T12:00:00Z" - }, - "spec": { - "description": "Disable duplicated secret storage in legacy tables", - "stage": "experimental", - "codeowner": "@grafana/hosted-grafana-team", - "requiresRestart": true - } - }, - { - "metadata": { - "name": "logRequestsInstrumentedAsUnknown", - "resourceVersion": "1654862400000", - "creationTimestamp": "2022-06-10T12:00:00Z" - }, - "spec": { - "description": "Logs the path for requests that are instrumented as unknown", - "stage": "experimental", - "codeowner": "@grafana/hosted-grafana-team" - } - }, - { - "metadata": { - "name": "dataConnectionsConsole", - "resourceVersion": "1654084800000", - "creationTimestamp": "2022-06-01T12:00:00Z" - }, - "spec": { - "description": "Enables a new top-level page called Connections. This page is an experiment that provides a better experience when you install and configure data sources and other plugins.", - "stage": "GA", "codeowner": "@grafana/plugins-platform-backend", - "allowSelfServe": true - } - }, - { - "metadata": { - "name": "topnav", - "resourceVersion": "1655726400000", - "creationTimestamp": "2022-06-20T12:00:00Z" - }, - "spec": { - "description": "Enables topnav support in external plugins. The new Grafana navigation cannot be disabled.", - "stage": "deprecated", - "codeowner": "@grafana/grafana-frontend-platform" - } - }, - { - "metadata": { - "name": "returnToPrevious", - "resourceVersion": "1704798000000", - "creationTimestamp": "2024-01-09T11:00:00Z" - }, - "spec": { - "description": "Enables the return to previous context functionality", - "stage": "experimental", - "codeowner": "@grafana/grafana-frontend-platform", - "frontend": true - } - }, - { - "metadata": { - "name": "grpcServer", - "resourceVersion": "1664280000000", - "creationTimestamp": "2022-09-27T12:00:00Z" - }, - "spec": { - "description": "Run the GRPC server", - "stage": "preview", - "codeowner": "@grafana/grafana-app-platform-squad", - "hideFromAdminPage": true - } - }, - { - "metadata": { - "name": "unifiedStorage", - "resourceVersion": "1669896000000", - "creationTimestamp": "2022-12-01T12:00:00Z" - }, - "spec": { - "description": "SQL-based k8s storage", - "stage": "experimental", - "codeowner": "@grafana/grafana-app-platform-squad", - "requiresDevMode": true, "requiresRestart": true } }, { "metadata": { - "name": "cloudWatchCrossAccountQuerying", - "resourceVersion": "1669636800000", - "creationTimestamp": "2022-11-28T12:00:00Z" + "name": "sseGroupByDatasource", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" }, "spec": { - "description": "Enables cross-account querying in CloudWatch datasources", - "stage": "GA", - "codeowner": "@grafana/aws-datasources", - "allowSelfServe": true + "description": "Send query to the same datasource in a single request when using server side expressions. The `cloudWatchBatchQueries` feature toggle should be enabled if this used with CloudWatch.", + "stage": "experimental", + "codeowner": "@grafana/observability-metrics" } }, { "metadata": { - "name": "redshiftAsyncQueryDataSupport", - "resourceVersion": "1661601600000", - "creationTimestamp": "2022-08-27T12:00:00Z" + "name": "cloudWatchBatchQueries", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" }, "spec": { - "description": "Enable async query data support for Redshift", - "stage": "GA", + "description": "Runs CloudWatch metrics queries as separate batches", + "stage": "preview", "codeowner": "@grafana/aws-datasources" } }, { "metadata": { - "name": "athenaAsyncQueryDataSupport", - "resourceVersion": "1661601600000", - "creationTimestamp": "2022-08-27T12:00:00Z" + "name": "managedPluginsInstall", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" }, "spec": { - "description": "Enable async query data support for Athena", - "stage": "GA", - "codeowner": "@grafana/aws-datasources", - "frontend": true - } - }, - { - "metadata": { - "name": "showDashboardValidationWarnings", - "resourceVersion": "1665748800000", - "creationTimestamp": "2022-10-14T12:00:00Z" - }, - "spec": { - "description": "Show warnings when dashboards do not validate against the schema", - "stage": "experimental", - "codeowner": "@grafana/dashboards-squad" - } - }, - { - "metadata": { - "name": "mysqlAnsiQuotes", - "resourceVersion": "1665576000000", - "creationTimestamp": "2022-10-12T12:00:00Z" - }, - "spec": { - "description": "Use double quotes to escape keyword in a MySQL query", - "stage": "experimental", - "codeowner": "@grafana/backend-platform" - } - }, - { - "metadata": { - "name": "accessControlOnCall", - "resourceVersion": "1666180800000", - "creationTimestamp": "2022-10-19T12:00:00Z" - }, - "spec": { - "description": "Access control primitives for OnCall", + "description": "Install managed plugins directly from plugins catalog", "stage": "preview", - "codeowner": "@grafana/identity-access-team", - "hideFromAdminPage": true + "codeowner": "@grafana/plugins-platform-backend" } }, { "metadata": { - "name": "nestedFolders", - "resourceVersion": "1666440000000", - "creationTimestamp": "2022-10-22T12:00:00Z" + "name": "pdfTables", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" }, "spec": { - "description": "Enable folder nesting", + "description": "Enables generating table data as PDF in reporting", "stage": "preview", - "codeowner": "@grafana/backend-platform" + "codeowner": "@grafana/sharing-squad" } }, { "metadata": { - "name": "nestedFolderPicker", - "resourceVersion": "1690200000000", - "creationTimestamp": "2023-07-24T12:00:00Z" + "name": "logsInfiniteScrolling", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" }, "spec": { - "description": "Enables the new folder picker to work with nested folders. Requires the nestedFolders feature toggle", - "stage": "GA", - "codeowner": "@grafana/grafana-frontend-platform", - "frontend": true, - "allowSelfServe": true - } - }, - { - "metadata": { - "name": "alertingBacktesting", - "resourceVersion": "1666267200000", - "creationTimestamp": "2022-10-20T12:00:00Z" - }, - "spec": { - "description": "Rule backtesting API for alerting", - "stage": "experimental", - "codeowner": "@grafana/alerting-squad" - } - }, - { - "metadata": { - "name": "editPanelCSVDragAndDrop", - "resourceVersion": "1707523537136", - "creationTimestamp": "2022-12-20T12:00:00Z", - "annotations": { - "grafana.app/updatedTimestamp": "2024-02-10 00:05:37.1362 +0000 UTC" - } - }, - "spec": { - "description": "Enables drag and drop for CSV and Excel files", - "stage": "experimental", - "codeowner": "@grafana/dataviz-squad", - "frontend": true - } - }, - { - "metadata": { - "name": "alertingNoNormalState", - "resourceVersion": "1673697600000", - "creationTimestamp": "2023-01-14T12:00:00Z" - }, - "spec": { - "description": "Stop maintaining state of alerts that are not firing", - "stage": "preview", - "codeowner": "@grafana/alerting-squad", - "hideFromAdminPage": true - } - }, - { - "metadata": { - "name": "logsContextDatasourceUi", - "resourceVersion": "1674820800000", - "creationTimestamp": "2023-01-27T12:00:00Z" - }, - "spec": { - "description": "Allow datasource to provide custom UI for context view", - "stage": "GA", - "codeowner": "@grafana/observability-logs", - "frontend": true, - "allowSelfServe": true - } - }, - { - "metadata": { - "name": "lokiQuerySplitting", - "resourceVersion": "1675944000000", - "creationTimestamp": "2023-02-09T12:00:00Z" - }, - "spec": { - "description": "Split large interval queries into subqueries with smaller time intervals", - "stage": "GA", - "codeowner": "@grafana/observability-logs", - "frontend": true, - "allowSelfServe": true - } - }, - { - "metadata": { - "name": "lokiQuerySplittingConfig", - "resourceVersion": "1679313600000", - "creationTimestamp": "2023-03-20T12:00:00Z" - }, - "spec": { - "description": "Give users the option to configure split durations for Loki queries", + "description": "Enables infinite scrolling for the Logs panel in Explore and Dashboards", "stage": "experimental", "codeowner": "@grafana/observability-logs", "frontend": true } }, - { - "metadata": { - "name": "individualCookiePreferences", - "resourceVersion": "1677153600000", - "creationTimestamp": "2023-02-23T12:00:00Z" - }, - "spec": { - "description": "Support overriding cookie preferences per user", - "stage": "experimental", - "codeowner": "@grafana/backend-platform" - } - }, - { - "metadata": { - "name": "prometheusMetricEncyclopedia", - "resourceVersion": "1678190400000", - "creationTimestamp": "2023-03-07T12:00:00Z" - }, - "spec": { - "description": "Adds the metrics explorer component to the Prometheus query builder as an option in metric select", - "stage": "GA", - "codeowner": "@grafana/observability-metrics", - "frontend": true, - "allowSelfServe": true - } - }, - { - "metadata": { - "name": "influxdbBackendMigration", - "resourceVersion": "1678881600000", - "creationTimestamp": "2023-03-15T12:00:00Z" - }, - "spec": { - "description": "Query InfluxDB InfluxQL without the proxy", - "stage": "GA", - "codeowner": "@grafana/observability-metrics", - "frontend": true - } - }, - { - "metadata": { - "name": "influxqlStreamingParser", - "resourceVersion": "1701259200000", - "creationTimestamp": "2023-11-29T12:00:00Z" - }, - "spec": { - "description": "Enable streaming JSON parser for InfluxDB datasource InfluxQL query language", - "stage": "experimental", - "codeowner": "@grafana/observability-metrics" - } - }, - { - "metadata": { - "name": "influxdbRunQueriesInParallel", - "resourceVersion": "1706529600000", - "creationTimestamp": "2024-01-29T12:00:00Z" - }, - "spec": { - "description": "Enables running InfluxDB Influxql queries in parallel", - "stage": "privatePreview", - "codeowner": "@grafana/observability-metrics" - } - }, - { - "metadata": { - "name": "clientTokenRotation", - "resourceVersion": "1679572800000", - "creationTimestamp": "2023-03-23T12:00:00Z" - }, - "spec": { - "description": "Replaces the current in-request token rotation so that the client initiates the rotation", - "stage": "GA", - "codeowner": "@grafana/identity-access-team" - } - }, - { - "metadata": { - "name": "prometheusDataplane", - "resourceVersion": "1680091200000", - "creationTimestamp": "2023-03-29T12:00:00Z" - }, - "spec": { - "description": "Changes responses to from Prometheus to be compliant with the dataplane specification. In particular, when this feature toggle is active, the numeric `Field.Name` is set from 'Value' to the value of the `__name__` label.", - "stage": "GA", - "codeowner": "@grafana/observability-metrics", - "allowSelfServe": true - } - }, - { - "metadata": { - "name": "lokiMetricDataplane", - "resourceVersion": "1681387200000", - "creationTimestamp": "2023-04-13T12:00:00Z" - }, - "spec": { - "description": "Changes metric responses from Loki to be compliant with the dataplane specification.", - "stage": "GA", - "codeowner": "@grafana/observability-logs", - "allowSelfServe": true - } - }, - { - "metadata": { - "name": "lokiLogsDataplane", - "resourceVersion": "1689249600000", - "creationTimestamp": "2023-07-13T12:00:00Z" - }, - "spec": { - "description": "Changes logs responses from Loki to be compliant with the dataplane specification.", - "stage": "experimental", - "codeowner": "@grafana/observability-logs" - } - }, - { - "metadata": { - "name": "dataplaneFrontendFallback", - "resourceVersion": "1682337600000", - "creationTimestamp": "2023-04-24T12:00:00Z" - }, - "spec": { - "description": "Support dataplane contract field name change for transformations and field name matchers where the name is different", - "stage": "GA", - "codeowner": "@grafana/observability-metrics", - "frontend": true, - "allowSelfServe": true - } - }, - { - "metadata": { - "name": "disableSSEDataplane", - "resourceVersion": "1682337600000", - "creationTimestamp": "2023-04-24T12:00:00Z" - }, - "spec": { - "description": "Disables dataplane specific processing in server side expressions.", - "stage": "experimental", - "codeowner": "@grafana/observability-metrics" - } - }, - { - "metadata": { - "name": "alertStateHistoryLokiSecondary", - "resourceVersion": "1680177600000", - "creationTimestamp": "2023-03-30T12:00:00Z" - }, - "spec": { - "description": "Enable Grafana to write alert state history to an external Loki instance in addition to Grafana annotations.", - "stage": "experimental", - "codeowner": "@grafana/alerting-squad" - } - }, - { - "metadata": { - "name": "alertStateHistoryLokiPrimary", - "resourceVersion": "1680177600000", - "creationTimestamp": "2023-03-30T12:00:00Z" - }, - "spec": { - "description": "Enable a remote Loki instance as the primary source for state history reads.", - "stage": "experimental", - "codeowner": "@grafana/alerting-squad" - } - }, - { - "metadata": { - "name": "alertStateHistoryLokiOnly", - "resourceVersion": "1680177600000", - "creationTimestamp": "2023-03-30T12:00:00Z" - }, - "spec": { - "description": "Disable Grafana alerts from emitting annotations when a remote Loki instance is available.", - "stage": "experimental", - "codeowner": "@grafana/alerting-squad" - } - }, - { - "metadata": { - "name": "unifiedRequestLog", - "resourceVersion": "1680264000000", - "creationTimestamp": "2023-03-31T12:00:00Z" - }, - "spec": { - "description": "Writes error logs to the request logger", - "stage": "experimental", - "codeowner": "@grafana/backend-platform" - } - }, - { - "metadata": { - "name": "renderAuthJWT", - "resourceVersion": "1680523200000", - "creationTimestamp": "2023-04-03T12:00:00Z" - }, - "spec": { - "description": "Uses JWT-based auth for rendering instead of relying on remote cache", - "stage": "preview", - "codeowner": "@grafana/grafana-as-code", - "hideFromAdminPage": true - } - }, - { - "metadata": { - "name": "externalServiceAuth", - "resourceVersion": "1681214400000", - "creationTimestamp": "2023-04-11T12:00:00Z" - }, - "spec": { - "description": "Starts an OAuth2 authentication provider for external services", - "stage": "experimental", - "codeowner": "@grafana/identity-access-team", - "requiresDevMode": true - } - }, - { - "metadata": { - "name": "refactorVariablesTimeRange", - "resourceVersion": "1686052800000", - "creationTimestamp": "2023-06-06T12:00:00Z" - }, - "spec": { - "description": "Refactor time range variables flow to reduce number of API calls made when query variables are chained", - "stage": "preview", - "codeowner": "@grafana/dashboards-squad", - "hideFromAdminPage": true - } - }, - { - "metadata": { - "name": "enableElasticsearchBackendQuerying", - "resourceVersion": "1681473600000", - "creationTimestamp": "2023-04-14T12:00:00Z" - }, - "spec": { - "description": "Enable the processing of queries and responses in the Elasticsearch data source through backend", - "stage": "GA", - "codeowner": "@grafana/observability-logs", - "allowSelfServe": true - } - }, - { - "metadata": { - "name": "faroDatasourceSelector", - "resourceVersion": "1683201600000", - "creationTimestamp": "2023-05-04T12:00:00Z" - }, - "spec": { - "description": "Enable the data source selector within the Frontend Apps section of the Frontend Observability", - "stage": "preview", - "codeowner": "@grafana/app-o11y", - "frontend": true - } - }, { "metadata": { "name": "enableDatagridEditing", - "resourceVersion": "1707523537136", - "creationTimestamp": "2023-04-24T12:00:00Z", - "annotations": { - "grafana.app/updatedTimestamp": "2024-02-10 00:05:37.1362 +0000 UTC" - } + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" }, "spec": { "description": "Enables the edit functionality in the datagrid panel", @@ -791,316 +102,11 @@ "frontend": true } }, - { - "metadata": { - "name": "extraThemes", - "resourceVersion": "1683720000000", - "creationTimestamp": "2023-05-10T12:00:00Z" - }, - "spec": { - "description": "Enables extra themes", - "stage": "experimental", - "codeowner": "@grafana/grafana-frontend-platform", - "frontend": true - } - }, - { - "metadata": { - "name": "lokiPredefinedOperations", - "resourceVersion": "1685707200000", - "creationTimestamp": "2023-06-02T12:00:00Z" - }, - "spec": { - "description": "Adds predefined query operations to Loki query editor", - "stage": "experimental", - "codeowner": "@grafana/observability-logs", - "frontend": true - } - }, - { - "metadata": { - "name": "pluginsFrontendSandbox", - "resourceVersion": "1685966400000", - "creationTimestamp": "2023-06-05T12:00:00Z" - }, - "spec": { - "description": "Enables the plugins frontend sandbox", - "stage": "experimental", - "codeowner": "@grafana/plugins-platform-backend", - "frontend": true - } - }, - { - "metadata": { - "name": "dashboardEmbed", - "resourceVersion": "1688644800000", - "creationTimestamp": "2023-07-06T12:00:00Z" - }, - "spec": { - "description": "Allow embedding dashboard for external use in Code editors", - "stage": "experimental", - "codeowner": "@grafana/grafana-as-code", - "frontend": true - } - }, - { - "metadata": { - "name": "frontendSandboxMonitorOnly", - "resourceVersion": "1688558400000", - "creationTimestamp": "2023-07-05T12:00:00Z" - }, - "spec": { - "description": "Enables monitor only in the plugin frontend sandbox (if enabled)", - "stage": "experimental", - "codeowner": "@grafana/plugins-platform-backend", - "frontend": true - } - }, - { - "metadata": { - "name": "sqlDatasourceDatabaseSelection", - "resourceVersion": "1707523537136", - "creationTimestamp": "2023-06-06T12:00:00Z", - "annotations": { - "grafana.app/updatedTimestamp": "2024-02-10 00:05:37.1362 +0000 UTC" - } - }, - "spec": { - "description": "Enables previous SQL data source dataset dropdown behavior", - "stage": "preview", - "codeowner": "@grafana/dataviz-squad", - "frontend": true, - "hideFromAdminPage": true - } - }, - { - "metadata": { - "name": "lokiFormatQuery", - "resourceVersion": "1687348800000", - "creationTimestamp": "2023-06-21T12:00:00Z" - }, - "spec": { - "description": "Enables the ability to format Loki queries", - "stage": "experimental", - "codeowner": "@grafana/observability-logs", - "frontend": true - } - }, - { - "metadata": { - "name": "cloudWatchLogsMonacoEditor", - "resourceVersion": "1686571200000", - "creationTimestamp": "2023-06-12T12:00:00Z" - }, - "spec": { - "description": "Enables the Monaco editor for CloudWatch Logs queries", - "stage": "GA", - "codeowner": "@grafana/aws-datasources", - "frontend": true, - "allowSelfServe": true - } - }, - { - "metadata": { - "name": "exploreScrollableLogsContainer", - "resourceVersion": "1686830400000", - "creationTimestamp": "2023-06-15T12:00:00Z" - }, - "spec": { - "description": "Improves the scrolling behavior of logs in Explore", - "stage": "experimental", - "codeowner": "@grafana/observability-logs", - "frontend": true - } - }, - { - "metadata": { - "name": "recordedQueriesMulti", - "resourceVersion": "1686744000000", - "creationTimestamp": "2023-06-14T12:00:00Z" - }, - "spec": { - "description": "Enables writing multiple items from a single query within Recorded Queries", - "stage": "GA", - "codeowner": "@grafana/observability-metrics" - } - }, - { - "metadata": { - "name": "pluginsDynamicAngularDetectionPatterns", - "resourceVersion": "1687780800000", - "creationTimestamp": "2023-06-26T12:00:00Z" - }, - "spec": { - "description": "Enables fetching Angular detection patterns for plugins from GCOM and fallback to hardcoded ones", - "stage": "experimental", - "codeowner": "@grafana/plugins-platform-backend" - } - }, - { - "metadata": { - "name": "vizAndWidgetSplit", - "resourceVersion": "1687867200000", - "creationTimestamp": "2023-06-27T12:00:00Z" - }, - "spec": { - "description": "Split panels between visualizations and widgets", - "stage": "experimental", - "codeowner": "@grafana/dashboards-squad", - "frontend": true - } - }, - { - "metadata": { - "name": "prometheusIncrementalQueryInstrumentation", - "resourceVersion": "1688558400000", - "creationTimestamp": "2023-07-05T12:00:00Z" - }, - "spec": { - "description": "Adds RudderStack events to incremental queries", - "stage": "experimental", - "codeowner": "@grafana/observability-metrics", - "frontend": true - } - }, - { - "metadata": { - "name": "logsExploreTableVisualisation", - "resourceVersion": "1707747885704", - "creationTimestamp": "2023-07-12T12:00:00Z", - "annotations": { - "grafana.app/updatedTimestamp": "2024-02-12 14:24:45.704022 +0000 UTC" - } - }, - "spec": { - "description": "A table visualisation for logs in Explore", - "stage": "GA", - "codeowner": "@grafana/observability-logs", - "frontend": true - } - }, - { - "metadata": { - "name": "awsDatasourcesTempCredentials", - "resourceVersion": "1688644800000", - "creationTimestamp": "2023-07-06T12:00:00Z" - }, - "spec": { - "description": "Support temporary security credentials in AWS plugins for Grafana Cloud customers", - "stage": "experimental", - "codeowner": "@grafana/aws-datasources" - } - }, - { - "metadata": { - "name": "transformationsRedesign", - "resourceVersion": "1689163200000", - "creationTimestamp": "2023-07-12T12:00:00Z" - }, - "spec": { - "description": "Enables the transformations redesign", - "stage": "GA", - "codeowner": "@grafana/observability-metrics", - "frontend": true, - "allowSelfServe": true - } - }, - { - "metadata": { - "name": "mlExpressions", - "resourceVersion": "1689249600000", - "creationTimestamp": "2023-07-13T12:00:00Z" - }, - "spec": { - "description": "Enable support for Machine Learning in server-side expressions", - "stage": "experimental", - "codeowner": "@grafana/alerting-squad" - } - }, - { - "metadata": { - "name": "traceQLStreaming", - "resourceVersion": "1690372800000", - "creationTimestamp": "2023-07-26T12:00:00Z" - }, - "spec": { - "description": "Enables response streaming of TraceQL queries of the Tempo data source", - "stage": "experimental", - "codeowner": "@grafana/observability-traces-and-profiling", - "frontend": true - } - }, - { - "metadata": { - "name": "metricsSummary", - "resourceVersion": "1693224000000", - "creationTimestamp": "2023-08-28T12:00:00Z" - }, - "spec": { - "description": "Enables metrics summary queries in the Tempo data source", - "stage": "experimental", - "codeowner": "@grafana/observability-traces-and-profiling", - "frontend": true - } - }, - { - "metadata": { - "name": "grafanaAPIServerWithExperimentalAPIs", - "resourceVersion": "1696593600000", - "creationTimestamp": "2023-10-06T12:00:00Z" - }, - "spec": { - "description": "Register experimental APIs with the k8s API server", - "stage": "experimental", - "codeowner": "@grafana/grafana-app-platform-squad", - "requiresDevMode": true, - "requiresRestart": true - } - }, - { - "metadata": { - "name": "grafanaAPIServerEnsureKubectlAccess", - "resourceVersion": "1701864000000", - "creationTimestamp": "2023-12-06T12:00:00Z" - }, - "spec": { - "description": "Start an additional https handler and write kubectl options", - "stage": "experimental", - "codeowner": "@grafana/grafana-app-platform-squad", - "requiresDevMode": true, - "requiresRestart": true - } - }, - { - "metadata": { - "name": "featureToggleAdminPage", - "resourceVersion": "1689681600000", - "creationTimestamp": "2023-07-18T12:00:00Z" - }, - "spec": { - "description": "Enable admin page for managing feature toggles from the Grafana front-end", - "stage": "experimental", - "codeowner": "@grafana/grafana-operator-experience-squad", - "requiresRestart": true - } - }, - { - "metadata": { - "name": "awsAsyncQueryCaching", - "resourceVersion": "1689940800000", - "creationTimestamp": "2023-07-21T12:00:00Z" - }, - "spec": { - "description": "Enable caching for async queries for Redshift and Athena. Requires that the datasource has caching and async query support enabled", - "stage": "GA", - "codeowner": "@grafana/aws-datasources" - } - }, { "metadata": { "name": "splitScopes", - "resourceVersion": "1689940800000", - "creationTimestamp": "2023-07-21T12:00:00Z" + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" }, "spec": { "description": "Support faster dashboard and folder search by splitting permission scopes into parts", @@ -1113,8 +119,8 @@ { "metadata": { "name": "permissionsFilterRemoveSubquery", - "resourceVersion": "1690977600000", - "creationTimestamp": "2023-08-02T12:00:00Z" + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" }, "spec": { "description": "Alternative permission filter implementation that does not use subqueries for fetching the dashboard folder", @@ -1122,559 +128,11 @@ "codeowner": "@grafana/backend-platform" } }, - { - "metadata": { - "name": "prometheusConfigOverhaulAuth", - "resourceVersion": "1689940800000", - "creationTimestamp": "2023-07-21T12:00:00Z" - }, - "spec": { - "description": "Update the Prometheus configuration page with the new auth component", - "stage": "GA", - "codeowner": "@grafana/observability-metrics" - } - }, - { - "metadata": { - "name": "configurableSchedulerTick", - "resourceVersion": "1690372800000", - "creationTimestamp": "2023-07-26T12:00:00Z" - }, - "spec": { - "description": "Enable changing the scheduler base interval via configuration option unified_alerting.scheduler_tick_interval", - "stage": "experimental", - "codeowner": "@grafana/alerting-squad", - "requiresRestart": true, - "hideFromDocs": true - } - }, - { - "metadata": { - "name": "influxdbSqlSupport", - "resourceVersion": "1690977600000", - "creationTimestamp": "2023-08-02T12:00:00Z" - }, - "spec": { - "description": "Enable InfluxDB SQL query language support with new querying UI", - "stage": "GA", - "codeowner": "@grafana/observability-metrics", - "requiresRestart": true, - "allowSelfServe": true - } - }, - { - "metadata": { - "name": "alertingNoDataErrorExecution", - "resourceVersion": "1692100800000", - "creationTimestamp": "2023-08-15T12:00:00Z" - }, - "spec": { - "description": "Changes how Alerting state manager handles execution of NoData/Error", - "stage": "GA", - "codeowner": "@grafana/alerting-squad", - "requiresRestart": true - } - }, - { - "metadata": { - "name": "angularDeprecationUI", - "resourceVersion": "1693310400000", - "creationTimestamp": "2023-08-29T12:00:00Z" - }, - "spec": { - "description": "Display new Angular deprecation-related UI features", - "stage": "experimental", - "codeowner": "@grafana/plugins-platform-backend", - "frontend": true - } - }, - { - "metadata": { - "name": "dashgpt", - "resourceVersion": "1700222400000", - "creationTimestamp": "2023-11-17T12:00:00Z" - }, - "spec": { - "description": "Enable AI powered features in dashboards", - "stage": "preview", - "codeowner": "@grafana/dashboards-squad", - "frontend": true - } - }, - { - "metadata": { - "name": "reportingRetries", - "resourceVersion": "1693483200000", - "creationTimestamp": "2023-08-31T12:00:00Z" - }, - "spec": { - "description": "Enables rendering retries for the reporting feature", - "stage": "preview", - "codeowner": "@grafana/sharing-squad", - "requiresRestart": true - } - }, - { - "metadata": { - "name": "sseGroupByDatasource", - "resourceVersion": "1694088000000", - "creationTimestamp": "2023-09-07T12:00:00Z" - }, - "spec": { - "description": "Send query to the same datasource in a single request when using server side expressions. The `cloudWatchBatchQueries` feature toggle should be enabled if this used with CloudWatch.", - "stage": "experimental", - "codeowner": "@grafana/observability-metrics" - } - }, - { - "metadata": { - "name": "libraryPanelRBAC", - "resourceVersion": "1697025600000", - "creationTimestamp": "2023-10-11T12:00:00Z" - }, - "spec": { - "description": "Enables RBAC support for library panels", - "stage": "experimental", - "codeowner": "@grafana/dashboards-squad", - "requiresRestart": true - } - }, - { - "metadata": { - "name": "lokiRunQueriesInParallel", - "resourceVersion": "1695124800000", - "creationTimestamp": "2023-09-19T12:00:00Z" - }, - "spec": { - "description": "Enables running Loki queries in parallel", - "stage": "privatePreview", - "codeowner": "@grafana/observability-logs" - } - }, - { - "metadata": { - "name": "wargamesTesting", - "resourceVersion": "1694606400000", - "creationTimestamp": "2023-09-13T12:00:00Z" - }, - "spec": { - "description": "Placeholder feature flag for internal testing", - "stage": "experimental", - "codeowner": "@grafana/hosted-grafana-team" - } - }, - { - "metadata": { - "name": "alertingInsights", - "resourceVersion": "1694692800000", - "creationTimestamp": "2023-09-14T12:00:00Z" - }, - "spec": { - "description": "Show the new alerting insights landing page", - "stage": "GA", - "codeowner": "@grafana/alerting-squad", - "frontend": true, - "hideFromAdminPage": true - } - }, - { - "metadata": { - "name": "externalCorePlugins", - "resourceVersion": "1695384000000", - "creationTimestamp": "2023-09-22T12:00:00Z" - }, - "spec": { - "description": "Allow core plugins to be loaded as external", - "stage": "experimental", - "codeowner": "@grafana/plugins-platform-backend" - } - }, - { - "metadata": { - "name": "pluginsAPIMetrics", - "resourceVersion": "1695297600000", - "creationTimestamp": "2023-09-21T12:00:00Z" - }, - "spec": { - "description": "Sends metrics of public grafana packages usage by plugins", - "stage": "experimental", - "codeowner": "@grafana/plugins-platform-backend", - "frontend": true - } - }, - { - "metadata": { - "name": "idForwarding", - "resourceVersion": "1695643200000", - "creationTimestamp": "2023-09-25T12:00:00Z" - }, - "spec": { - "description": "Generate signed id token for identity that can be forwarded to plugins and external services", - "stage": "experimental", - "codeowner": "@grafana/identity-access-team" - } - }, - { - "metadata": { - "name": "cloudWatchWildCardDimensionValues", - "resourceVersion": "1695816000000", - "creationTimestamp": "2023-09-27T12:00:00Z" - }, - "spec": { - "description": "Fetches dimension values from CloudWatch to correctly label wildcard dimensions", - "stage": "GA", - "codeowner": "@grafana/aws-datasources", - "allowSelfServe": true - } - }, - { - "metadata": { - "name": "externalServiceAccounts", - "resourceVersion": "1695902400000", - "creationTimestamp": "2023-09-28T12:00:00Z" - }, - "spec": { - "description": "Automatic service account and token setup for plugins", - "stage": "preview", - "codeowner": "@grafana/identity-access-team", - "hideFromAdminPage": true - } - }, - { - "metadata": { - "name": "panelMonitoring", - "resourceVersion": "1696766400000", - "creationTimestamp": "2023-10-08T12:00:00Z" - }, - "spec": { - "description": "Enables panel monitoring through logs and measurements", - "stage": "experimental", - "codeowner": "@grafana/dataviz-squad", - "frontend": true - } - }, - { - "metadata": { - "name": "enableNativeHTTPHistogram", - "resourceVersion": "1696334400000", - "creationTimestamp": "2023-10-03T12:00:00Z" - }, - "spec": { - "description": "Enables native HTTP Histograms", - "stage": "experimental", - "codeowner": "@grafana/hosted-grafana-team" - } - }, - { - "metadata": { - "name": "formatString", - "resourceVersion": "1707523537136", - "creationTimestamp": "2023-10-13T12:00:00Z", - "annotations": { - "grafana.app/updatedTimestamp": "2024-02-10 00:05:37.1362 +0000 UTC" - } - }, - "spec": { - "description": "Enable format string transformer", - "stage": "preview", - "codeowner": "@grafana/dataviz-squad", - "frontend": true - } - }, - { - "metadata": { - "name": "transformationsVariableSupport", - "resourceVersion": "1707523537136", - "creationTimestamp": "2023-10-04T12:00:00Z", - "annotations": { - "grafana.app/updatedTimestamp": "2024-02-10 00:05:37.1362 +0000 UTC" - } - }, - "spec": { - "description": "Allows using variables in transformations", - "stage": "preview", - "codeowner": "@grafana/dataviz-squad", - "frontend": true - } - }, - { - "metadata": { - "name": "kubernetesPlaylists", - "resourceVersion": "1699444800000", - "creationTimestamp": "2023-11-08T12:00:00Z" - }, - "spec": { - "description": "Use the kubernetes API in the frontend for playlists, and route /api/playlist requests to k8s", - "stage": "experimental", - "codeowner": "@grafana/grafana-app-platform-squad", - "requiresRestart": true - } - }, - { - "metadata": { - "name": "kubernetesSnapshots", - "resourceVersion": "1707374669879", - "creationTimestamp": "2023-12-04T12:00:00Z", - "annotations": { - "grafana.app/updatedTimestamp": "2024-02-08 06:44:29.879787 +0000 UTC" - } - }, - "spec": { - "description": "Routes snapshot requests from /api to the /apis endpoint", - "stage": "experimental", - "codeowner": "@grafana/grafana-app-platform-squad", - "requiresRestart": true - } - }, - { - "metadata": { - "name": "kubernetesQueryServiceRewrite", - "resourceVersion": "1706443200000", - "creationTimestamp": "2024-01-28T12:00:00Z" - }, - "spec": { - "description": "Rewrite requests targeting /ds/query to the query service", - "stage": "experimental", - "codeowner": "@grafana/grafana-app-platform-squad", - "requiresDevMode": true, - "requiresRestart": true - } - }, - { - "metadata": { - "name": "cloudWatchBatchQueries", - "resourceVersion": "1697803200000", - "creationTimestamp": "2023-10-20T12:00:00Z" - }, - "spec": { - "description": "Runs CloudWatch metrics queries as separate batches", - "stage": "preview", - "codeowner": "@grafana/aws-datasources" - } - }, - { - "metadata": { - "name": "recoveryThreshold", - "resourceVersion": "1696939200000", - "creationTimestamp": "2023-10-10T12:00:00Z" - }, - "spec": { - "description": "Enables feature recovery threshold (aka hysteresis) for threshold server-side expression", - "stage": "GA", - "codeowner": "@grafana/alerting-squad", - "requiresRestart": true - } - }, - { - "metadata": { - "name": "lokiStructuredMetadata", - "resourceVersion": "1700136000000", - "creationTimestamp": "2023-11-16T12:00:00Z" - }, - "spec": { - "description": "Enables the loki data source to request structured metadata from the Loki server", - "stage": "experimental", - "codeowner": "@grafana/observability-logs" - } - }, - { - "metadata": { - "name": "teamHttpHeaders", - "resourceVersion": "1697544000000", - "creationTimestamp": "2023-10-17T12:00:00Z" - }, - "spec": { - "description": "Enables datasources to apply team headers to the client requests", - "stage": "experimental", - "codeowner": "@grafana/identity-access-team" - } - }, - { - "metadata": { - "name": "awsDatasourcesNewFormStyling", - "resourceVersion": "1697112000000", - "creationTimestamp": "2023-10-12T12:00:00Z" - }, - "spec": { - "description": "Applies new form styling for configuration and query editors in AWS plugins", - "stage": "preview", - "codeowner": "@grafana/aws-datasources", - "frontend": true - } - }, - { - "metadata": { - "name": "cachingOptimizeSerializationMemoryUsage", - "resourceVersion": "1697112000000", - "creationTimestamp": "2023-10-12T12:00:00Z" - }, - "spec": { - "description": "If enabled, the caching backend gradually serializes query responses for the cache, comparing against the configured `[caching]max_value_mb` value as it goes. This can can help prevent Grafana from running out of memory while attempting to cache very large query responses.", - "stage": "experimental", - "codeowner": "@grafana/grafana-operator-experience-squad" - } - }, - { - "metadata": { - "name": "panelTitleSearchInV1", - "resourceVersion": "1697198400000", - "creationTimestamp": "2023-10-13T12:00:00Z" - }, - "spec": { - "description": "Enable searching for dashboards using panel title in search v1", - "stage": "experimental", - "codeowner": "@grafana/backend-platform", - "requiresDevMode": true - } - }, - { - "metadata": { - "name": "pluginsInstrumentationStatusSource", - "resourceVersion": "1697544000000", - "creationTimestamp": "2023-10-17T12:00:00Z" - }, - "spec": { - "description": "Include a status source label for plugin request metrics and logs", - "stage": "experimental", - "codeowner": "@grafana/plugins-platform-backend" - } - }, - { - "metadata": { - "name": "managedPluginsInstall", - "resourceVersion": "1697630400000", - "creationTimestamp": "2023-10-18T12:00:00Z" - }, - "spec": { - "description": "Install managed plugins directly from plugins catalog", - "stage": "preview", - "codeowner": "@grafana/plugins-platform-backend" - } - }, - { - "metadata": { - "name": "prometheusPromQAIL", - "resourceVersion": "1697716800000", - "creationTimestamp": "2023-10-19T12:00:00Z" - }, - "spec": { - "description": "Prometheus and AI/ML to assist users in creating a query", - "stage": "experimental", - "codeowner": "@grafana/observability-metrics", - "frontend": true - } - }, - { - "metadata": { - "name": "addFieldFromCalculationStatFunctions", - "resourceVersion": "1707523537136", - "creationTimestamp": "2023-11-03T12:00:00Z", - "annotations": { - "grafana.app/updatedTimestamp": "2024-02-10 00:05:37.1362 +0000 UTC" - } - }, - "spec": { - "description": "Add cumulative and window functions to the add field from calculation transformation", - "stage": "preview", - "codeowner": "@grafana/dataviz-squad", - "frontend": true - } - }, - { - "metadata": { - "name": "alertmanagerRemoteSecondary", - "resourceVersion": "1698667200000", - "creationTimestamp": "2023-10-30T12:00:00Z" - }, - "spec": { - "description": "Enable Grafana to sync configuration and state with a remote Alertmanager.", - "stage": "experimental", - "codeowner": "@grafana/alerting-squad" - } - }, - { - "metadata": { - "name": "alertmanagerRemotePrimary", - "resourceVersion": "1698667200000", - "creationTimestamp": "2023-10-30T12:00:00Z" - }, - "spec": { - "description": "Enable Grafana to have a remote Alertmanager instance as the primary Alertmanager.", - "stage": "experimental", - "codeowner": "@grafana/alerting-squad" - } - }, - { - "metadata": { - "name": "alertmanagerRemoteOnly", - "resourceVersion": "1698667200000", - "creationTimestamp": "2023-10-30T12:00:00Z" - }, - "spec": { - "description": "Disable the internal Alertmanager and only use the external one defined.", - "stage": "experimental", - "codeowner": "@grafana/alerting-squad" - } - }, - { - "metadata": { - "name": "annotationPermissionUpdate", - "resourceVersion": "1698753600000", - "creationTimestamp": "2023-10-31T12:00:00Z" - }, - "spec": { - "description": "Separate annotation permissions from dashboard permissions to allow for more granular control.", - "stage": "experimental", - "codeowner": "@grafana/identity-access-team" - } - }, - { - "metadata": { - "name": "extractFieldsNameDeduplication", - "resourceVersion": "1707523537136", - "creationTimestamp": "2023-11-02T12:00:00Z", - "annotations": { - "grafana.app/updatedTimestamp": "2024-02-10 00:05:37.1362 +0000 UTC" - } - }, - "spec": { - "description": "Make sure extracted field names are unique in the dataframe", - "stage": "experimental", - "codeowner": "@grafana/dataviz-squad", - "frontend": true - } - }, - { - "metadata": { - "name": "dashboardSceneForViewers", - "resourceVersion": "1698926400000", - "creationTimestamp": "2023-11-02T12:00:00Z" - }, - "spec": { - "description": "Enables dashboard rendering using Scenes for viewer roles", - "stage": "experimental", - "codeowner": "@grafana/dashboards-squad", - "frontend": true - } - }, - { - "metadata": { - "name": "dashboardScene", - "resourceVersion": "1699876800000", - "creationTimestamp": "2023-11-13T12:00:00Z" - }, - "spec": { - "description": "Enables dashboard rendering using scenes for all roles", - "stage": "experimental", - "codeowner": "@grafana/dashboards-squad", - "frontend": true - } - }, { "metadata": { "name": "panelFilterVariable", - "resourceVersion": "1699012800000", - "creationTimestamp": "2023-11-03T12:00:00Z" + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" }, "spec": { "description": "Enables use of the `systemPanelFilterVar` variable to filter panels in a dashboard", @@ -1686,21 +144,275 @@ }, { "metadata": { - "name": "pdfTables", - "resourceVersion": "1699272000000", - "creationTimestamp": "2023-11-06T12:00:00Z" + "name": "displayAnonymousStats", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" }, "spec": { - "description": "Enables generating table data as PDF in reporting", + "description": "Enables anonymous stats to be shown in the UI for Grafana", + "stage": "GA", + "codeowner": "@grafana/identity-access-team", + "frontend": true + } + }, + { + "metadata": { + "name": "logRequestsInstrumentedAsUnknown", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Logs the path for requests that are instrumented as unknown", + "stage": "experimental", + "codeowner": "@grafana/hosted-grafana-team" + } + }, + { + "metadata": { + "name": "dashboardEmbed", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Allow embedding dashboard for external use in Code editors", + "stage": "experimental", + "codeowner": "@grafana/grafana-as-code", + "frontend": true + } + }, + { + "metadata": { + "name": "sqlDatasourceDatabaseSelection", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Enables previous SQL data source dataset dropdown behavior", "stage": "preview", - "codeowner": "@grafana/sharing-squad" + "codeowner": "@grafana/dataviz-squad", + "frontend": true, + "hideFromAdminPage": true + } + }, + { + "metadata": { + "name": "kubernetesSnapshots", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Routes snapshot requests from /api to the /apis endpoint", + "stage": "experimental", + "codeowner": "@grafana/grafana-app-platform-squad", + "requiresRestart": true + } + }, + { + "metadata": { + "name": "extractFieldsNameDeduplication", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Make sure extracted field names are unique in the dataframe", + "stage": "experimental", + "codeowner": "@grafana/dataviz-squad", + "frontend": true + } + }, + { + "metadata": { + "name": "vizAndWidgetSplit", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Split panels between visualizations and widgets", + "stage": "experimental", + "codeowner": "@grafana/dashboards-squad", + "frontend": true + } + }, + { + "metadata": { + "name": "idForwarding", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Generate signed id token for identity that can be forwarded to plugins and external services", + "stage": "experimental", + "codeowner": "@grafana/identity-access-team" + } + }, + { + "metadata": { + "name": "featureHighlights", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Highlight Grafana Enterprise features", + "stage": "GA", + "codeowner": "@grafana/grafana-as-code", + "allowSelfServe": true + } + }, + { + "metadata": { + "name": "clientTokenRotation", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Replaces the current in-request token rotation so that the client initiates the rotation", + "stage": "GA", + "codeowner": "@grafana/identity-access-team" + } + }, + { + "metadata": { + "name": "unifiedRequestLog", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Writes error logs to the request logger", + "stage": "experimental", + "codeowner": "@grafana/backend-platform" + } + }, + { + "metadata": { + "name": "kubernetesQueryServiceRewrite", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Rewrite requests targeting /ds/query to the query service", + "stage": "experimental", + "codeowner": "@grafana/grafana-app-platform-squad", + "requiresDevMode": true, + "requiresRestart": true + } + }, + { + "metadata": { + "name": "alertmanagerRemoteOnly", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Disable the internal Alertmanager and only use the external one defined.", + "stage": "experimental", + "codeowner": "@grafana/alerting-squad" + } + }, + { + "metadata": { + "name": "alertStateHistoryLokiPrimary", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Enable a remote Loki instance as the primary source for state history reads.", + "stage": "experimental", + "codeowner": "@grafana/alerting-squad" + } + }, + { + "metadata": { + "name": "extraThemes", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Enables extra themes", + "stage": "experimental", + "codeowner": "@grafana/grafana-frontend-platform", + "frontend": true + } + }, + { + "metadata": { + "name": "awsDatasourcesTempCredentials", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Support temporary security credentials in AWS plugins for Grafana Cloud customers", + "stage": "experimental", + "codeowner": "@grafana/aws-datasources" + } + }, + { + "metadata": { + "name": "nestedFolders", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Enable folder nesting", + "stage": "preview", + "codeowner": "@grafana/backend-platform" + } + }, + { + "metadata": { + "name": "lokiLogsDataplane", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Changes logs responses from Loki to be compliant with the dataplane specification.", + "stage": "experimental", + "codeowner": "@grafana/observability-logs" + } + }, + { + "metadata": { + "name": "groupToNestedTableTransformation", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Enables the group to nested table transformation", + "stage": "preview", + "codeowner": "@grafana/dataviz-squad", + "frontend": true + } + }, + { + "metadata": { + "name": "topnav", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Enables topnav support in external plugins. The new Grafana navigation cannot be disabled.", + "stage": "deprecated", + "codeowner": "@grafana/grafana-frontend-platform" + } + }, + { + "metadata": { + "name": "unifiedStorage", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "SQL-based k8s storage", + "stage": "experimental", + "codeowner": "@grafana/grafana-app-platform-squad", + "requiresDevMode": true, + "requiresRestart": true } }, { "metadata": { "name": "ssoSettingsApi", - "resourceVersion": "1699444800000", - "creationTimestamp": "2023-11-08T12:00:00Z" + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" }, "spec": { "description": "Enables the SSO settings API", @@ -1711,8 +423,8 @@ { "metadata": { "name": "canvasPanelPanZoom", - "resourceVersion": "1703678400000", - "creationTimestamp": "2023-12-27T12:00:00Z" + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" }, "spec": { "description": "Allow pan and zoom in canvas panel", @@ -1723,12 +435,142 @@ }, { "metadata": { - "name": "logsInfiniteScrolling", - "resourceVersion": "1699531200000", - "creationTimestamp": "2023-11-09T12:00:00Z" + "name": "newPDFRendering", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" }, "spec": { - "description": "Enables infinite scrolling for the Logs panel in Explore and Dashboards", + "description": "New implementation for the dashboard to PDF rendering", + "stage": "experimental", + "codeowner": "@grafana/sharing-squad" + } + }, + { + "metadata": { + "name": "alertingNoDataErrorExecution", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Changes how Alerting state manager handles execution of NoData/Error", + "stage": "GA", + "codeowner": "@grafana/alerting-squad", + "requiresRestart": true + } + }, + { + "metadata": { + "name": "panelMonitoring", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Enables panel monitoring through logs and measurements", + "stage": "experimental", + "codeowner": "@grafana/dataviz-squad", + "frontend": true + } + }, + { + "metadata": { + "name": "pluginsInstrumentationStatusSource", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Include a status source label for plugin request metrics and logs", + "stage": "experimental", + "codeowner": "@grafana/plugins-platform-backend" + } + }, + { + "metadata": { + "name": "dashboardSceneForViewers", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Enables dashboard rendering using Scenes for viewer roles", + "stage": "experimental", + "codeowner": "@grafana/dashboards-squad", + "frontend": true + } + }, + { + "metadata": { + "name": "lokiQueryHints", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Enables query hints for Loki", + "stage": "GA", + "codeowner": "@grafana/observability-logs", + "frontend": true + } + }, + { + "metadata": { + "name": "editPanelCSVDragAndDrop", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Enables drag and drop for CSV and Excel files", + "stage": "experimental", + "codeowner": "@grafana/dataviz-squad", + "frontend": true + } + }, + { + "metadata": { + "name": "dataplaneFrontendFallback", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Support dataplane contract field name change for transformations and field name matchers where the name is different", + "stage": "GA", + "codeowner": "@grafana/observability-metrics", + "frontend": true, + "allowSelfServe": true + } + }, + { + "metadata": { + "name": "influxdbSqlSupport", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Enable InfluxDB SQL query language support with new querying UI", + "stage": "GA", + "codeowner": "@grafana/observability-metrics", + "requiresRestart": true, + "allowSelfServe": true + } + }, + { + "metadata": { + "name": "frontendSandboxMonitorOnly", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Enables monitor only in the plugin frontend sandbox (if enabled)", + "stage": "experimental", + "codeowner": "@grafana/plugins-platform-backend", + "frontend": true + } + }, + { + "metadata": { + "name": "exploreScrollableLogsContainer", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Improves the scrolling behavior of logs in Explore", "stage": "experimental", "codeowner": "@grafana/observability-logs", "frontend": true @@ -1736,36 +578,21 @@ }, { "metadata": { - "name": "flameGraphItemCollapsing", - "resourceVersion": "1699531200000", - "creationTimestamp": "2023-11-09T12:00:00Z" + "name": "externalCorePlugins", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" }, "spec": { - "description": "Allow collapsing of flame graph items", + "description": "Allow core plugins to be loaded as external", "stage": "experimental", - "codeowner": "@grafana/observability-traces-and-profiling", - "frontend": true - } - }, - { - "metadata": { - "name": "alertingDetailsViewV2", - "resourceVersion": "1699531200000", - "creationTimestamp": "2023-11-09T12:00:00Z" - }, - "spec": { - "description": "Enables the preview of the new alert details view", - "stage": "experimental", - "codeowner": "@grafana/alerting-squad", - "frontend": true, - "hideFromDocs": true + "codeowner": "@grafana/plugins-platform-backend" } }, { "metadata": { "name": "datatrails", - "resourceVersion": "1700049600000", - "creationTimestamp": "2023-11-15T12:00:00Z" + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" }, "spec": { "description": "Enables the new core app datatrails", @@ -1775,124 +602,11 @@ "hideFromDocs": true } }, - { - "metadata": { - "name": "alertingSimplifiedRouting", - "resourceVersion": "1699617600000", - "creationTimestamp": "2023-11-10T12:00:00Z" - }, - "spec": { - "description": "Enables the simplified routing for alerting", - "stage": "experimental", - "codeowner": "@grafana/alerting-squad", - "hideFromDocs": true - } - }, - { - "metadata": { - "name": "logRowsPopoverMenu", - "resourceVersion": "1700136000000", - "creationTimestamp": "2023-11-16T12:00:00Z" - }, - "spec": { - "description": "Enable filtering menu displayed when text of a log line is selected", - "stage": "GA", - "codeowner": "@grafana/observability-logs", - "frontend": true - } - }, - { - "metadata": { - "name": "pluginsSkipHostEnvVars", - "resourceVersion": "1700049600000", - "creationTimestamp": "2023-11-15T12:00:00Z" - }, - "spec": { - "description": "Disables passing host environment variable to plugin processes", - "stage": "experimental", - "codeowner": "@grafana/plugins-platform-backend" - } - }, - { - "metadata": { - "name": "tableSharedCrosshair", - "resourceVersion": "1707523537136", - "creationTimestamp": "2023-12-12T12:00:00Z", - "annotations": { - "grafana.app/updatedTimestamp": "2024-02-10 00:05:37.1362 +0000 UTC" - } - }, - "spec": { - "description": "Enables shared crosshair in table panel", - "stage": "experimental", - "codeowner": "@grafana/dataviz-squad", - "frontend": true - } - }, - { - "metadata": { - "name": "regressionTransformation", - "resourceVersion": "1707523537136", - "creationTimestamp": "2023-11-24T12:00:00Z", - "annotations": { - "grafana.app/updatedTimestamp": "2024-02-10 00:05:37.1362 +0000 UTC" - } - }, - "spec": { - "description": "Enables regression analysis transformation", - "stage": "preview", - "codeowner": "@grafana/dataviz-squad", - "frontend": true - } - }, - { - "metadata": { - "name": "displayAnonymousStats", - "resourceVersion": "1701259200000", - "creationTimestamp": "2023-11-29T12:00:00Z" - }, - "spec": { - "description": "Enables anonymous stats to be shown in the UI for Grafana", - "stage": "GA", - "codeowner": "@grafana/identity-access-team", - "frontend": true - } - }, - { - "metadata": { - "name": "lokiQueryHints", - "resourceVersion": "1702900800000", - "creationTimestamp": "2023-12-18T12:00:00Z" - }, - "spec": { - "description": "Enables query hints for Loki", - "stage": "GA", - "codeowner": "@grafana/observability-logs", - "frontend": true - } - }, - { - "metadata": { - "name": "kubernetesFeatureToggles", - "resourceVersion": "1703216580000", - "creationTimestamp": "2023-12-22T03:43:00Z" - }, - "spec": { - "description": "Use the kubernetes API for feature toggle management in the frontend", - "stage": "experimental", - "codeowner": "@grafana/grafana-operator-experience-squad", - "frontend": true, - "hideFromAdminPage": true - } - }, { "metadata": { "name": "alertingPreviewUpgrade", - "resourceVersion": "1707425412785", - "creationTimestamp": "2024-01-03T12:00:00Z", - "annotations": { - "grafana.app/updatedTimestamp": "2024-02-08 20:50:12.785364 +0000 UTC" - } + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" }, "spec": { "description": "Show Unified Alerting preview and upgrade page in legacy alerting", @@ -1903,22 +617,344 @@ }, { "metadata": { - "name": "enablePluginsTracingByDefault", - "resourceVersion": "1704801600000", - "creationTimestamp": "2024-01-09T12:00:00Z" + "name": "exploreContentOutline", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" }, "spec": { - "description": "Enable plugin tracing for all external plugins", + "description": "Content outline sidebar", + "stage": "GA", + "codeowner": "@grafana/explore-squad", + "frontend": true, + "allowSelfServe": true + } + }, + { + "metadata": { + "name": "logsContextDatasourceUi", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Allow datasource to provide custom UI for context view", + "stage": "GA", + "codeowner": "@grafana/observability-logs", + "frontend": true, + "allowSelfServe": true + } + }, + { + "metadata": { + "name": "lokiPredefinedOperations", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Adds predefined query operations to Loki query editor", "stage": "experimental", - "codeowner": "@grafana/plugins-platform-backend", + "codeowner": "@grafana/observability-logs", + "frontend": true + } + }, + { + "metadata": { + "name": "lokiRunQueriesInParallel", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Enables running Loki queries in parallel", + "stage": "privatePreview", + "codeowner": "@grafana/observability-logs" + } + }, + { + "metadata": { + "name": "promQLScope", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "In-development feature that will allow injection of labels into prometheus queries.", + "stage": "experimental", + "codeowner": "@grafana/observability-metrics" + } + }, + { + "metadata": { + "name": "live-service-web-worker", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "This will use a webworker thread to processes events rather than the main thread", + "stage": "experimental", + "codeowner": "@grafana/grafana-app-platform-squad", + "frontend": true + } + }, + { + "metadata": { + "name": "disableSecretsCompatibility", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Disable duplicated secret storage in legacy tables", + "stage": "experimental", + "codeowner": "@grafana/hosted-grafana-team", "requiresRestart": true } }, + { + "metadata": { + "name": "prometheusIncrementalQueryInstrumentation", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Adds RudderStack events to incremental queries", + "stage": "experimental", + "codeowner": "@grafana/observability-metrics", + "frontend": true + } + }, + { + "metadata": { + "name": "storage", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Configurable storage for dashboards, datasources, and resources", + "stage": "experimental", + "codeowner": "@grafana/grafana-app-platform-squad" + } + }, + { + "metadata": { + "name": "redshiftAsyncQueryDataSupport", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Enable async query data support for Redshift", + "stage": "GA", + "codeowner": "@grafana/aws-datasources" + } + }, + { + "metadata": { + "name": "awsDatasourcesNewFormStyling", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Applies new form styling for configuration and query editors in AWS plugins", + "stage": "preview", + "codeowner": "@grafana/aws-datasources", + "frontend": true + } + }, + { + "metadata": { + "name": "libraryPanelRBAC", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Enables RBAC support for library panels", + "stage": "experimental", + "codeowner": "@grafana/dashboards-squad", + "requiresRestart": true + } + }, + { + "metadata": { + "name": "flameGraphItemCollapsing", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Allow collapsing of flame graph items", + "stage": "experimental", + "codeowner": "@grafana/observability-traces-and-profiling", + "frontend": true + } + }, + { + "metadata": { + "name": "alertingDetailsViewV2", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Enables the preview of the new alert details view", + "stage": "experimental", + "codeowner": "@grafana/alerting-squad", + "frontend": true, + "hideFromDocs": true + } + }, + { + "metadata": { + "name": "publicDashboardsEmailSharing", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Enables public dashboard sharing to be restricted to only allowed emails", + "stage": "preview", + "codeowner": "@grafana/sharing-squad", + "hideFromAdminPage": true, + "hideFromDocs": true + } + }, + { + "metadata": { + "name": "influxdbBackendMigration", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Query InfluxDB InfluxQL without the proxy", + "stage": "GA", + "codeowner": "@grafana/observability-metrics", + "frontend": true + } + }, + { + "metadata": { + "name": "angularDeprecationUI", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Display new Angular deprecation-related UI features", + "stage": "experimental", + "codeowner": "@grafana/plugins-platform-backend", + "frontend": true + } + }, + { + "metadata": { + "name": "grafanaAPIServerWithExperimentalAPIs", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Register experimental APIs with the k8s API server", + "stage": "experimental", + "codeowner": "@grafana/grafana-app-platform-squad", + "requiresDevMode": true, + "requiresRestart": true + } + }, + { + "metadata": { + "name": "awsAsyncQueryCaching", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Enable caching for async queries for Redshift and Athena. Requires that the datasource has caching and async query support enabled", + "stage": "GA", + "codeowner": "@grafana/aws-datasources" + } + }, + { + "metadata": { + "name": "wargamesTesting", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Placeholder feature flag for internal testing", + "stage": "experimental", + "codeowner": "@grafana/hosted-grafana-team" + } + }, + { + "metadata": { + "name": "teamHttpHeaders", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Enables datasources to apply team headers to the client requests", + "stage": "experimental", + "codeowner": "@grafana/identity-access-team" + } + }, + { + "metadata": { + "name": "dashboardScene", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Enables dashboard rendering using scenes for all roles", + "stage": "experimental", + "codeowner": "@grafana/dashboards-squad", + "frontend": true + } + }, + { + "metadata": { + "name": "correlations", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Correlations page", + "stage": "GA", + "codeowner": "@grafana/explore-squad", + "allowSelfServe": true + } + }, + { + "metadata": { + "name": "datasourceQueryMultiStatus", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Introduce HTTP 207 Multi Status for api/ds/query", + "stage": "experimental", + "codeowner": "@grafana/plugins-platform-backend" + } + }, + { + "metadata": { + "name": "traceQLStreaming", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Enables response streaming of TraceQL queries of the Tempo data source", + "stage": "experimental", + "codeowner": "@grafana/observability-traces-and-profiling", + "frontend": true + } + }, + { + "metadata": { + "name": "returnToPrevious", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Enables the return to previous context functionality", + "stage": "experimental", + "codeowner": "@grafana/grafana-frontend-platform", + "frontend": true + } + }, { "metadata": { "name": "cloudRBACRoles", - "resourceVersion": "1704888000000", - "creationTimestamp": "2024-01-10T12:00:00Z" + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" }, "spec": { "description": "Enabled grafana cloud specific RBAC roles", @@ -1928,11 +964,273 @@ "hideFromDocs": true } }, + { + "metadata": { + "name": "kubernetesAggregator", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Enable grafana aggregator", + "stage": "experimental", + "codeowner": "@grafana/grafana-app-platform-squad", + "requiresRestart": true + } + }, + { + "metadata": { + "name": "kubernetesFeatureToggles", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Use the kubernetes API for feature toggle management in the frontend", + "stage": "experimental", + "codeowner": "@grafana/grafana-operator-experience-squad", + "frontend": true, + "hideFromAdminPage": true + } + }, + { + "metadata": { + "name": "disableAngular", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Dynamic flag to disable angular at runtime. The preferred method is to set `angular_support_enabled` to `false` in the [security] settings, which allows you to change the state at runtime.", + "stage": "preview", + "codeowner": "@grafana/dataviz-squad", + "frontend": true, + "hideFromAdminPage": true + } + }, + { + "metadata": { + "name": "canvasPanelNesting", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Allow elements nesting", + "stage": "experimental", + "codeowner": "@grafana/dataviz-squad", + "frontend": true, + "hideFromAdminPage": true + } + }, + { + "metadata": { + "name": "dashboardSceneSolo", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Enables rendering dashboards using scenes for solo panels", + "stage": "experimental", + "codeowner": "@grafana/dashboards-squad", + "frontend": true + } + }, + { + "metadata": { + "name": "recordedQueriesMulti", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Enables writing multiple items from a single query within Recorded Queries", + "stage": "GA", + "codeowner": "@grafana/observability-metrics" + } + }, + { + "metadata": { + "name": "pluginsSkipHostEnvVars", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Disables passing host environment variable to plugin processes", + "stage": "experimental", + "codeowner": "@grafana/plugins-platform-backend" + } + }, + { + "metadata": { + "name": "autoMigrateGraphPanel", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Migrate old graph panel to supported time series panel - broken out from autoMigrateOldPanels to enable granular tracking", + "stage": "preview", + "codeowner": "@grafana/dataviz-squad", + "frontend": true + } + }, + { + "metadata": { + "name": "lokiQuerySplittingConfig", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Give users the option to configure split durations for Loki queries", + "stage": "experimental", + "codeowner": "@grafana/observability-logs", + "frontend": true + } + }, + { + "metadata": { + "name": "enableElasticsearchBackendQuerying", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Enable the processing of queries and responses in the Elasticsearch data source through backend", + "stage": "GA", + "codeowner": "@grafana/observability-logs", + "allowSelfServe": true + } + }, + { + "metadata": { + "name": "refactorVariablesTimeRange", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Refactor time range variables flow to reduce number of API calls made when query variables are chained", + "stage": "preview", + "codeowner": "@grafana/dashboards-squad", + "hideFromAdminPage": true + } + }, + { + "metadata": { + "name": "cloudWatchLogsMonacoEditor", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Enables the Monaco editor for CloudWatch Logs queries", + "stage": "GA", + "codeowner": "@grafana/aws-datasources", + "frontend": true, + "allowSelfServe": true + } + }, + { + "metadata": { + "name": "grafanaAPIServerEnsureKubectlAccess", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Start an additional https handler and write kubectl options", + "stage": "experimental", + "codeowner": "@grafana/grafana-app-platform-squad", + "requiresDevMode": true, + "requiresRestart": true + } + }, + { + "metadata": { + "name": "formatString", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Enable format string transformer", + "stage": "preview", + "codeowner": "@grafana/dataviz-squad", + "frontend": true + } + }, + { + "metadata": { + "name": "transformationsVariableSupport", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Allows using variables in transformations", + "stage": "preview", + "codeowner": "@grafana/dataviz-squad", + "frontend": true + } + }, + { + "metadata": { + "name": "traceToMetrics", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Enable trace to metrics links", + "stage": "experimental", + "codeowner": "@grafana/observability-traces-and-profiling", + "frontend": true + } + }, + { + "metadata": { + "name": "influxdbRunQueriesInParallel", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Enables running InfluxDB Influxql queries in parallel", + "stage": "privatePreview", + "codeowner": "@grafana/observability-metrics" + } + }, + { + "metadata": { + "name": "externalServiceAuth", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Starts an OAuth2 authentication provider for external services", + "stage": "experimental", + "codeowner": "@grafana/identity-access-team", + "requiresDevMode": true + } + }, + { + "metadata": { + "name": "addFieldFromCalculationStatFunctions", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Add cumulative and window functions to the add field from calculation transformation", + "stage": "preview", + "codeowner": "@grafana/dataviz-squad", + "frontend": true + } + }, + { + "metadata": { + "name": "alertingSimplifiedRouting", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Enables the simplified routing for alerting", + "stage": "experimental", + "codeowner": "@grafana/alerting-squad", + "hideFromDocs": true + } + }, { "metadata": { "name": "alertingQueryOptimization", - "resourceVersion": "1704888000000", - "creationTimestamp": "2024-01-10T12:00:00Z" + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" }, "spec": { "description": "Optimizes eligible queries in order to reduce load on datasources", @@ -1942,22 +1240,59 @@ }, { "metadata": { - "name": "newFolderPicker", - "resourceVersion": "1705060800000", - "creationTimestamp": "2024-01-12T12:00:00Z" + "name": "nodeGraphDotLayout", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" }, "spec": { - "description": "Enables the nested folder picker without having nested folders enabled", + "description": "Changed the layout algorithm for the node graph", "stage": "experimental", - "codeowner": "@grafana/grafana-frontend-platform", + "codeowner": "@grafana/observability-traces-and-profiling", "frontend": true } }, + { + "metadata": { + "name": "logsExploreTableVisualisation", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "A table visualisation for logs in Explore", + "stage": "GA", + "codeowner": "@grafana/observability-logs", + "frontend": true + } + }, + { + "metadata": { + "name": "prometheusConfigOverhaulAuth", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Update the Prometheus configuration page with the new auth component", + "stage": "GA", + "codeowner": "@grafana/observability-metrics" + } + }, + { + "metadata": { + "name": "alertmanagerRemoteSecondary", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Enable Grafana to sync configuration and state with a remote Alertmanager.", + "stage": "experimental", + "codeowner": "@grafana/alerting-squad" + } + }, { "metadata": { "name": "jitterAlertRulesWithinGroups", - "resourceVersion": "1705492800000", - "creationTimestamp": "2024-01-17T12:00:00Z" + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" }, "spec": { "description": "Distributes alert rule evaluations more evenly over time, including spreading out rules within the same group", @@ -1967,23 +1302,11 @@ "hideFromDocs": true } }, - { - "metadata": { - "name": "onPremToCloudMigrations", - "resourceVersion": "1705894200000", - "creationTimestamp": "2024-01-22T03:30:00Z" - }, - "spec": { - "description": "In-development feature that will allow users to easily migrate their on-prem Grafana instances to Grafana Cloud.", - "stage": "experimental", - "codeowner": "@grafana/grafana-operator-experience-squad" - } - }, { "metadata": { "name": "alertingSaveStatePeriodic", - "resourceVersion": "1705924800000", - "creationTimestamp": "2024-01-22T12:00:00Z" + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" }, "spec": { "description": "Writes the state periodically to the database, asynchronous to rule evaluation", @@ -1993,24 +1316,381 @@ }, { "metadata": { - "name": "promQLScope", - "resourceVersion": "1706486400000", - "creationTimestamp": "2024-01-29T00:00:00Z" + "name": "alertStateHistoryLokiOnly", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" }, "spec": { - "description": "In-development feature that will allow injection of labels into prometheus queries.", + "description": "Disable Grafana alerts from emitting annotations when a remote Loki instance is available.", + "stage": "experimental", + "codeowner": "@grafana/alerting-squad" + } + }, + { + "metadata": { + "name": "pluginsFrontendSandbox", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Enables the plugins frontend sandbox", + "stage": "experimental", + "codeowner": "@grafana/plugins-platform-backend", + "frontend": true + } + }, + { + "metadata": { + "name": "lokiFormatQuery", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Enables the ability to format Loki queries", + "stage": "experimental", + "codeowner": "@grafana/observability-logs", + "frontend": true + } + }, + { + "metadata": { + "name": "alertingInsights", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Show the new alerting insights landing page", + "stage": "GA", + "codeowner": "@grafana/alerting-squad", + "frontend": true, + "hideFromAdminPage": true + } + }, + { + "metadata": { + "name": "nestedFolderPicker", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Enables the new folder picker to work with nested folders. Requires the nestedFolders feature toggle", + "stage": "GA", + "codeowner": "@grafana/grafana-frontend-platform", + "frontend": true, + "allowSelfServe": true + } + }, + { + "metadata": { + "name": "alertingNoNormalState", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Stop maintaining state of alerts that are not firing", + "stage": "preview", + "codeowner": "@grafana/alerting-squad", + "hideFromAdminPage": true + } + }, + { + "metadata": { + "name": "alertStateHistoryLokiSecondary", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Enable Grafana to write alert state history to an external Loki instance in addition to Grafana annotations.", + "stage": "experimental", + "codeowner": "@grafana/alerting-squad" + } + }, + { + "metadata": { + "name": "pluginsAPIMetrics", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Sends metrics of public grafana packages usage by plugins", + "stage": "experimental", + "codeowner": "@grafana/plugins-platform-backend", + "frontend": true + } + }, + { + "metadata": { + "name": "newFolderPicker", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Enables the nested folder picker without having nested folders enabled", + "stage": "experimental", + "codeowner": "@grafana/grafana-frontend-platform", + "frontend": true + } + }, + { + "metadata": { + "name": "onPremToCloudMigrations", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "In-development feature that will allow users to easily migrate their on-prem Grafana instances to Grafana Cloud.", + "stage": "experimental", + "codeowner": "@grafana/grafana-operator-experience-squad" + } + }, + { + "metadata": { + "name": "migrationLocking", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Lock database during migrations", + "stage": "preview", + "codeowner": "@grafana/backend-platform" + } + }, + { + "metadata": { + "name": "influxqlStreamingParser", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Enable streaming JSON parser for InfluxDB datasource InfluxQL query language", "stage": "experimental", "codeowner": "@grafana/observability-metrics" } }, { "metadata": { - "name": "nodeGraphDotLayout", - "resourceVersion": "1704196800000", - "creationTimestamp": "2024-01-02T12:00:00Z" + "name": "featureToggleAdminPage", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" }, "spec": { - "description": "Changed the layout algorithm for the node graph", + "description": "Enable admin page for managing feature toggles from the Grafana front-end", + "stage": "experimental", + "codeowner": "@grafana/grafana-operator-experience-squad", + "requiresRestart": true + } + }, + { + "metadata": { + "name": "recoveryThreshold", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Enables feature recovery threshold (aka hysteresis) for threshold server-side expression", + "stage": "GA", + "codeowner": "@grafana/alerting-squad", + "requiresRestart": true + } + }, + { + "metadata": { + "name": "annotationPermissionUpdate", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Separate annotation permissions from dashboard permissions to allow for more granular control.", + "stage": "experimental", + "codeowner": "@grafana/identity-access-team" + } + }, + { + "metadata": { + "name": "newVizTooltips", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "New visualizations tooltips UX", + "stage": "preview", + "codeowner": "@grafana/dataviz-squad", + "frontend": true + } + }, + { + "metadata": { + "name": "scenes", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Experimental framework to build interactive dashboards", + "stage": "experimental", + "codeowner": "@grafana/dashboards-squad", + "frontend": true + } + }, + { + "metadata": { + "name": "accessControlOnCall", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Access control primitives for OnCall", + "stage": "preview", + "codeowner": "@grafana/identity-access-team", + "hideFromAdminPage": true + } + }, + { + "metadata": { + "name": "disableSSEDataplane", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Disables dataplane specific processing in server side expressions.", + "stage": "experimental", + "codeowner": "@grafana/observability-metrics" + } + }, + { + "metadata": { + "name": "cloudWatchWildCardDimensionValues", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Fetches dimension values from CloudWatch to correctly label wildcard dimensions", + "stage": "GA", + "codeowner": "@grafana/aws-datasources", + "allowSelfServe": true + } + }, + { + "metadata": { + "name": "externalServiceAccounts", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Automatic service account and token setup for plugins", + "stage": "preview", + "codeowner": "@grafana/identity-access-team", + "hideFromAdminPage": true + } + }, + { + "metadata": { + "name": "lokiStructuredMetadata", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Enables the loki data source to request structured metadata from the Loki server", + "stage": "experimental", + "codeowner": "@grafana/observability-logs" + } + }, + { + "metadata": { + "name": "publicDashboards", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "[Deprecated] Public dashboards are now enabled by default; to disable them, use the configuration setting. This feature toggle will be removed in the next major version.", + "stage": "GA", + "codeowner": "@grafana/sharing-squad", + "allowSelfServe": true + } + }, + { + "metadata": { + "name": "showDashboardValidationWarnings", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Show warnings when dashboards do not validate against the schema", + "stage": "experimental", + "codeowner": "@grafana/dashboards-squad" + } + }, + { + "metadata": { + "name": "lokiMetricDataplane", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Changes metric responses from Loki to be compliant with the dataplane specification.", + "stage": "GA", + "codeowner": "@grafana/observability-logs", + "allowSelfServe": true + } + }, + { + "metadata": { + "name": "dashgpt", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Enable AI powered features in dashboards", + "stage": "preview", + "codeowner": "@grafana/dashboards-squad", + "frontend": true + } + }, + { + "metadata": { + "name": "pluginsDynamicAngularDetectionPatterns", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Enables fetching Angular detection patterns for plugins from GCOM and fallback to hardcoded ones", + "stage": "experimental", + "codeowner": "@grafana/plugins-platform-backend" + } + }, + { + "metadata": { + "name": "mlExpressions", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Enable support for Machine Learning in server-side expressions", + "stage": "experimental", + "codeowner": "@grafana/alerting-squad" + } + }, + { + "metadata": { + "name": "configurableSchedulerTick", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Enable changing the scheduler base interval via configuration option unified_alerting.scheduler_tick_interval", + "stage": "experimental", + "codeowner": "@grafana/alerting-squad", + "requiresRestart": true, + "hideFromDocs": true + } + }, + { + "metadata": { + "name": "metricsSummary", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Enables metrics summary queries in the Tempo data source", "stage": "experimental", "codeowner": "@grafana/observability-traces-and-profiling", "frontend": true @@ -2018,12 +1698,25 @@ }, { "metadata": { - "name": "groupToNestedTableTransformation", - "resourceVersion": "1707134400000", - "creationTimestamp": "2024-02-05T12:00:00Z" + "name": "prometheusPromQAIL", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" }, "spec": { - "description": "Enables the group to nested table transformation", + "description": "Prometheus and AI/ML to assist users in creating a query", + "stage": "experimental", + "codeowner": "@grafana/observability-metrics", + "frontend": true + } + }, + { + "metadata": { + "name": "regressionTransformation", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Enables regression analysis transformation", "stage": "preview", "codeowner": "@grafana/dataviz-squad", "frontend": true @@ -2031,24 +1724,231 @@ }, { "metadata": { - "name": "newPDFRendering", - "resourceVersion": "1707425412785", - "creationTimestamp": "2024-02-08T20:50:12Z" + "name": "alertingBacktesting", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" }, "spec": { - "description": "New implementation for the dashboard to PDF rendering", + "description": "Rule backtesting API for alerting", "stage": "experimental", - "codeowner": "@grafana/sharing-squad" + "codeowner": "@grafana/alerting-squad" } }, { "metadata": { - "name": "autoMigrateGraphPanel", - "resourceVersion": "1707433170195", - "creationTimestamp": "2024-02-08T22:59:30Z" + "name": "prometheusDataplane", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" }, "spec": { - "description": "Migrate old graph panel to supported time series panel - broken out from autoMigrateOldPanels to enable granular tracking", + "description": "Changes responses to from Prometheus to be compliant with the dataplane specification. In particular, when this feature toggle is active, the numeric `Field.Name` is set from 'Value' to the value of the `__name__` label.", + "stage": "GA", + "codeowner": "@grafana/observability-metrics", + "allowSelfServe": true + } + }, + { + "metadata": { + "name": "renderAuthJWT", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Uses JWT-based auth for rendering instead of relying on remote cache", + "stage": "preview", + "codeowner": "@grafana/grafana-as-code", + "hideFromAdminPage": true + } + }, + { + "metadata": { + "name": "reportingRetries", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Enables rendering retries for the reporting feature", + "stage": "preview", + "codeowner": "@grafana/sharing-squad", + "requiresRestart": true + } + }, + { + "metadata": { + "name": "athenaAsyncQueryDataSupport", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Enable async query data support for Athena", + "stage": "GA", + "codeowner": "@grafana/aws-datasources", + "frontend": true + } + }, + { + "metadata": { + "name": "alertmanagerRemotePrimary", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Enable Grafana to have a remote Alertmanager instance as the primary Alertmanager.", + "stage": "experimental", + "codeowner": "@grafana/alerting-squad" + } + }, + { + "metadata": { + "name": "logRowsPopoverMenu", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Enable filtering menu displayed when text of a log line is selected", + "stage": "GA", + "codeowner": "@grafana/observability-logs", + "frontend": true + } + }, + { + "metadata": { + "name": "dataConnectionsConsole", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Enables a new top-level page called Connections. This page is an experiment that provides a better experience when you install and configure data sources and other plugins.", + "stage": "GA", + "codeowner": "@grafana/plugins-platform-backend", + "allowSelfServe": true + } + }, + { + "metadata": { + "name": "grpcServer", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Run the GRPC server", + "stage": "preview", + "codeowner": "@grafana/grafana-app-platform-squad", + "hideFromAdminPage": true + } + }, + { + "metadata": { + "name": "cloudWatchCrossAccountQuerying", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Enables cross-account querying in CloudWatch datasources", + "stage": "GA", + "codeowner": "@grafana/aws-datasources", + "allowSelfServe": true + } + }, + { + "metadata": { + "name": "mysqlAnsiQuotes", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Use double quotes to escape keyword in a MySQL query", + "stage": "experimental", + "codeowner": "@grafana/backend-platform" + } + }, + { + "metadata": { + "name": "lokiQuerySplitting", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Split large interval queries into subqueries with smaller time intervals", + "stage": "GA", + "codeowner": "@grafana/observability-logs", + "frontend": true, + "allowSelfServe": true + } + }, + { + "metadata": { + "name": "individualCookiePreferences", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Support overriding cookie preferences per user", + "stage": "experimental", + "codeowner": "@grafana/backend-platform" + } + }, + { + "metadata": { + "name": "prometheusMetricEncyclopedia", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Adds the metrics explorer component to the Prometheus query builder as an option in metric select", + "stage": "GA", + "codeowner": "@grafana/observability-metrics", + "frontend": true, + "allowSelfServe": true + } + }, + { + "metadata": { + "name": "tableSharedCrosshair", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Enables shared crosshair in table panel", + "stage": "experimental", + "codeowner": "@grafana/dataviz-squad", + "frontend": true + } + }, + { + "metadata": { + "name": "queryOverLive", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Use Grafana Live WebSocket to execute backend queries", + "stage": "experimental", + "codeowner": "@grafana/grafana-app-platform-squad", + "frontend": true + } + }, + { + "metadata": { + "name": "panelTitleSearch", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Search for dashboards using panel title", + "stage": "preview", + "codeowner": "@grafana/grafana-app-platform-squad", + "hideFromAdminPage": true + } + }, + { + "metadata": { + "name": "autoMigrateOldPanels", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Migrate old angular panels to supported versions (graph, table-old, worldmap, etc)", "stage": "preview", "codeowner": "@grafana/dataviz-squad", "frontend": true @@ -2056,16 +1956,93 @@ }, { "metadata": { - "name": "dashboardSceneSolo", - "resourceVersion": "1707577534071", - "creationTimestamp": "2024-02-10T15:05:34Z" + "name": "disableEnvelopeEncryption", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" }, "spec": { - "description": "Enables rendering dashboards using scenes for solo panels", - "stage": "experimental", - "codeowner": "@grafana/dashboards-squad", + "description": "Disable envelope encryption (emergency only)", + "stage": "GA", + "codeowner": "@grafana/grafana-as-code", + "hideFromAdminPage": true + } + }, + { + "metadata": { + "name": "faroDatasourceSelector", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Enable the data source selector within the Frontend Apps section of the Frontend Observability", + "stage": "preview", + "codeowner": "@grafana/app-o11y", "frontend": true } + }, + { + "metadata": { + "name": "transformationsRedesign", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Enables the transformations redesign", + "stage": "GA", + "codeowner": "@grafana/observability-metrics", + "frontend": true, + "allowSelfServe": true + } + }, + { + "metadata": { + "name": "panelTitleSearchInV1", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Enable searching for dashboards using panel title in search v1", + "stage": "experimental", + "codeowner": "@grafana/backend-platform", + "requiresDevMode": true + } + }, + { + "metadata": { + "name": "enableNativeHTTPHistogram", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Enables native HTTP Histograms", + "stage": "experimental", + "codeowner": "@grafana/hosted-grafana-team" + } + }, + { + "metadata": { + "name": "kubernetesPlaylists", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "Use the kubernetes API in the frontend for playlists, and route /api/playlist requests to k8s", + "stage": "experimental", + "codeowner": "@grafana/grafana-app-platform-squad", + "requiresRestart": true + } + }, + { + "metadata": { + "name": "cachingOptimizeSerializationMemoryUsage", + "resourceVersion": "1707755276481", + "creationTimestamp": "2024-02-12T16:27:56Z" + }, + "spec": { + "description": "If enabled, the caching backend gradually serializes query responses for the cache, comparing against the configured `[caching]max_value_mb` value as it goes. This can can help prevent Grafana from running out of memory while attempting to cache very large query responses.", + "stage": "experimental", + "codeowner": "@grafana/grafana-operator-experience-squad" + } } ] } \ No newline at end of file