| 
				
	
				Actionlint / Lint GitHub Actions files (push) Waiting to run
				
					Details
				
			 
				
	
				Backend Code Checks / Validate Backend Configs (push) Waiting to run
				
					Details
				
			 
				
	
				Backend Unit Tests / Detect whether code changed (push) Waiting to run
				
					Details
				
			 
				
	
				Backend Unit Tests / Grafana (${{ matrix.shard }}) (1/8) (push) Blocked by required conditions
				
					Details
				
			 
				
	
				Backend Unit Tests / Grafana (${{ matrix.shard }}) (2/8) (push) Blocked by required conditions
				
					Details
				
			 
				
	
				Backend Unit Tests / Grafana (${{ matrix.shard }}) (3/8) (push) Blocked by required conditions
				
					Details
				
			 
				
	
				Backend Unit Tests / Grafana (${{ matrix.shard }}) (4/8) (push) Blocked by required conditions
				
					Details
				
			 
				
	
				Backend Unit Tests / Grafana (${{ matrix.shard }}) (5/8) (push) Blocked by required conditions
				
					Details
				
			 
				
	
				Backend Unit Tests / Grafana (${{ matrix.shard }}) (6/8) (push) Blocked by required conditions
				
					Details
				
			 
				
	
				Backend Unit Tests / Grafana (${{ matrix.shard }}) (7/8) (push) Blocked by required conditions
				
					Details
				
			 
				
	
				Backend Unit Tests / Grafana (${{ matrix.shard }}) (8/8) (push) Blocked by required conditions
				
					Details
				
			 
				
	
				Backend Unit Tests / Grafana Enterprise (${{ matrix.shard }}) (1/8) (push) Blocked by required conditions
				
					Details
				
			 
				
	
				Backend Unit Tests / Grafana Enterprise (${{ matrix.shard }}) (2/8) (push) Blocked by required conditions
				
					Details
				
			 
				
	
				Backend Unit Tests / Grafana Enterprise (${{ matrix.shard }}) (3/8) (push) Blocked by required conditions
				
					Details
				
			 
				
	
				Backend Unit Tests / Grafana Enterprise (${{ matrix.shard }}) (4/8) (push) Blocked by required conditions
				
					Details
				
			 
				
	
				Backend Unit Tests / Grafana Enterprise (${{ matrix.shard }}) (5/8) (push) Blocked by required conditions
				
					Details
				
			 
				
	
				Backend Unit Tests / Grafana Enterprise (${{ matrix.shard }}) (6/8) (push) Blocked by required conditions
				
					Details
				
			 
				
	
				Backend Unit Tests / Grafana Enterprise (${{ matrix.shard }}) (7/8) (push) Blocked by required conditions
				
					Details
				
			 
				
	
				Backend Unit Tests / Grafana Enterprise (${{ matrix.shard }}) (8/8) (push) Blocked by required conditions
				
					Details
				
			 
				
	
				Backend Unit Tests / All backend unit tests complete (push) Blocked by required conditions
				
					Details
				
			 
				
	
				CodeQL checks / Analyze (actions) (push) Waiting to run
				
					Details
				
			 
				
	
				CodeQL checks / Analyze (go) (push) Waiting to run
				
					Details
				
			 
				
	
				CodeQL checks / Analyze (javascript) (push) Waiting to run
				
					Details
				
			 
				
	
				Lint Frontend / Detect whether code changed (push) Waiting to run
				
					Details
				
			 
				
	
				Lint Frontend / Lint (push) Blocked by required conditions
				
					Details
				
			 
				
	
				Lint Frontend / Typecheck (push) Blocked by required conditions
				
					Details
				
			 
				
	
				Lint Frontend / Betterer (push) Blocked by required conditions
				
					Details
				
			 
				
	
				golangci-lint / lint-go (push) Waiting to run
				
					Details
				
			 
				
	
				Crowdin Upload Action / upload-sources-to-crowdin (push) Waiting to run
				
					Details
				
			 
				
	
				Verify i18n / verify-i18n (push) Waiting to run
				
					Details
				
			 
				
	
				Documentation / Build & Verify Docs (push) Waiting to run
				
					Details
				
			 
				
	
				End-to-end tests / Detect whether code changed (push) Waiting to run
				
					Details
				
			 
				
	
				End-to-end tests / Build & Package Grafana (push) Blocked by required conditions
				
					Details
				
			 
				
	
				End-to-end tests / Build E2E test runner (push) Blocked by required conditions
				
					Details
				
			 
				
	
				End-to-end tests / ${{ matrix.suite }} (--flags="--env dashboardScene=false", e2e/old-arch/dashboards-suite, dashboards-suite (old arch)) (push) Blocked by required conditions
				
					Details
				
			 
				
	
				End-to-end tests / ${{ matrix.suite }} (--flags="--env dashboardScene=false", e2e/old-arch/panels-suite, panels-suite (old arch)) (push) Blocked by required conditions
				
					Details
				
			 
				
	
				End-to-end tests / ${{ matrix.suite }} (--flags="--env dashboardScene=false", e2e/old-arch/smoke-tests-suite, smoke-tests-suite (old arch)) (push) Blocked by required conditions
				
					Details
				
			 
				
	
				End-to-end tests / ${{ matrix.suite }} (--flags="--env dashboardScene=false", e2e/old-arch/various-suite, various-suite (old arch)) (push) Blocked by required conditions
				
					Details
				
			 
				
	
				End-to-end tests / ${{ matrix.suite }} (e2e/dashboards-suite, dashboards-suite) (push) Blocked by required conditions
				
					Details
				
			 
				
	
				End-to-end tests / ${{ matrix.suite }} (e2e/panels-suite, panels-suite) (push) Blocked by required conditions
				
					Details
				
			 
				
	
				End-to-end tests / ${{ matrix.suite }} (e2e/smoke-tests-suite, smoke-tests-suite) (push) Blocked by required conditions
				
					Details
				
			 
				
	
				End-to-end tests / ${{ matrix.suite }} (e2e/various-suite, various-suite) (push) Blocked by required conditions
				
					Details
				
			 
				
	
				End-to-end tests / Playwright E2E tests (${{ matrix.shard }}/${{ matrix.shardTotal }}) (1, 8) (push) Blocked by required conditions
				
					Details
				
			 
				
	
				End-to-end tests / Playwright E2E tests (${{ matrix.shard }}/${{ matrix.shardTotal }}) (2, 8) (push) Blocked by required conditions
				
					Details
				
			 
				
	
				End-to-end tests / Playwright E2E tests (${{ matrix.shard }}/${{ matrix.shardTotal }}) (3, 8) (push) Blocked by required conditions
				
					Details
				
			 
				
	
				End-to-end tests / Playwright E2E tests (${{ matrix.shard }}/${{ matrix.shardTotal }}) (4, 8) (push) Blocked by required conditions
				
					Details
				
			 
				
	
				End-to-end tests / Playwright E2E tests (${{ matrix.shard }}/${{ matrix.shardTotal }}) (5, 8) (push) Blocked by required conditions
				
					Details
				
			 
				
	
				End-to-end tests / Playwright E2E tests (${{ matrix.shard }}/${{ matrix.shardTotal }}) (6, 8) (push) Blocked by required conditions
				
					Details
				
			 
				
	
				End-to-end tests / Playwright E2E tests (${{ matrix.shard }}/${{ matrix.shardTotal }}) (7, 8) (push) Blocked by required conditions
				
					Details
				
			 
				
	
				End-to-end tests / Playwright E2E tests (${{ matrix.shard }}/${{ matrix.shardTotal }}) (8, 8) (push) Blocked by required conditions
				
					Details
				
			 
				
	
				End-to-end tests / All Playwright tests complete (push) Blocked by required conditions
				
					Details
				
			 
				
	
				End-to-end tests / A11y test (push) Blocked by required conditions
				
					Details
				
			 
				
	
				End-to-end tests / All E2E tests complete (push) Blocked by required conditions
				
					Details
				
			 
				
	
				Frontend tests / Detect whether code changed (push) Waiting to run
				
					Details
				
			 
				
	
				Frontend tests / Unit tests (${{ matrix.chunk }} / 8) (1) (push) Blocked by required conditions
				
					Details
				
			 
				
	
				Frontend tests / Unit tests (${{ matrix.chunk }} / 8) (2) (push) Blocked by required conditions
				
					Details
				
			 
				
	
				Frontend tests / Unit tests (${{ matrix.chunk }} / 8) (3) (push) Blocked by required conditions
				
					Details
				
			 
				
	
				Frontend tests / Unit tests (${{ matrix.chunk }} / 8) (4) (push) Blocked by required conditions
				
					Details
				
			 
				
	
				Frontend tests / Unit tests (${{ matrix.chunk }} / 8) (5) (push) Blocked by required conditions
				
					Details
				
			 
				
	
				Frontend tests / Unit tests (${{ matrix.chunk }} / 8) (6) (push) Blocked by required conditions
				
					Details
				
			 
				
	
				Frontend tests / Unit tests (${{ matrix.chunk }} / 8) (7) (push) Blocked by required conditions
				
					Details
				
			 
				
	
				Frontend tests / Unit tests (${{ matrix.chunk }} / 8) (8) (push) Blocked by required conditions
				
					Details
				
			 
				
	
				Frontend tests / Decoupled plugin tests (push) Blocked by required conditions
				
					Details
				
			 
				
	
				Frontend tests / All frontend unit tests complete (push) Blocked by required conditions
				
					Details
				
			 
				
	
				Integration Tests / Sqlite (${{ matrix.shard }}) (1/8) (push) Waiting to run
				
					Details
				
			 
				
	
				Integration Tests / Sqlite (${{ matrix.shard }}) (2/8) (push) Waiting to run
				
					Details
				
			 
				
	
				Integration Tests / Sqlite (${{ matrix.shard }}) (3/8) (push) Waiting to run
				
					Details
				
			 
				
	
				Integration Tests / Sqlite (${{ matrix.shard }}) (4/8) (push) Waiting to run
				
					Details
				
			 
				
	
				Integration Tests / Sqlite (${{ matrix.shard }}) (5/8) (push) Waiting to run
				
					Details
				
			 
				
	
				Integration Tests / Sqlite (${{ matrix.shard }}) (6/8) (push) Waiting to run
				
					Details
				
			 
				
	
				Integration Tests / Sqlite (${{ matrix.shard }}) (7/8) (push) Waiting to run
				
					Details
				
			 
				
	
				Integration Tests / Sqlite (${{ matrix.shard }}) (8/8) (push) Waiting to run
				
					Details
				
			 
				
	
				Integration Tests / MySQL (${{ matrix.shard }}) (1/8) (push) Waiting to run
				
					Details
				
			 
				
	
				Integration Tests / MySQL (${{ matrix.shard }}) (2/8) (push) Waiting to run
				
					Details
				
			 
				
	
				Integration Tests / MySQL (${{ matrix.shard }}) (3/8) (push) Waiting to run
				
					Details
				
			 
				
	
				Integration Tests / MySQL (${{ matrix.shard }}) (4/8) (push) Waiting to run
				
					Details
				
			 
				
	
				Integration Tests / MySQL (${{ matrix.shard }}) (5/8) (push) Waiting to run
				
					Details
				
			 
				
	
				Integration Tests / MySQL (${{ matrix.shard }}) (6/8) (push) Waiting to run
				
					Details
				
			 
				
	
				Integration Tests / MySQL (${{ matrix.shard }}) (7/8) (push) Waiting to run
				
					Details
				
			 
				
	
				Integration Tests / MySQL (${{ matrix.shard }}) (8/8) (push) Waiting to run
				
					Details
				
			 
				
	
				Integration Tests / Postgres (${{ matrix.shard }}) (1/8) (push) Waiting to run
				
					Details
				
			 
				
	
				Integration Tests / Postgres (${{ matrix.shard }}) (2/8) (push) Waiting to run
				
					Details
				
			 
				
	
				Integration Tests / Postgres (${{ matrix.shard }}) (3/8) (push) Waiting to run
				
					Details
				
			 
				
	
				Integration Tests / Postgres (${{ matrix.shard }}) (4/8) (push) Waiting to run
				
					Details
				
			 
				
	
				Integration Tests / Postgres (${{ matrix.shard }}) (5/8) (push) Waiting to run
				
					Details
				
			 
				
	
				Integration Tests / Postgres (${{ matrix.shard }}) (6/8) (push) Waiting to run
				
					Details
				
			 
				
	
				Integration Tests / Postgres (${{ matrix.shard }}) (7/8) (push) Waiting to run
				
					Details
				
			 
				
	
				Integration Tests / Postgres (${{ matrix.shard }}) (8/8) (push) Waiting to run
				
					Details
				
			 
				
	
				Integration Tests / All backend integration tests complete (push) Blocked by required conditions
				
					Details
				
			 
				
	
				publish-technical-documentation-next / sync (push) Waiting to run
				
					Details
				
			 
				
	
				Reject GitHub secrets / reject-gh-secrets (push) Waiting to run
				
					Details
				
			 
				
	
				Build Release Packages / setup (push) Waiting to run
				
					Details
				
			 
				
	
				Build Release Packages / Dispatch grafana-enterprise build (push) Blocked by required conditions
				
					Details
				
			 
				
	
				Build Release Packages / ${{ needs.setup.outputs.version }} / ${{ matrix.name }} (targz:grafana:darwin/amd64, darwin-amd64) (push) Blocked by required conditions
				
					Details
				
			 
				
	
				Build Release Packages / ${{ needs.setup.outputs.version }} / ${{ matrix.name }} (targz:grafana:darwin/arm64, darwin-arm64) (push) Blocked by required conditions
				
					Details
				
			 
				
	
				Build Release Packages / ${{ needs.setup.outputs.version }} / ${{ matrix.name }} (targz:grafana:linux/amd64,deb:grafana:linux/amd64,rpm:grafana:linux/amd64,docker:grafana:linux/amd64,docker:grafana:linux/amd64:ubuntu,npm:grafana,storybook, linux-amd64) (push) Blocked by required conditions
				
					Details
				
			 
				
	
				Build Release Packages / ${{ needs.setup.outputs.version }} / ${{ matrix.name }} (targz:grafana:linux/arm/v6,deb:grafana:linux/arm/v6, linux-armv6) (push) Blocked by required conditions
				
					Details
				
			 
				
	
				Build Release Packages / ${{ needs.setup.outputs.version }} / ${{ matrix.name }} (targz:grafana:linux/arm/v7,deb:grafana:linux/arm/v7,docker:grafana:linux/arm/v7,docker:grafana:linux/arm/v7:ubuntu, linux-armv7) (push) Blocked by required conditions
				
					Details
				
			 
				
	
				Build Release Packages / ${{ needs.setup.outputs.version }} / ${{ matrix.name }} (targz:grafana:linux/arm64,deb:grafana:linux/arm64,rpm:grafana:linux/arm64,docker:grafana:linux/arm64,docker:grafana:linux/arm64:ubuntu, linux-arm64) (push) Blocked by required conditions
				
					Details
				
			 
				
	
				Build Release Packages / ${{ needs.setup.outputs.version }} / ${{ matrix.name }} (targz:grafana:linux/s390x,deb:grafana:linux/s390x,rpm:grafana:linux/s390x,docker:grafana:linux/s390x,docker:grafana:linux/s390x:ubuntu, linux-s390x) (push) Blocked by required conditions
				
					Details
				
			 
				
	
				Build Release Packages / ${{ needs.setup.outputs.version }} / ${{ matrix.name }} (targz:grafana:windows/amd64,zip:grafana:windows/amd64,msi:grafana:windows/amd64, windows-amd64) (push) Blocked by required conditions
				
					Details
				
			 
				
	
				Build Release Packages / ${{ needs.setup.outputs.version }} / ${{ matrix.name }} (targz:grafana:windows/arm64,zip:grafana:windows/arm64, windows-arm64) (push) Blocked by required conditions
				
					Details
				
			 
				
	
				Build Release Packages / Upload artifacts (push) Blocked by required conditions
				
					Details
				
			 
				
	
				Run dashboard schema v2 e2e / dashboard-schema-v2-e2e (push) Waiting to run
				
					Details
				
			 
				
	
				Shellcheck / Shellcheck scripts (push) Waiting to run
				
					Details
				
			 
				
	
				Run Storybook a11y tests / Detect whether code changed (push) Waiting to run
				
					Details
				
			 
				
	
				Run Storybook a11y tests / Run Storybook a11y tests (push) Blocked by required conditions
				
					Details
				
			 
				
	
				Swagger generated code / Verify committed API specs match (push) Waiting to run
				
					Details
				
			 
				
	
				Dispatch sync to mirror / dispatch-job (push) Waiting to run
				
					Details
				
			 
				
	
				trigger-dashboard-search-e2e / trigger-search-e2e (push) Waiting to run
				
					Details
				
			 
				
	
				Trivy Scan / trivy-scan (push) Waiting to run
				
					Details
				
			 
				
	
				Verify Storybook (Playwright) / Verify Storybook (Playwright) (push) Has been cancelled
				
					Details
				
			 
				
	
				Verify Storybook / Verify Storybook (push) Has been cancelled
				
					Details
				
			 | ||
|---|---|---|
| .. | ||
| apis/aggregation | ||
| apiserver | ||
| examples | ||
| generated | ||
| registry/dataplaneservice | ||
| README.md | ||
| go.mod | ||
| go.sum | ||
| requestflow.png | ||
		
			
				
				README.md
			
		
		
			
			
		
	
	Data Plane Aggregator
The data plane aggregator is a reverse proxy similar to kube-aggregator that sits first in the request path. It is responsible for reverse proxying any registered data plane (anything that isn't CRUD + List + Watch) routes to the appropriate app handlers. Anything that does not match the registered data planeroutes will be delegated to the next apiserver in the handler chain (e.g. kube-aggregator). Currently the aggregator uses the Grafana plugin framework to register and proxy requests to Grafana plugins. The benefit of this approach is that it allows apps to be built, packaged, published, and deployed using the existing Grafana plugin framework.
Architecture
The data plane aggregator is built on top of the Kubernetes API server framework. It introduces a new DataPlaneService Custom Resource Definition (CRD) to dynamically register and proxy requests to Grafana plugins.
The main components are:
- GrafanaAggregator: The main server component, located in pkg/aggregator/apiserver/apiserver.go. It's responsible for:- Creating a generic API server.
- Registering the DataPlaneServiceresource.
- Running the DataPlaneServiceRegistrationController.
 
- DataPlaneServiceRegistrationController: This controller, located in pkg/aggregator/apiserver/dataplaneservice_controller.go, is responsible for:- Watching for add,update, anddeleteevents onDataPlaneServiceresources.
- Passing the DataPlaneServiceto thePluginHandlerto add, update, or remove the corresponding proxy handlers.
 
- Watching for 
- PluginHandler: This handler, located in pkg/aggregator/apiserver/plugin/handler.go, is responsible for:- Translating between the HTTP request/response and Grafana plugin request/response.
- Adding and removing HTTP handlers to proxy requests to plugins based on the registered DataPlaneServiceresources.
 
- DataPlaneService: Defined in pkg/aggregator/apis/aggregation/v0alpha1/types.go, this represents a service provided by a Grafana plugin.
The following diagram illustrates the request flow:
sequenceDiagram
    autonumber
    participant plugin as disk
    participant exe as plugin<br>binaries
    participant wrap as apiserver
    participant agg as kube-aggregator
    participant data as dataplane-aggregator
    participant storage as Unified<br>Storage
    Note over plugin,storage: Registration
    wrap->>plugin: Load Scope app manifest
    wrap->>agg: Create Scope APIService
    wrap->>plugin: Load SLO app manifest
    wrap->>agg: Create SLO APIService
    wrap->>plugin: Load Dashboard app manifest
    wrap->>agg: Create Dashboard APIService
    wrap->>data: Create Dashboard DataPlaneService
    Note over plugin,storage: Storage Access
    data->>storage: DataPlaneServices
    agg->>storage: APIServices
    wrap->>storage: Custom resources
    Note over plugin,storage: Create, Update, or Delete Hooks
    data->>agg: Local delegation to kube-aggregator
    agg->>wrap: HTTP reverse proxy incoming request
    wrap->>exe: gRPC admission mutation hook
    wrap->>exe: gRPC admission validation hook
    Note over plugin,storage: Get, List, or Watch Hooks
    data->>agg: Local delegation to kube-aggregator
    agg->>wrap: HTTP reverse proxy incoming request
    wrap->>exe: gRPC conversion hook
    Note over plugin,storage: Subresource & Custom Routes
    data->>exe: gRPC plugin resource calls
    data->>exe: gRPC plugin query data
    data->>exe: gRPC plugin stream
    data->>exe: gRPC plugin health
    data->>exe: gRPC plugin metrics
    Note over plugin,storage: Async (controllers)
    exe->>data: Watch
    data->>agg: Local delegation to kube-aggregator
    agg->>wrap: HTTP reverse proxy incoming request
    wrap->>storage: Watch
DataPlaneService
A DataPlaneService is a non-namespaced resource that represents a service exposed by a Grafana plugin. Here is an example:
apiVersion: aggregation.grafana.app/v0alpha1
kind: DataPlaneService
metadata:
  name: <plugin-id>
spec:
  pluginID: <plugin-id>
  pluginType: <plugin-type> # app or datasource
  group: <api-group>
  version: <api-version>
  services:
    - type: <service-type> # admission, conversion, query, stream, route, datasource-proxy
      method: <http-method>
      path: <url-path>
Query Example
- custom.inichanges:
[feature_toggles]
kubernetesAggregator = true
dataplaneAggregator = true
grafanaAPIServerEnsureKubectlAccess = true
- start grafana:
make run
- enable aggregation for prometheus data source:
export KUBECONFIG=./data/grafana-apiserver/grafana.kubeconfig
kubectl apply -f pkg/aggregator/examples/datasource.yml --validate=false
dataplaneservice.aggregation.grafana.app/v0alpha1.prometheus.grafana.app created
- 
edit pkg/aggregator/examples/datasource-query.jsonand update the datasource UID to match the UID of a prometheus data source.
- 
execute query (replace examplewith the UID of a prometheus data source):
curl 'http://admin:admin@localhost:3000/apis/prometheus.grafana.app/v0alpha1/namespaces/default/connections/example/query' -X POST -d '@pkg/aggregator/examples/datasource-query.json'
