Compare commits

..

2 Commits

Author SHA1 Message Date
Peter Štibraný
c7293f6fb5 Initial prototype extracting SearchServer from ResourceServer. 2025-12-16 09:41:56 +01:00
Peter Štibraný
584287dc61 Add support for LIST with filtering on selectable fields 2025-12-15 12:10:43 +01:00
634 changed files with 5998 additions and 34964 deletions

11
.github/CODEOWNERS vendored
View File

@@ -208,7 +208,7 @@
/pkg/tests/apis/shorturl @grafana/sharing-squad
/pkg/tests/api/correlations/ @grafana/datapro
/pkg/tsdb/grafanads/ @grafana/grafana-backend-group
/pkg/tsdb/opentsdb/ @grafana/oss-big-tent
/pkg/tsdb/opentsdb/ @grafana/partner-datasources
/pkg/util/ @grafana/grafana-backend-group
/pkg/web/ @grafana/grafana-backend-group
@@ -260,7 +260,7 @@
/devenv/dev-dashboards/dashboards.go @grafana/dataviz-squad
/devenv/dev-dashboards/home.json @grafana/dataviz-squad
/devenv/dev-dashboards/datasource-elasticsearch/ @grafana/partner-datasources
/devenv/dev-dashboards/datasource-opentsdb/ @grafana/oss-big-tent
/devenv/dev-dashboards/datasource-opentsdb/ @grafana/partner-datasources
/devenv/dev-dashboards/datasource-influxdb/ @grafana/partner-datasources
/devenv/dev-dashboards/datasource-mssql/ @grafana/partner-datasources
/devenv/dev-dashboards/datasource-loki/ @grafana/plugins-platform-frontend
@@ -307,7 +307,7 @@
/devenv/docker/blocks/mysql_exporter/ @grafana/oss-big-tent
/devenv/docker/blocks/mysql_opendata/ @grafana/oss-big-tent
/devenv/docker/blocks/mysql_tests/ @grafana/oss-big-tent
/devenv/docker/blocks/opentsdb/ @grafana/oss-big-tent
/devenv/docker/blocks/opentsdb/ @grafana/partner-datasources
/devenv/docker/blocks/postgres/ @grafana/oss-big-tent
/devenv/docker/blocks/postgres_tests/ @grafana/oss-big-tent
/devenv/docker/blocks/prometheus/ @grafana/oss-big-tent
@@ -520,7 +520,7 @@ i18next.config.ts @grafana/grafana-frontend-platform
/e2e-playwright/various-suite/solo-route.spec.ts @grafana/dashboards-squad
/e2e-playwright/various-suite/trace-view-scrolling.spec.ts @grafana/observability-traces-and-profiling
/e2e-playwright/various-suite/verify-i18n.spec.ts @grafana/grafana-frontend-platform
/e2e-playwright/various-suite/visualization-suggestions.spec.ts @grafana/dataviz-squad
/e2e-playwright/various-suite/visualization-suggestions.spec.ts @grafana/dashboards-squad
/e2e-playwright/various-suite/perf-test.spec.ts @grafana/grafana-frontend-platform
# Packages
@@ -956,7 +956,6 @@ playwright.storybook.config.ts @grafana/grafana-frontend-platform
/public/app/features/notifications/ @grafana/grafana-search-navigate-organise
/public/app/features/org/ @grafana/grafana-search-navigate-organise
/public/app/features/panel/ @grafana/dashboards-squad
/public/app/features/panel/components/VizTypePicker/VisualizationSuggestions.tsx @grafana/dataviz-squad
/public/app/features/panel/suggestions/ @grafana/dataviz-squad
/public/app/features/playlist/ @grafana/dashboards-squad
/public/app/features/plugins/ @grafana/plugins-platform-frontend
@@ -1101,7 +1100,7 @@ eslint-suppressions.json @grafanabot
/public/app/plugins/datasource/mixed/ @grafana/dashboards-squad
/public/app/plugins/datasource/mssql/ @grafana/partner-datasources
/public/app/plugins/datasource/mysql/ @grafana/oss-big-tent
/public/app/plugins/datasource/opentsdb/ @grafana/oss-big-tent
/public/app/plugins/datasource/opentsdb/ @grafana/partner-datasources
/public/app/plugins/datasource/grafana-postgresql-datasource/ @grafana/oss-big-tent
/public/app/plugins/datasource/prometheus/ @grafana/oss-big-tent
/public/app/plugins/datasource/cloud-monitoring/ @grafana/partner-datasources

View File

@@ -12,7 +12,6 @@ on:
permissions:
id-token: write
contents: read
statuses: write
# Since this is run on a pull request, we want to apply the patches intended for the
# target branch onto the source branch, to verify compatibility before merging.

View File

@@ -29,10 +29,6 @@ permissions:
# target branch onto the source branch, to verify compatibility before merging.
jobs:
dispatch-job:
# If the source is not from a fork then dispatch the job to the workflow.
# This will fail on forks when trying to broker a token, so instead, forks will create the required status and mark
# it as a success
if: ${{ ! github.event.pull_request.head.repo.fork }}
env:
HEAD_REF: ${{ inputs.head_ref }}
BASE_REF: ${{ github.base_ref }}
@@ -80,20 +76,3 @@ jobs:
triggering_github_handle: SENDER
}
})
dispatch-job-fork:
# If the source is from a fork then use the built-in workflow token to create the same status and unconditionally
# mark it as a success.
if: ${{ github.event.pull_request.head.repo.fork }}
permissions:
statuses: write
runs-on: ubuntu-latest
steps:
- name: Create status
uses: myrotvorets/set-commit-status-action@6d6905c99cd24a4a2cbccc720b62dc6ca5587141
with:
token: ${{ github.token }}
sha: ${{ inputs.pr_commit_sha }}
repo: ${{ inputs.repo }}
status: success
context: "Test Patches (event)"
description: "Test Patches (event) on a fork"

View File

@@ -111,13 +111,12 @@ jobs:
ownerRepo: 'grafana/grafana-enterprise'
from: ${{ needs.setup.outputs.release_branch }}
to: ${{ needs.create_next_release_branch_enterprise.outputs.branch }}
# Removed this for now since it doesn't work
# post_changelog_on_forum:
# needs: setup
# uses: grafana/grafana/.github/workflows/community-release.yml@main
# with:
# version: ${{ needs.setup.outputs.version }}
# dry_run: ${{ needs.setup.outputs.dry_run == 'true' }}
post_changelog_on_forum:
needs: setup
uses: grafana/grafana/.github/workflows/community-release.yml@main
with:
version: ${{ needs.setup.outputs.version }}
dry_run: ${{ needs.setup.outputs.dry_run == 'true' }}
create_github_release:
# a github release requires a git tag
# The github-release action retrieves the changelog using the /repos/grafana/grafana/contents/CHANGELOG.md API

3
.gitignore vendored
View File

@@ -262,6 +262,3 @@ public/mockServiceWorker.js
# Ignore grafana/hippocampus local cache folder
.hippo
# Claude Code session notes
[Cc]laude.[Mm][Dd]

View File

@@ -3,7 +3,7 @@
# Others can set up the YAML LSP manually, which supports schemas: https://github.com/redhat-developer/yaml-language-server
# $schema: https://golangci-lint.run/jsonschema/golangci.jsonschema.json
version: '2'
version: "2"
run:
timeout: 15m
concurrency: 10
@@ -83,16 +83,6 @@ linters:
deny:
- pkg: github.com/grafana/grafana/pkg
desc: apps/playlist is not allowed to import grafana core
apps-dashboard:
list-mode: lax
files:
- ./apps/dashboard/*
- ./apps/dashboard/**/*
allow:
- github.com/grafana/grafana/pkg/apimachinery
deny:
- pkg: github.com/grafana/grafana/pkg
desc: apps/dashboard is not allowed to import grafana core
apps-secret:
list-mode: lax
files:
@@ -291,16 +281,16 @@ linters:
text: G306
- linters:
- gosec
text: '401'
text: "401"
- linters:
- gosec
text: '402'
text: "402"
- linters:
- gosec
text: '501'
text: "501"
- linters:
- gosec
text: '404'
text: "404"
- linters:
- errorlint
text: non-wrapping format verb for fmt.Errorf

View File

@@ -15,7 +15,6 @@ require (
github.com/stretchr/testify v1.11.1
k8s.io/apimachinery v0.34.2
k8s.io/apiserver v0.34.2
k8s.io/client-go v0.34.2
k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912
)
@@ -44,7 +43,6 @@ replace github.com/grafana/grafana/apps/plugins => ../plugins
replace github.com/prometheus/alertmanager => github.com/grafana/prometheus-alertmanager v0.25.1-0.20250911094103-5456b6e45604
require (
cel.dev/expr v0.24.0 // indirect
cloud.google.com/go/compute/metadata v0.9.0 // indirect
dario.cat/mergo v1.0.2 // indirect
filippo.io/edwards25519 v1.1.0 // indirect
@@ -57,7 +55,6 @@ require (
github.com/Masterminds/goutils v1.1.1 // indirect
github.com/Masterminds/semver v1.5.0 // indirect
github.com/Masterminds/sprig/v3 v3.3.0 // indirect
github.com/NYTimes/gziphandler v1.1.1 // indirect
github.com/ProtonMail/go-crypto v1.1.6 // indirect
github.com/VividCortex/mysqlerr v0.0.0-20170204212430-6c6b55f8796f // indirect
github.com/alecthomas/units v0.0.0-20240927000941-0f3dac36c52b // indirect
@@ -88,7 +85,6 @@ require (
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/cheekybits/genny v1.0.0 // indirect
github.com/cloudflare/circl v1.6.1 // indirect
github.com/coreos/go-semver v0.3.1 // indirect
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
@@ -105,7 +101,6 @@ require (
github.com/evanphx/json-patch v5.9.11+incompatible // indirect
github.com/fatih/color v1.18.0 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/fsnotify/fsnotify v1.9.0 // indirect
github.com/fxamacker/cbor/v2 v2.9.0 // indirect
github.com/gchaincl/sqlhooks v1.3.0 // indirect
github.com/getkin/kin-openapi v0.133.0 // indirect
@@ -149,13 +144,12 @@ require (
github.com/golang-migrate/migrate/v4 v4.7.0 // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/google/btree v1.1.3 // indirect
github.com/google/cel-go v0.26.1 // indirect
github.com/google/flatbuffers v25.2.10+incompatible // indirect
github.com/google/gnostic-models v0.7.0 // indirect
github.com/google/go-querystring v1.1.0 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/google/wire v0.7.0 // indirect
github.com/grafana/alerting v0.0.0-20251212143239-491433b332b7 // indirect
github.com/grafana/alerting v0.0.0-20251204145817-de8c2bbf9eba // indirect
github.com/grafana/authlib v0.0.0-20250930082137-a40e2c2b094f // indirect
github.com/grafana/dataplane/sdata v0.0.9 // indirect
github.com/grafana/dskit v0.0.0-20250908063411-6b6da59b5cc4 // indirect
@@ -168,7 +162,6 @@ require (
github.com/grafana/sqlds/v4 v4.2.7 // indirect
github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.1.0 // indirect
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.3 // indirect
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.1-0.20191002090509-6af20e3a5340 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-hclog v1.6.3 // indirect
@@ -183,7 +176,6 @@ require (
github.com/hashicorp/memberlist v0.5.2 // indirect
github.com/hashicorp/yamux v0.1.2 // indirect
github.com/huandu/xstrings v1.5.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jaegertracing/jaeger-idl v0.5.0 // indirect
github.com/jessevdk/go-flags v1.6.1 // indirect
github.com/jmespath-community/go-jmespath v1.1.1 // indirect
@@ -256,9 +248,7 @@ require (
github.com/shurcooL/vfsgen v0.0.0-20230704071429-0000e147ea92 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
github.com/spf13/cast v1.10.0 // indirect
github.com/spf13/cobra v1.10.1 // indirect
github.com/spf13/pflag v1.0.10 // indirect
github.com/stoewer/go-strcase v1.3.1 // indirect
github.com/stretchr/objx v0.5.2 // indirect
github.com/tetratelabs/wazero v1.8.2 // indirect
github.com/thomaspoignant/go-feature-flag v1.42.0 // indirect
@@ -266,9 +256,6 @@ require (
github.com/woodsbury/decimal128 v1.3.0 // indirect
github.com/x448/float16 v0.8.4 // indirect
github.com/zeebo/xxh3 v1.0.2 // indirect
go.etcd.io/etcd/api/v3 v3.6.4 // indirect
go.etcd.io/etcd/client/pkg/v3 v3.6.4 // indirect
go.etcd.io/etcd/client/v3 v3.6.4 // indirect
go.mongodb.org/mongo-driver v1.17.4 // indirect
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0 // indirect
@@ -287,8 +274,6 @@ require (
go.opentelemetry.io/proto/otlp v1.9.0 // indirect
go.uber.org/atomic v1.11.0 // indirect
go.uber.org/mock v0.6.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.27.1 // indirect
go.yaml.in/yaml/v2 v2.4.3 // indirect
go.yaml.in/yaml/v3 v3.0.4 // indirect
golang.org/x/crypto v0.45.0 // indirect
@@ -312,26 +297,23 @@ require (
google.golang.org/grpc v1.77.0 // indirect
google.golang.org/protobuf v1.36.10 // indirect
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/mail.v2 v2.3.1 // indirect
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
gopkg.in/src-d/go-errors.v1 v1.0.0 // indirect
gopkg.in/telebot.v3 v3.3.8 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/api v0.34.2 // indirect
k8s.io/apiextensions-apiserver v0.34.2 // indirect
k8s.io/client-go v0.34.2 // indirect
k8s.io/component-base v0.34.2 // indirect
k8s.io/klog/v2 v2.130.1 // indirect
k8s.io/kms v0.34.2 // indirect
k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 // indirect
modernc.org/libc v1.66.10 // indirect
modernc.org/mathutil v1.7.1 // indirect
modernc.org/memory v1.11.0 // indirect
modernc.org/sqlite v1.40.1 // indirect
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2 // indirect
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect
sigs.k8s.io/randfill v1.0.0 // indirect
sigs.k8s.io/structured-merge-diff/v6 v6.3.1 // indirect

View File

@@ -282,7 +282,6 @@ github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03V
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/cznic/b v0.0.0-20180115125044-35e9bbe41f07/go.mod h1:URriBxXwVq5ijiJ12C7iIZqlA69nTlI+LgI6/pwftG8=
github.com/cznic/fileutil v0.0.0-20180108211300-6a051e75936f/go.mod h1:8S58EK26zhXSxzv7NQFpnliaOQsmDUxvoQO3rt154Vg=
@@ -407,8 +406,6 @@ github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ=
github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg=
github.com/go-openapi/analysis v0.24.0 h1:vE/VFFkICKyYuTWYnplQ+aVr45vlG6NcZKC7BdIXhsA=
github.com/go-openapi/analysis v0.24.0/go.mod h1:GLyoJA+bvmGGaHgpfeDh8ldpGo69fAJg7eeMDMRCIrw=
github.com/go-openapi/errors v0.22.3 h1:k6Hxa5Jg1TUyZnOwV2Lh81j8ayNw5VVYLvKrp4zFKFs=
@@ -609,10 +606,8 @@ github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2z
github.com/gorilla/mux v1.7.1/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 h1:JeSE6pjso5THxAzdVpqr6/geYxZytqFMBCOtn/ujyeo=
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674/go.mod h1:r4w70xmWCQKmi1ONH4KIaBptdivuRPyosB9RmPlGEwA=
github.com/grafana/alerting v0.0.0-20251212143239-491433b332b7 h1:ZzG/gCclEit9w0QUfQt9GURcOycAIGcsQAhY1u0AEX0=
github.com/grafana/alerting v0.0.0-20251212143239-491433b332b7/go.mod h1:l7v67cgP7x72ajB9UPZlumdrHqNztpKoqQ52cU8T3LU=
github.com/grafana/alerting v0.0.0-20251204145817-de8c2bbf9eba h1:psKWNETD5nGxmFAlqnWsXoRyUwSa2GHNEMSEDKGKfQ4=
github.com/grafana/alerting v0.0.0-20251204145817-de8c2bbf9eba/go.mod h1:l7v67cgP7x72ajB9UPZlumdrHqNztpKoqQ52cU8T3LU=
github.com/grafana/authlib v0.0.0-20250930082137-a40e2c2b094f h1:Cbm6OKkOcJ+7CSZsGsEJzktC/SIa5bxVeYKQLuYK86o=
github.com/grafana/authlib v0.0.0-20250930082137-a40e2c2b094f/go.mod h1:axY0cdOg3q0TZHwpHnIz5x16xZ8ZBxJHShsSHHXcHQg=
github.com/grafana/authlib/types v0.0.0-20251119142549-be091cf2f4d4 h1:Muoy+FMGrHj3GdFbvsMzUT7eusgii9PKf9L1ZaXDDbY=
@@ -754,8 +749,6 @@ github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGw
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
github.com/jmoiron/sqlx v1.4.0 h1:1PLqN7S1UYp5t4SrVVnt4nUVNemrDAtxlulVe+Qgm3o=
github.com/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT4JLY=
github.com/jonboulle/clockwork v0.5.0 h1:Hyh9A8u51kptdkR+cqRpT1EebBwTn1oK9YfGYbdFz6I=
github.com/jonboulle/clockwork v0.5.0/go.mod h1:3mZlmanh0g2NDKO5TWZVJAfofYk64M7XN3SzBPjZF60=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA=
@@ -986,7 +979,6 @@ github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSg
github.com/pressly/goose/v3 v3.26.0 h1:KJakav68jdH0WDvoAcj8+n61WqOIaPGgH0bJWS6jpmM=
github.com/pressly/goose/v3 v3.26.0/go.mod h1:4hC1KrritdCxtuFsqgs1R4AU5bWtTAf+cnWvfhf2DNY=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM=
github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og=
@@ -1004,7 +996,6 @@ github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6T
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA=
@@ -1019,7 +1010,6 @@ github.com/prometheus/common/sigv4 v0.1.0/go.mod h1:2Jkxxk9yYvCkE5G1sQT7GuEXm57J
github.com/prometheus/exporter-toolkit v0.14.0 h1:NMlswfibpcZZ+H0sZBiTjrA3/aBFHkNZqE+iCj5EmRg=
github.com/prometheus/exporter-toolkit v0.14.0/go.mod h1:Gu5LnVvt7Nr/oqTBUC23WILZepW0nffNo10XdhQcwWA=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
@@ -1046,7 +1036,6 @@ github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0t
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
github.com/rs/cors v1.11.1 h1:eU3gRzXLRK57F5rKMGMZURNdIG4EoAmX8k94r9wXWHA=
github.com/rs/cors v1.11.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/sagikazarmark/crypt v0.6.0/go.mod h1:U8+INwJo3nBv1m6A/8OBXAq7Jnpspk5AxSgDyEQcea8=
github.com/sagikazarmark/locafero v0.11.0 h1:1iurJgmM9G3PA/I+wWYIOw/5SyBtxapeHDcg+AAIFXc=
@@ -1069,8 +1058,6 @@ github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6Mwd
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/soheilhy/cmux v0.1.5 h1:jjzc5WVemNEDTLwv9tlmemhC73tI08BNOIGwBOo10Js=
github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0=
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 h1:+jumHNA0Wrelhe64i8F6HNlS8pkoyMv5sreGx2Ry5Rw=
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8/go.mod h1:3n1Cwaq1E1/1lhQhtRK2ts/ZwZEhjcQeJQ1RuC6Q/8U=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
@@ -1084,7 +1071,6 @@ github.com/spf13/cobra v1.10.1 h1:lJeBwCfmrnXthfAupyUTzJ/J4Nc1RsHC/mSRU2dll/s=
github.com/spf13/cobra v1.10.1/go.mod h1:7SmJGaTHFVBY0jW4NXGluQoLvhqFQM+6XSKD+P4XaB0=
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.13.0/go.mod h1:Icm2xNL3/8uyh/wFuB1jI7TiTNKp8632Nwegu+zgdYw=
@@ -1110,7 +1096,6 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
github.com/stretchr/testify v1.7.5/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
@@ -1127,8 +1112,6 @@ github.com/thomaspoignant/go-feature-flag v1.42.0/go.mod h1:y0QiWH7chHWhGATb/+Xq
github.com/tidwall/pretty v0.0.0-20180105212114-65a9db5fad51/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
github.com/tjhop/slog-gokit v0.1.5 h1:ayloIUi5EK2QYB8eY4DOPO95/mRtMW42lUkp3quJohc=
github.com/tjhop/slog-gokit v0.1.5/go.mod h1:yA48zAHvV+Sg4z4VRyeFyFUNNXd3JY5Zg84u3USICq0=
github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75 h1:6fotK7otjonDflCTK0BCfls4SPy3NcCVb5dqqmbRknE=
github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75/go.mod h1:KO6IkyS8Y3j8OdNO85qEYBsRPuteD+YciPomcXdrMnk=
github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
github.com/uber/jaeger-client-go v2.30.0+incompatible h1:D6wyKGCecFaSRUpo8lCVbaOOb6ThwMmTEbhRwtKR97o=
github.com/uber/jaeger-client-go v2.30.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk=
@@ -1146,8 +1129,6 @@ github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcY
github.com/xanzy/go-gitlab v0.15.0/go.mod h1:8zdQa/ri1dfn8eS3Ir1SyfvOKlw7WBJ8DVThkpGiXrs=
github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I=
github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y=
github.com/xiang90/probing v0.0.0-20221125231312-a49e3df8f510 h1:S2dVYn90KE98chqDkyE9Z4N61UnQd+KOfgp5Iu53llk=
github.com/xiang90/probing v0.0.0-20221125231312-a49e3df8f510/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
@@ -1158,8 +1139,6 @@ github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN
github.com/zeebo/xxh3 v1.0.2 h1:xZmwmqxHZA8AI603jOQ0tMqmBr9lPeFwGg6d+xy9DC0=
github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA=
gitlab.com/nyarla/go-crypt v0.0.0-20160106005555-d9a5dc2b789b/go.mod h1:T3BPAOm2cqquPa0MKWeNkmOM5RQsRhkrwMWonFMN7fE=
go.etcd.io/bbolt v1.4.2 h1:IrUHp260R8c+zYx/Tm8QZr04CX+qWS5PGfPdevhdm1I=
go.etcd.io/bbolt v1.4.2/go.mod h1:Is8rSHO/b4f3XigBC0lL0+4FwAQv3HXEEIgFMuKHceM=
go.etcd.io/etcd/api/v3 v3.5.4/go.mod h1:5GB2vv4A4AOn3yk7MftYGHkUfGtDHnEraIjym4dYz5A=
go.etcd.io/etcd/api/v3 v3.6.4 h1:7F6N7toCKcV72QmoUKa23yYLiiljMrT4xCeBL9BmXdo=
go.etcd.io/etcd/api/v3 v3.6.4/go.mod h1:eFhhvfR8Px1P6SEuLT600v+vrhdDTdcfMzmnxVXXSbk=
@@ -1170,12 +1149,6 @@ go.etcd.io/etcd/client/v2 v2.305.4/go.mod h1:Ud+VUwIi9/uQHOMA+4ekToJ12lTxlv0zB/+
go.etcd.io/etcd/client/v3 v3.5.4/go.mod h1:ZaRkVgBZC+L+dLCjTcF1hRXpgZXQPOvnA/Ak/gq3kiY=
go.etcd.io/etcd/client/v3 v3.6.4 h1:YOMrCfMhRzY8NgtzUsHl8hC2EBSnuqbR3dh84Uryl7A=
go.etcd.io/etcd/client/v3 v3.6.4/go.mod h1:jaNNHCyg2FdALyKWnd7hxZXZxZANb0+KGY+YQaEMISo=
go.etcd.io/etcd/pkg/v3 v3.6.4 h1:fy8bmXIec1Q35/jRZ0KOes8vuFxbvdN0aAFqmEfJZWA=
go.etcd.io/etcd/pkg/v3 v3.6.4/go.mod h1:kKcYWP8gHuBRcteyv6MXWSN0+bVMnfgqiHueIZnKMtE=
go.etcd.io/etcd/server/v3 v3.6.4 h1:LsCA7CzjVt+8WGrdsnh6RhC0XqCsLkBly3ve5rTxMAU=
go.etcd.io/etcd/server/v3 v3.6.4/go.mod h1:aYCL/h43yiONOv0QIR82kH/2xZ7m+IWYjzRmyQfnCAg=
go.etcd.io/raft/v3 v3.6.0 h1:5NtvbDVYpnfZWcIHgGRk9DyzkBIXOi8j+DDp1IcnUWQ=
go.etcd.io/raft/v3 v3.6.0/go.mod h1:nLvLevg6+xrVtHUmVaTcTz603gQPHfh7kUAwV6YpfGo=
go.mongodb.org/mongo-driver v1.1.0/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
go.mongodb.org/mongo-driver v1.17.4 h1:jUorfmVzljjr0FLzYQsGP8cgN/qzzxlY9Vh0C9KFXVw=
go.mongodb.org/mongo-driver v1.17.4/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ=
@@ -1328,7 +1301,6 @@ golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73r
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181108082009-03003ca0c849/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -1740,7 +1712,6 @@ google.golang.org/genproto/googleapis/api v0.0.0-20251111163417-95abcf5c77ba/go.
google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba h1:UKgtfRM7Yh93Sya0Fo8ZzhDP4qBckrrxEr2oF5UIVb8=
google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk=
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
google.golang.org/grpc v1.18.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=

View File

@@ -8,24 +8,18 @@ import (
"github.com/grafana/grafana-app-sdk/app"
"github.com/grafana/grafana-app-sdk/k8s"
appsdkapiserver "github.com/grafana/grafana-app-sdk/k8s/apiserver"
"github.com/grafana/grafana-app-sdk/logging"
"github.com/grafana/grafana-app-sdk/operator"
"github.com/grafana/grafana-app-sdk/resource"
"github.com/grafana/grafana-app-sdk/simple"
advisorapi "github.com/grafana/grafana/apps/advisor/pkg/apis"
advisorv0alpha1 "github.com/grafana/grafana/apps/advisor/pkg/apis/advisor/v0alpha1"
"github.com/grafana/grafana/apps/advisor/pkg/app/checkregistry"
"github.com/grafana/grafana/apps/advisor/pkg/app/checks"
"github.com/grafana/grafana/apps/advisor/pkg/app/checkscheduler"
"github.com/grafana/grafana/apps/advisor/pkg/app/checktyperegisterer"
"github.com/grafana/grafana/pkg/apimachinery/identity"
"github.com/grafana/grafana/pkg/services/org"
"github.com/grafana/grafana/pkg/setting"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apiserver/pkg/authorization/authorizer"
"k8s.io/client-go/rest"
)
func New(cfg app.Config) (app.App, error) {
@@ -194,45 +188,3 @@ func GetKinds() map[schema.GroupVersion][]resource.Kind {
},
}
}
func ProvideAppInstaller(
authorizer authorizer.Authorizer,
checkRegistry checkregistry.CheckService,
cfg *setting.Cfg,
orgService org.Service,
) (*AdvisorAppInstaller, error) {
provider := simple.NewAppProvider(advisorapi.LocalManifest(), nil, New)
pluginConfig := cfg.PluginSettings["grafana-advisor-app"]
specificConfig := checkregistry.AdvisorAppConfig{
CheckRegistry: checkRegistry,
PluginConfig: pluginConfig,
StackID: cfg.StackID,
OrgService: orgService,
}
appCfg := app.Config{
KubeConfig: rest.Config{},
ManifestData: *advisorapi.LocalManifest().ManifestData,
SpecificConfig: specificConfig,
}
defaultInstaller, err := appsdkapiserver.NewDefaultAppInstaller(provider, appCfg, advisorapi.NewGoTypeAssociator())
if err != nil {
return nil, err
}
installer := &AdvisorAppInstaller{
AppInstaller: defaultInstaller,
authorizer: authorizer,
}
return installer, nil
}
type AdvisorAppInstaller struct {
appsdkapiserver.AppInstaller
authorizer authorizer.Authorizer
}
func (a *AdvisorAppInstaller) GetAuthorizer() authorizer.Authorizer {
return a.authorizer
}

View File

@@ -0,0 +1,47 @@
package app
import (
"context"
claims "github.com/grafana/authlib/types"
"github.com/grafana/grafana/pkg/apimachinery/identity"
"k8s.io/apiserver/pkg/authorization/authorizer"
)
func GetAuthorizer() authorizer.Authorizer {
return authorizer.AuthorizerFunc(func(
ctx context.Context, attr authorizer.Attributes,
) (authorized authorizer.Decision, reason string, err error) {
if !attr.IsResourceRequest() {
return authorizer.DecisionNoOpinion, "", nil
}
// Check for service identity
if identity.IsServiceIdentity(ctx) {
return authorizer.DecisionAllow, "", nil
}
// Check for access policy identity
info, ok := claims.AuthInfoFrom(ctx)
if ok && claims.IsIdentityType(info.GetIdentityType(), claims.TypeAccessPolicy) {
// For access policy identities, we need to use ResourceAuthorizer
// This requires an AccessClient, which should be provided by the API server
// For now, we'll use the default ResourceAuthorizer from the API server
// This will be set up by the API server's authorization chain
return authorizer.DecisionNoOpinion, "", nil
}
// For regular Grafana users, check if they are admin
u, err := identity.GetRequester(ctx)
if err != nil {
return authorizer.DecisionDeny, "valid user is required", err
}
// check if is admin
if u.HasRole(identity.RoleAdmin) {
return authorizer.DecisionAllow, "", nil
}
return authorizer.DecisionDeny, "forbidden", nil
})
}

View File

@@ -0,0 +1,91 @@
package app
import (
"context"
"testing"
claims "github.com/grafana/authlib/types"
"github.com/grafana/grafana/pkg/apimachinery/identity"
"github.com/stretchr/testify/assert"
"k8s.io/apiserver/pkg/authorization/authorizer"
)
func TestGetAuthorizer(t *testing.T) {
tests := []struct {
name string
ctx context.Context
attr authorizer.Attributes
expectedDecision authorizer.Decision
expectedReason string
expectedErr error
}{
{
name: "non-resource request",
ctx: context.TODO(),
attr: &mockAttributes{resourceRequest: false},
expectedDecision: authorizer.DecisionNoOpinion,
expectedReason: "",
expectedErr: nil,
},
{
name: "user is admin",
ctx: identity.WithRequester(context.TODO(), &mockUser{isGrafanaAdmin: true}),
attr: &mockAttributes{resourceRequest: true},
expectedDecision: authorizer.DecisionAllow,
expectedReason: "",
expectedErr: nil,
},
{
name: "user is not admin",
ctx: identity.WithRequester(context.TODO(), &mockUser{isGrafanaAdmin: false}),
attr: &mockAttributes{resourceRequest: true},
expectedDecision: authorizer.DecisionDeny,
expectedReason: "forbidden",
expectedErr: nil,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
auth := GetAuthorizer()
decision, reason, err := auth.Authorize(tt.ctx, tt.attr)
assert.Equal(t, tt.expectedDecision, decision)
assert.Equal(t, tt.expectedReason, reason)
assert.Equal(t, tt.expectedErr, err)
})
}
}
type mockAttributes struct {
authorizer.Attributes
resourceRequest bool
}
func (m *mockAttributes) IsResourceRequest() bool {
return m.resourceRequest
}
// Implement other methods of authorizer.Attributes as needed
type mockUser struct {
identity.Requester
isGrafanaAdmin bool
}
func (m *mockUser) GetIsGrafanaAdmin() bool {
return m.isGrafanaAdmin
}
func (m *mockUser) HasRole(role identity.RoleType) bool {
return role == identity.RoleAdmin && m.isGrafanaAdmin
}
func (m *mockUser) GetUID() string {
return "test-uid"
}
func (m *mockUser) GetIdentityType() claims.IdentityType {
return claims.TypeUser
}
// Implement other methods of identity.Requester as needed

View File

@@ -4,7 +4,7 @@ go 1.25.5
require (
github.com/go-kit/log v0.2.1
github.com/grafana/alerting v0.0.0-20251212143239-491433b332b7
github.com/grafana/alerting v0.0.0-20251204145817-de8c2bbf9eba
github.com/grafana/dskit v0.0.0-20250908063411-6b6da59b5cc4
github.com/grafana/grafana-app-sdk v0.48.5
github.com/grafana/grafana-app-sdk/logging v0.48.3

View File

@@ -216,10 +216,12 @@ github.com/google/pprof v0.0.0-20250403155104-27863c87afa6/go.mod h1:boTsfXsheKC
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/grafana/grafana-app-sdk v0.48.5 h1:MS8l9fTZz+VbTfgApn09jw27GxhQ6fNOWGhC4ydvZmM=
github.com/grafana/grafana-app-sdk v0.48.5/go.mod h1:HJsMOSBmt/D/Ihs1SvagOwmXKi0coBMVHlfvdd+qe9Y=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/grafana/alerting v0.0.0-20251212143239-491433b332b7 h1:ZzG/gCclEit9w0QUfQt9GURcOycAIGcsQAhY1u0AEX0=
github.com/grafana/alerting v0.0.0-20251212143239-491433b332b7/go.mod h1:l7v67cgP7x72ajB9UPZlumdrHqNztpKoqQ52cU8T3LU=
github.com/grafana/alerting v0.0.0-20251204145817-de8c2bbf9eba h1:psKWNETD5nGxmFAlqnWsXoRyUwSa2GHNEMSEDKGKfQ4=
github.com/grafana/alerting v0.0.0-20251204145817-de8c2bbf9eba/go.mod h1:l7v67cgP7x72ajB9UPZlumdrHqNztpKoqQ52cU8T3LU=
github.com/grafana/dskit v0.0.0-20250908063411-6b6da59b5cc4 h1:jSojuc7njleS3UOz223WDlXOinmuLAIPI0z2vtq8EgI=
github.com/grafana/dskit v0.0.0-20250908063411-6b6da59b5cc4/go.mod h1:VahT+GtfQIM+o8ht2StR6J9g+Ef+C2Vokh5uuSmOD/4=
github.com/grafana/grafana-app-sdk v0.48.5 h1:MS8l9fTZz+VbTfgApn09jw27GxhQ6fNOWGhC4ydvZmM=

View File

@@ -9,7 +9,6 @@ require (
github.com/grafana/grafana-app-sdk/logging v0.48.3
github.com/grafana/grafana-plugin-sdk-go v0.284.0
github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250514132646-acbc7b54ed9e
github.com/hashicorp/golang-lru/v2 v2.0.7
github.com/prometheus/client_golang v1.23.2
github.com/stretchr/testify v1.11.1
k8s.io/apimachinery v0.34.2
@@ -58,6 +57,7 @@ require (
github.com/hashicorp/go-hclog v1.6.3 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/hashicorp/go-plugin v1.7.0 // indirect
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
github.com/hashicorp/yamux v0.1.2 // indirect
github.com/jaegertracing/jaeger-idl v0.5.0 // indirect
github.com/josharian/intern v1.0.0 // indirect

View File

@@ -1,603 +0,0 @@
{
"kind": "DashboardWithAccessInfo",
"apiVersion": "dashboard.grafana.app/v1beta1",
"metadata": {
"name": "value-mapping-test",
"namespace": "default",
"uid": "value-mapping-test",
"resourceVersion": "1765384157199094",
"generation": 2,
"creationTimestamp": "2025-11-19T20:09:28Z",
"labels": {
"grafana.app/deprecatedInternalID": "646372978987008"
},
"annotations": {},
"managedFields": []
},
"spec": {
"annotations": {
"list": [
{
"builtIn": 1,
"datasource": {
"type": "grafana",
"uid": "-- Grafana --"
},
"enable": true,
"hide": true,
"iconColor": "rgba(0, 211, 255, 1)",
"name": "Annotations & Alerts",
"type": "dashboard"
}
]
},
"description": "Test dashboard for all value mapping types and override matcher types",
"editable": true,
"fiscalYearStartMonth": 0,
"graphTooltip": 0,
"links": [],
"panels": [
{
"datasource": {
"type": "prometheus",
"uid": "prometheus-uid"
},
"description": "Panel with ValueMap mapping type - maps specific text values to colors and display text",
"fieldConfig": {
"defaults": {
"mappings": [
{
"options": {
"critical": {
"color": "red",
"index": 0,
"text": "Critical!"
},
"warning": {
"color": "orange",
"index": 1,
"text": "Warning"
},
"ok": {
"color": "green",
"index": 2,
"text": "OK"
}
},
"type": "value"
}
]
},
"overrides": [
{
"matcher": {
"id": "byName",
"options": "status"
},
"properties": [
{
"id": "custom.width",
"value": 100
},
{
"id": "custom.align",
"value": "center"
}
]
}
]
},
"gridPos": {
"h": 8,
"w": 12,
"x": 0,
"y": 0
},
"id": 1,
"targets": [
{
"expr": "up",
"refId": "A"
}
],
"title": "ValueMap Example",
"type": "stat"
},
{
"datasource": {
"type": "prometheus",
"uid": "prometheus-uid"
},
"description": "Panel with RangeMap mapping type - maps numerical ranges to colors and display text",
"fieldConfig": {
"defaults": {
"mappings": [
{
"options": {
"from": 0,
"to": 50,
"result": {
"color": "green",
"index": 0,
"text": "Low"
}
},
"type": "range"
},
{
"options": {
"from": 50,
"to": 80,
"result": {
"color": "orange",
"index": 1,
"text": "Medium"
}
},
"type": "range"
},
{
"options": {
"from": 80,
"to": 100,
"result": {
"color": "red",
"index": 2,
"text": "High"
}
},
"type": "range"
}
]
},
"overrides": [
{
"matcher": {
"id": "byRegexp",
"options": "/^cpu_/"
},
"properties": [
{
"id": "unit",
"value": "percent"
},
{
"id": "decimals",
"value": 2
}
]
}
]
},
"gridPos": {
"h": 8,
"w": 12,
"x": 12,
"y": 0
},
"id": 2,
"targets": [
{
"expr": "cpu_usage_percent",
"refId": "A"
}
],
"title": "RangeMap Example",
"type": "gauge"
},
{
"datasource": {
"type": "prometheus",
"uid": "prometheus-uid"
},
"description": "Panel with RegexMap mapping type - maps values matching regex patterns to colors",
"fieldConfig": {
"defaults": {
"mappings": [
{
"options": {
"pattern": "/^error.*/",
"result": {
"color": "red",
"index": 0,
"text": "Error"
}
},
"type": "regex"
},
{
"options": {
"pattern": "/^warn.*/",
"result": {
"color": "orange",
"index": 1,
"text": "Warning"
}
},
"type": "regex"
},
{
"options": {
"pattern": "/^info.*/",
"result": {
"color": "blue",
"index": 2,
"text": "Info"
}
},
"type": "regex"
}
]
},
"overrides": [
{
"matcher": {
"id": "byType",
"options": "string"
},
"properties": [
{
"id": "custom.cellOptions",
"value": {
"type": "color-text"
}
}
]
}
]
},
"gridPos": {
"h": 8,
"w": 12,
"x": 0,
"y": 8
},
"id": 3,
"targets": [
{
"expr": "log_level",
"refId": "A"
}
],
"title": "RegexMap Example",
"type": "stat"
},
{
"datasource": {
"type": "prometheus",
"uid": "prometheus-uid"
},
"description": "Panel with SpecialValueMap mapping type - maps special values like null, NaN, true, false to display text",
"fieldConfig": {
"defaults": {
"mappings": [
{
"options": {
"match": "null",
"result": {
"color": "gray",
"index": 0,
"text": "No Data"
}
},
"type": "special"
},
{
"options": {
"match": "nan",
"result": {
"color": "gray",
"index": 1,
"text": "Not a Number"
}
},
"type": "special"
},
{
"options": {
"match": "null+nan",
"result": {
"color": "gray",
"index": 2,
"text": "N/A"
}
},
"type": "special"
},
{
"options": {
"match": "true",
"result": {
"color": "green",
"index": 3,
"text": "Yes"
}
},
"type": "special"
},
{
"options": {
"match": "false",
"result": {
"color": "red",
"index": 4,
"text": "No"
}
},
"type": "special"
},
{
"options": {
"match": "empty",
"result": {
"color": "gray",
"index": 5,
"text": "Empty"
}
},
"type": "special"
}
]
},
"overrides": [
{
"matcher": {
"id": "byFrameRefID",
"options": "A"
},
"properties": [
{
"id": "color",
"value": {
"mode": "fixed",
"fixedColor": "blue"
}
}
]
}
]
},
"gridPos": {
"h": 8,
"w": 12,
"x": 12,
"y": 8
},
"id": 4,
"targets": [
{
"expr": "some_metric",
"refId": "A"
}
],
"title": "SpecialValueMap Example",
"type": "stat"
},
{
"datasource": {
"type": "prometheus",
"uid": "prometheus-uid"
},
"description": "Panel with all mapping types combined - demonstrates mixing different mapping types and multiple override matchers",
"fieldConfig": {
"defaults": {
"mappings": [
{
"options": {
"success": {
"color": "green",
"index": 0,
"text": "Success"
},
"failure": {
"color": "red",
"index": 1,
"text": "Failure"
}
},
"type": "value"
},
{
"options": {
"from": 0,
"to": 100,
"result": {
"color": "blue",
"index": 2,
"text": "In Range"
}
},
"type": "range"
},
{
"options": {
"pattern": "/^[A-Z]{3}-\\d+$/",
"result": {
"color": "purple",
"index": 3,
"text": "ID Format"
}
},
"type": "regex"
},
{
"options": {
"match": "null",
"result": {
"color": "gray",
"index": 4,
"text": "Missing"
}
},
"type": "special"
}
]
},
"overrides": [
{
"matcher": {
"id": "byName",
"options": "status"
},
"properties": [
{
"id": "custom.width",
"value": 120
},
{
"id": "custom.cellOptions",
"value": {
"type": "color-background"
}
}
]
},
{
"matcher": {
"id": "byRegexp",
"options": "/^value_/"
},
"properties": [
{
"id": "unit",
"value": "short"
},
{
"id": "min",
"value": 0
},
{
"id": "max",
"value": 100
}
]
},
{
"matcher": {
"id": "byType",
"options": "number"
},
"properties": [
{
"id": "decimals",
"value": 2
},
{
"id": "thresholds",
"value": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "yellow",
"value": 50
},
{
"color": "red",
"value": 80
}
]
}
}
]
},
{
"matcher": {
"id": "byFrameRefID",
"options": "B"
},
"properties": [
{
"id": "displayName",
"value": "Secondary Query"
}
]
},
{
"matcher": {
"id": "byValue",
"options": {
"reducer": "allIsNull",
"op": "gte",
"value": 0
}
},
"properties": [
{
"id": "custom.hidden",
"value": true
}
]
}
]
},
"gridPos": {
"h": 8,
"w": 24,
"x": 0,
"y": 16
},
"id": 5,
"targets": [
{
"expr": "combined_metric",
"refId": "A"
},
{
"expr": "secondary_metric",
"refId": "B"
}
],
"title": "Combined Mappings and Overrides Example",
"type": "table"
}
],
"schemaVersion": 42,
"tags": [
"value-mapping",
"overrides",
"test"
],
"templating": {
"list": []
},
"time": {
"from": "now-6h",
"to": "now"
},
"timepicker": {},
"timezone": "browser",
"title": "Value Mapping and Overrides Test",
"weekStart": ""
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v0alpha1"
}
},
"access": {
"slug": "value-mapping-test",
"url": "/d/value-mapping-test/value-mapping-and-overrides-test",
"canSave": true,
"canEdit": true,
"canAdmin": true,
"canStar": true,
"canDelete": true,
"annotationsPermissions": {
"dashboard": {
"canAdd": true,
"canEdit": true,
"canDelete": true
},
"organization": {
"canAdd": true,
"canEdit": true,
"canDelete": true
}
}
}
}

View File

@@ -1,715 +0,0 @@
{
"kind": "DashboardWithAccessInfo",
"apiVersion": "dashboard.grafana.app/v2beta1",
"metadata": {
"name": "adt885j",
"namespace": "default",
"uid": "yTWet6JgBjlRIWnqRE9ZOmUycfT0tEkr2mljaln1GWIX",
"resourceVersion": "2",
"generation": 2,
"creationTimestamp": "2025-12-16T10:44:31Z",
"labels": {
"grafana.app/deprecatedInternalID": "2409"
},
"annotations": {
"grafana.app/createdBy": "user:u000000001",
"grafana.app/updatedBy": "user:u000000001",
"grafana.app/updatedTimestamp": "2025-12-16T10:51:14Z"
}
},
"spec": {
"annotations": [
{
"kind": "AnnotationQuery",
"spec": {
"query": {
"kind": "DataQuery",
"group": "grafana",
"version": "v0",
"datasource": {
"name": "-- Grafana --"
},
"spec": {}
},
"enable": true,
"hide": true,
"iconColor": "rgba(0, 211, 255, 1)",
"name": "Annotations \u0026 Alerts",
"builtIn": true
}
}
],
"cursorSync": "Off",
"description": "",
"editable": true,
"elements": {
"panel-1": {
"kind": "Panel",
"spec": {
"id": 1,
"title": "Panel1",
"description": "",
"links": [],
"data": {
"kind": "QueryGroup",
"spec": {
"queries": [
{
"kind": "PanelQuery",
"spec": {
"query": {
"kind": "DataQuery",
"group": "grafana-testdata-datasource",
"version": "v0",
"datasource": {
"name": "PD8C576611E62080A"
},
"spec": {}
},
"refId": "A",
"hidden": false
}
}
],
"transformations": [],
"queryOptions": {}
}
},
"vizConfig": {
"kind": "VizConfig",
"group": "timeseries",
"version": "12.4.0-pre",
"spec": {
"options": {
"legend": {
"calcs": [],
"displayMode": "list",
"placement": "bottom",
"showLegend": true
},
"tooltip": {
"hideZeros": false,
"mode": "single",
"sort": "none"
}
},
"fieldConfig": {
"defaults": {
"thresholds": {
"mode": "absolute",
"steps": [
{
"value": 0,
"color": "green"
},
{
"value": 80,
"color": "red"
}
]
},
"color": {
"mode": "palette-classic"
},
"custom": {
"axisBorderShow": false,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"barWidthFactor": 0.6,
"drawStyle": "line",
"fillOpacity": 0,
"gradientMode": "none",
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
},
"insertNulls": false,
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "auto",
"showValues": false,
"spanNulls": false,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
}
},
"overrides": []
}
}
}
}
},
"panel-2": {
"kind": "Panel",
"spec": {
"id": 2,
"title": "Panel2",
"description": "",
"links": [],
"data": {
"kind": "QueryGroup",
"spec": {
"queries": [
{
"kind": "PanelQuery",
"spec": {
"query": {
"kind": "DataQuery",
"group": "",
"version": "v0",
"spec": {}
},
"refId": "A",
"hidden": false
}
}
],
"transformations": [],
"queryOptions": {}
}
},
"vizConfig": {
"kind": "VizConfig",
"group": "timeseries",
"version": "12.4.0-pre",
"spec": {
"options": {
"legend": {
"calcs": [],
"displayMode": "list",
"placement": "bottom",
"showLegend": true
},
"tooltip": {
"hideZeros": false,
"mode": "single",
"sort": "none"
}
},
"fieldConfig": {
"defaults": {
"thresholds": {
"mode": "absolute",
"steps": [
{
"value": 0,
"color": "green"
},
{
"value": 80,
"color": "red"
}
]
},
"color": {
"mode": "palette-classic"
},
"custom": {
"axisBorderShow": false,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"barWidthFactor": 0.6,
"drawStyle": "line",
"fillOpacity": 0,
"gradientMode": "none",
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
},
"insertNulls": false,
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "auto",
"showValues": false,
"spanNulls": false,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
}
},
"overrides": []
}
}
}
}
},
"panel-3": {
"kind": "Panel",
"spec": {
"id": 3,
"title": "Panel3",
"description": "",
"links": [],
"data": {
"kind": "QueryGroup",
"spec": {
"queries": [
{
"kind": "PanelQuery",
"spec": {
"query": {
"kind": "DataQuery",
"group": "",
"version": "v0",
"spec": {}
},
"refId": "A",
"hidden": false
}
}
],
"transformations": [],
"queryOptions": {}
}
},
"vizConfig": {
"kind": "VizConfig",
"group": "timeseries",
"version": "12.4.0-pre",
"spec": {
"options": {
"legend": {
"calcs": [],
"displayMode": "list",
"placement": "bottom",
"showLegend": true
},
"tooltip": {
"hideZeros": false,
"mode": "single",
"sort": "none"
}
},
"fieldConfig": {
"defaults": {
"thresholds": {
"mode": "absolute",
"steps": [
{
"value": 0,
"color": "green"
},
{
"value": 80,
"color": "red"
}
]
},
"color": {
"mode": "palette-classic"
},
"custom": {
"axisBorderShow": false,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"barWidthFactor": 0.6,
"drawStyle": "line",
"fillOpacity": 0,
"gradientMode": "none",
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
},
"insertNulls": false,
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "auto",
"showValues": false,
"spanNulls": false,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
}
},
"overrides": []
}
}
}
}
},
"panel-4": {
"kind": "Panel",
"spec": {
"id": 4,
"title": "Panel4",
"description": "",
"links": [],
"data": {
"kind": "QueryGroup",
"spec": {
"queries": [
{
"kind": "PanelQuery",
"spec": {
"query": {
"kind": "DataQuery",
"group": "",
"version": "v0",
"spec": {}
},
"refId": "A",
"hidden": false
}
}
],
"transformations": [],
"queryOptions": {}
}
},
"vizConfig": {
"kind": "VizConfig",
"group": "timeseries",
"version": "12.4.0-pre",
"spec": {
"options": {
"legend": {
"calcs": [],
"displayMode": "list",
"placement": "bottom",
"showLegend": true
},
"tooltip": {
"hideZeros": false,
"mode": "single",
"sort": "none"
}
},
"fieldConfig": {
"defaults": {
"thresholds": {
"mode": "absolute",
"steps": [
{
"value": 0,
"color": "green"
},
{
"value": 80,
"color": "red"
}
]
},
"color": {
"mode": "palette-classic"
},
"custom": {
"axisBorderShow": false,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"barWidthFactor": 0.6,
"drawStyle": "line",
"fillOpacity": 0,
"gradientMode": "none",
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
},
"insertNulls": false,
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "auto",
"showValues": false,
"spanNulls": false,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
}
},
"overrides": []
}
}
}
}
},
"panel-5": {
"kind": "Panel",
"spec": {
"id": 5,
"title": "Panel5",
"description": "",
"links": [],
"data": {
"kind": "QueryGroup",
"spec": {
"queries": [
{
"kind": "PanelQuery",
"spec": {
"query": {
"kind": "DataQuery",
"group": "",
"version": "v0",
"spec": {}
},
"refId": "A",
"hidden": false
}
}
],
"transformations": [],
"queryOptions": {}
}
},
"vizConfig": {
"kind": "VizConfig",
"group": "timeseries",
"version": "12.4.0-pre",
"spec": {
"options": {
"legend": {
"calcs": [],
"displayMode": "list",
"placement": "bottom",
"showLegend": true
},
"tooltip": {
"hideZeros": false,
"mode": "single",
"sort": "none"
}
},
"fieldConfig": {
"defaults": {
"thresholds": {
"mode": "absolute",
"steps": [
{
"value": 0,
"color": "green"
},
{
"value": 80,
"color": "red"
}
]
},
"color": {
"mode": "palette-classic"
},
"custom": {
"axisBorderShow": false,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"barWidthFactor": 0.6,
"drawStyle": "line",
"fillOpacity": 0,
"gradientMode": "none",
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
},
"insertNulls": false,
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "auto",
"showValues": false,
"spanNulls": false,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
}
},
"overrides": []
}
}
}
}
}
},
"layout": {
"kind": "TabsLayout",
"spec": {
"tabs": [
{
"kind": "TabsLayoutTab",
"spec": {
"title": "Tab1",
"layout": {
"kind": "GridLayout",
"spec": {
"items": [
{
"kind": "GridLayoutItem",
"spec": {
"x": 0,
"y": 0,
"width": 7,
"height": 8,
"element": {
"kind": "ElementReference",
"name": "panel-1"
}
}
},
{
"kind": "GridLayoutItem",
"spec": {
"x": 7,
"y": 0,
"width": 8,
"height": 8,
"element": {
"kind": "ElementReference",
"name": "panel-2"
}
}
},
{
"kind": "GridLayoutItem",
"spec": {
"x": 15,
"y": 0,
"width": 9,
"height": 8,
"element": {
"kind": "ElementReference",
"name": "panel-3"
}
}
},
{
"kind": "GridLayoutItem",
"spec": {
"x": 0,
"y": 8,
"width": 12,
"height": 8,
"element": {
"kind": "ElementReference",
"name": "panel-4"
}
}
},
{
"kind": "GridLayoutItem",
"spec": {
"x": 12,
"y": 8,
"width": 12,
"height": 8,
"element": {
"kind": "ElementReference",
"name": "panel-5"
}
}
}
]
}
}
}
}
]
}
},
"links": [],
"liveNow": false,
"preload": false,
"tags": [],
"timeSettings": {
"timezone": "browser",
"from": "now-6h",
"to": "now",
"autoRefresh": "",
"autoRefreshIntervals": [
"5s",
"10s",
"30s",
"1m",
"5m",
"15m",
"30m",
"1h",
"2h",
"1d"
],
"hideTimepicker": false,
"fiscalYearStartMonth": 0
},
"title": "Dashboard with tabs",
"variables": []
},
"status": {},
"access": {
"slug": "dashboard-with-tabs",
"url": "/d/adt885j/dashboard-with-tabs",
"isPublic": false,
"canSave": true,
"canEdit": true,
"canAdmin": true,
"canStar": true,
"canDelete": true,
"annotationsPermissions": {
"dashboard": {
"canAdd": true,
"canEdit": true,
"canDelete": true
},
"organization": {
"canAdd": true,
"canEdit": true,
"canDelete": true
}
}
}
}

View File

@@ -530,7 +530,7 @@
"kind": "RowsLayoutRow",
"spec": {
"title": "",
"collapse": false,
"collapse": true,
"hideHeader": true,
"layout": {
"kind": "GridLayout",

View File

@@ -546,7 +546,7 @@
"kind": "RowsLayoutRow",
"spec": {
"title": "",
"collapse": false,
"collapse": true,
"hideHeader": true,
"layout": {
"kind": "GridLayout",

View File

@@ -548,7 +548,7 @@
"kind": "RowsLayoutRow",
"spec": {
"title": "",
"collapse": false,
"collapse": true,
"hideHeader": true,
"layout": {
"kind": "GridLayout",

View File

@@ -574,7 +574,7 @@
"kind": "RowsLayoutRow",
"spec": {
"title": "",
"collapse": false,
"collapse": true,
"hideHeader": true,
"layout": {
"kind": "GridLayout",

View File

@@ -1663,7 +1663,7 @@
"kind": "RowsLayoutRow",
"spec": {
"title": "",
"collapse": false,
"collapse": true,
"hideHeader": true,
"layout": {
"kind": "GridLayout",

View File

@@ -1727,7 +1727,7 @@
"kind": "RowsLayoutRow",
"spec": {
"title": "",
"collapse": false,
"collapse": true,
"hideHeader": true,
"layout": {
"kind": "GridLayout",

View File

@@ -328,7 +328,7 @@
"kind": "RowsLayoutRow",
"spec": {
"title": "",
"collapse": false,
"collapse": true,
"hideHeader": true,
"layout": {
"kind": "GridLayout",

View File

@@ -335,7 +335,7 @@
"kind": "RowsLayoutRow",
"spec": {
"title": "",
"collapse": false,
"collapse": true,
"hideHeader": true,
"layout": {
"kind": "GridLayout",

View File

@@ -1,580 +0,0 @@
{
"kind": "DashboardWithAccessInfo",
"apiVersion": "dashboard.grafana.app/v0alpha1",
"metadata": {
"name": "value-mapping-test",
"namespace": "default",
"uid": "value-mapping-test",
"resourceVersion": "1765384157199094",
"generation": 2,
"creationTimestamp": "2025-11-19T20:09:28Z",
"labels": {
"grafana.app/deprecatedInternalID": "646372978987008"
}
},
"spec": {
"annotations": {
"list": [
{
"builtIn": 1,
"datasource": {
"type": "grafana",
"uid": "-- Grafana --"
},
"enable": true,
"hide": true,
"iconColor": "rgba(0, 211, 255, 1)",
"name": "Annotations \u0026 Alerts",
"type": "dashboard"
}
]
},
"description": "Test dashboard for all value mapping types and override matcher types",
"editable": true,
"fiscalYearStartMonth": 0,
"graphTooltip": 0,
"links": [],
"panels": [
{
"datasource": {
"type": "prometheus",
"uid": "prometheus-uid"
},
"description": "Panel with ValueMap mapping type - maps specific text values to colors and display text",
"fieldConfig": {
"defaults": {
"mappings": [
{
"options": {
"critical": {
"color": "red",
"index": 0,
"text": "Critical!"
},
"ok": {
"color": "green",
"index": 2,
"text": "OK"
},
"warning": {
"color": "orange",
"index": 1,
"text": "Warning"
}
},
"type": "value"
}
]
},
"overrides": [
{
"matcher": {
"id": "byName",
"options": "status"
},
"properties": [
{
"id": "custom.width",
"value": 100
},
{
"id": "custom.align",
"value": "center"
}
]
}
]
},
"gridPos": {
"h": 8,
"w": 12,
"x": 0,
"y": 0
},
"id": 1,
"targets": [
{
"expr": "up",
"refId": "A"
}
],
"title": "ValueMap Example",
"type": "stat"
},
{
"datasource": {
"type": "prometheus",
"uid": "prometheus-uid"
},
"description": "Panel with RangeMap mapping type - maps numerical ranges to colors and display text",
"fieldConfig": {
"defaults": {
"mappings": [
{
"options": {
"from": 0,
"result": {
"color": "green",
"index": 0,
"text": "Low"
},
"to": 50
},
"type": "range"
},
{
"options": {
"from": 50,
"result": {
"color": "orange",
"index": 1,
"text": "Medium"
},
"to": 80
},
"type": "range"
},
{
"options": {
"from": 80,
"result": {
"color": "red",
"index": 2,
"text": "High"
},
"to": 100
},
"type": "range"
}
]
},
"overrides": [
{
"matcher": {
"id": "byRegexp",
"options": "/^cpu_/"
},
"properties": [
{
"id": "unit",
"value": "percent"
},
{
"id": "decimals",
"value": 2
}
]
}
]
},
"gridPos": {
"h": 8,
"w": 12,
"x": 12,
"y": 0
},
"id": 2,
"targets": [
{
"expr": "cpu_usage_percent",
"refId": "A"
}
],
"title": "RangeMap Example",
"type": "gauge"
},
{
"datasource": {
"type": "prometheus",
"uid": "prometheus-uid"
},
"description": "Panel with RegexMap mapping type - maps values matching regex patterns to colors",
"fieldConfig": {
"defaults": {
"mappings": [
{
"options": {
"pattern": "/^error.*/",
"result": {
"color": "red",
"index": 0,
"text": "Error"
}
},
"type": "regex"
},
{
"options": {
"pattern": "/^warn.*/",
"result": {
"color": "orange",
"index": 1,
"text": "Warning"
}
},
"type": "regex"
},
{
"options": {
"pattern": "/^info.*/",
"result": {
"color": "blue",
"index": 2,
"text": "Info"
}
},
"type": "regex"
}
]
},
"overrides": [
{
"matcher": {
"id": "byType",
"options": "string"
},
"properties": [
{
"id": "custom.cellOptions",
"value": {
"type": "color-text"
}
}
]
}
]
},
"gridPos": {
"h": 8,
"w": 12,
"x": 0,
"y": 8
},
"id": 3,
"targets": [
{
"expr": "log_level",
"refId": "A"
}
],
"title": "RegexMap Example",
"type": "stat"
},
{
"datasource": {
"type": "prometheus",
"uid": "prometheus-uid"
},
"description": "Panel with SpecialValueMap mapping type - maps special values like null, NaN, true, false to display text",
"fieldConfig": {
"defaults": {
"mappings": [
{
"options": {
"match": "null",
"result": {
"color": "gray",
"index": 0,
"text": "No Data"
}
},
"type": "special"
},
{
"options": {
"match": "nan",
"result": {
"color": "gray",
"index": 1,
"text": "Not a Number"
}
},
"type": "special"
},
{
"options": {
"match": "null+nan",
"result": {
"color": "gray",
"index": 2,
"text": "N/A"
}
},
"type": "special"
},
{
"options": {
"match": "true",
"result": {
"color": "green",
"index": 3,
"text": "Yes"
}
},
"type": "special"
},
{
"options": {
"match": "false",
"result": {
"color": "red",
"index": 4,
"text": "No"
}
},
"type": "special"
},
{
"options": {
"match": "empty",
"result": {
"color": "gray",
"index": 5,
"text": "Empty"
}
},
"type": "special"
}
]
},
"overrides": [
{
"matcher": {
"id": "byFrameRefID",
"options": "A"
},
"properties": [
{
"id": "color",
"value": {
"fixedColor": "blue",
"mode": "fixed"
}
}
]
}
]
},
"gridPos": {
"h": 8,
"w": 12,
"x": 12,
"y": 8
},
"id": 4,
"targets": [
{
"expr": "some_metric",
"refId": "A"
}
],
"title": "SpecialValueMap Example",
"type": "stat"
},
{
"datasource": {
"type": "prometheus",
"uid": "prometheus-uid"
},
"description": "Panel with all mapping types combined - demonstrates mixing different mapping types and multiple override matchers",
"fieldConfig": {
"defaults": {
"mappings": [
{
"options": {
"failure": {
"color": "red",
"index": 1,
"text": "Failure"
},
"success": {
"color": "green",
"index": 0,
"text": "Success"
}
},
"type": "value"
},
{
"options": {
"from": 0,
"result": {
"color": "blue",
"index": 2,
"text": "In Range"
},
"to": 100
},
"type": "range"
},
{
"options": {
"pattern": "/^[A-Z]{3}-\\d+$/",
"result": {
"color": "purple",
"index": 3,
"text": "ID Format"
}
},
"type": "regex"
},
{
"options": {
"match": "null",
"result": {
"color": "gray",
"index": 4,
"text": "Missing"
}
},
"type": "special"
}
]
},
"overrides": [
{
"matcher": {
"id": "byName",
"options": "status"
},
"properties": [
{
"id": "custom.width",
"value": 120
},
{
"id": "custom.cellOptions",
"value": {
"type": "color-background"
}
}
]
},
{
"matcher": {
"id": "byRegexp",
"options": "/^value_/"
},
"properties": [
{
"id": "unit",
"value": "short"
},
{
"id": "min",
"value": 0
},
{
"id": "max",
"value": 100
}
]
},
{
"matcher": {
"id": "byType",
"options": "number"
},
"properties": [
{
"id": "decimals",
"value": 2
},
{
"id": "thresholds",
"value": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "yellow",
"value": 50
},
{
"color": "red",
"value": 80
}
]
}
}
]
},
{
"matcher": {
"id": "byFrameRefID",
"options": "B"
},
"properties": [
{
"id": "displayName",
"value": "Secondary Query"
}
]
},
{
"matcher": {
"id": "byValue",
"options": {
"op": "gte",
"reducer": "allIsNull",
"value": 0
}
},
"properties": [
{
"id": "custom.hidden",
"value": true
}
]
}
]
},
"gridPos": {
"h": 8,
"w": 24,
"x": 0,
"y": 16
},
"id": 5,
"targets": [
{
"expr": "combined_metric",
"refId": "A"
},
{
"expr": "secondary_metric",
"refId": "B"
}
],
"title": "Combined Mappings and Overrides Example",
"type": "table"
}
],
"schemaVersion": 42,
"tags": [
"value-mapping",
"overrides",
"test"
],
"templating": {
"list": []
},
"time": {
"from": "now-6h",
"to": "now"
},
"timepicker": {},
"timezone": "browser",
"title": "Value Mapping and Overrides Test",
"weekStart": ""
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v1beta1"
}
}
}

View File

@@ -1,783 +0,0 @@
{
"kind": "DashboardWithAccessInfo",
"apiVersion": "dashboard.grafana.app/v2alpha1",
"metadata": {
"name": "value-mapping-test",
"namespace": "default",
"uid": "value-mapping-test",
"resourceVersion": "1765384157199094",
"generation": 2,
"creationTimestamp": "2025-11-19T20:09:28Z",
"labels": {
"grafana.app/deprecatedInternalID": "646372978987008"
}
},
"spec": {
"annotations": [
{
"kind": "AnnotationQuery",
"spec": {
"datasource": {
"type": "grafana",
"uid": "-- Grafana --"
},
"query": {
"kind": "grafana",
"spec": {}
},
"enable": true,
"hide": true,
"iconColor": "rgba(0, 211, 255, 1)",
"name": "Annotations \u0026 Alerts",
"builtIn": true,
"legacyOptions": {
"type": "dashboard"
}
}
}
],
"cursorSync": "Off",
"description": "Test dashboard for all value mapping types and override matcher types",
"editable": true,
"elements": {
"panel-1": {
"kind": "Panel",
"spec": {
"id": 1,
"title": "ValueMap Example",
"description": "Panel with ValueMap mapping type - maps specific text values to colors and display text",
"links": [],
"data": {
"kind": "QueryGroup",
"spec": {
"queries": [
{
"kind": "PanelQuery",
"spec": {
"query": {
"kind": "prometheus",
"spec": {
"expr": "up"
}
},
"datasource": {
"type": "prometheus",
"uid": "prometheus-uid"
},
"refId": "A",
"hidden": false
}
}
],
"transformations": [],
"queryOptions": {}
}
},
"vizConfig": {
"kind": "stat",
"spec": {
"pluginVersion": "",
"options": {},
"fieldConfig": {
"defaults": {
"mappings": [
{
"type": "value",
"options": {
"critical": {
"text": "Critical!",
"color": "red",
"index": 0
},
"ok": {
"text": "OK",
"color": "green",
"index": 2
},
"warning": {
"text": "Warning",
"color": "orange",
"index": 1
}
}
}
]
},
"overrides": [
{
"matcher": {
"id": "byName",
"options": "status"
},
"properties": [
{
"id": "custom.width",
"value": 100
},
{
"id": "custom.align",
"value": "center"
}
]
}
]
}
}
}
}
},
"panel-2": {
"kind": "Panel",
"spec": {
"id": 2,
"title": "RangeMap Example",
"description": "Panel with RangeMap mapping type - maps numerical ranges to colors and display text",
"links": [],
"data": {
"kind": "QueryGroup",
"spec": {
"queries": [
{
"kind": "PanelQuery",
"spec": {
"query": {
"kind": "prometheus",
"spec": {
"expr": "cpu_usage_percent"
}
},
"datasource": {
"type": "prometheus",
"uid": "prometheus-uid"
},
"refId": "A",
"hidden": false
}
}
],
"transformations": [],
"queryOptions": {}
}
},
"vizConfig": {
"kind": "gauge",
"spec": {
"pluginVersion": "",
"options": {},
"fieldConfig": {
"defaults": {
"mappings": [
{
"type": "range",
"options": {
"from": 0,
"to": 50,
"result": {
"text": "Low",
"color": "green",
"index": 0
}
}
},
{
"type": "range",
"options": {
"from": 50,
"to": 80,
"result": {
"text": "Medium",
"color": "orange",
"index": 1
}
}
},
{
"type": "range",
"options": {
"from": 80,
"to": 100,
"result": {
"text": "High",
"color": "red",
"index": 2
}
}
}
]
},
"overrides": [
{
"matcher": {
"id": "byRegexp",
"options": "/^cpu_/"
},
"properties": [
{
"id": "unit",
"value": "percent"
},
{
"id": "decimals",
"value": 2
}
]
}
]
}
}
}
}
},
"panel-3": {
"kind": "Panel",
"spec": {
"id": 3,
"title": "RegexMap Example",
"description": "Panel with RegexMap mapping type - maps values matching regex patterns to colors",
"links": [],
"data": {
"kind": "QueryGroup",
"spec": {
"queries": [
{
"kind": "PanelQuery",
"spec": {
"query": {
"kind": "prometheus",
"spec": {
"expr": "log_level"
}
},
"datasource": {
"type": "prometheus",
"uid": "prometheus-uid"
},
"refId": "A",
"hidden": false
}
}
],
"transformations": [],
"queryOptions": {}
}
},
"vizConfig": {
"kind": "stat",
"spec": {
"pluginVersion": "",
"options": {},
"fieldConfig": {
"defaults": {
"mappings": [
{
"type": "regex",
"options": {
"pattern": "/^error.*/",
"result": {
"text": "Error",
"color": "red",
"index": 0
}
}
},
{
"type": "regex",
"options": {
"pattern": "/^warn.*/",
"result": {
"text": "Warning",
"color": "orange",
"index": 1
}
}
},
{
"type": "regex",
"options": {
"pattern": "/^info.*/",
"result": {
"text": "Info",
"color": "blue",
"index": 2
}
}
}
]
},
"overrides": [
{
"matcher": {
"id": "byType",
"options": "string"
},
"properties": [
{
"id": "custom.cellOptions",
"value": {
"type": "color-text"
}
}
]
}
]
}
}
}
}
},
"panel-4": {
"kind": "Panel",
"spec": {
"id": 4,
"title": "SpecialValueMap Example",
"description": "Panel with SpecialValueMap mapping type - maps special values like null, NaN, true, false to display text",
"links": [],
"data": {
"kind": "QueryGroup",
"spec": {
"queries": [
{
"kind": "PanelQuery",
"spec": {
"query": {
"kind": "prometheus",
"spec": {
"expr": "some_metric"
}
},
"datasource": {
"type": "prometheus",
"uid": "prometheus-uid"
},
"refId": "A",
"hidden": false
}
}
],
"transformations": [],
"queryOptions": {}
}
},
"vizConfig": {
"kind": "stat",
"spec": {
"pluginVersion": "",
"options": {},
"fieldConfig": {
"defaults": {
"mappings": [
{
"type": "special",
"options": {
"match": "null",
"result": {
"text": "No Data",
"color": "gray",
"index": 0
}
}
},
{
"type": "special",
"options": {
"match": "nan",
"result": {
"text": "Not a Number",
"color": "gray",
"index": 1
}
}
},
{
"type": "special",
"options": {
"match": "null+nan",
"result": {
"text": "N/A",
"color": "gray",
"index": 2
}
}
},
{
"type": "special",
"options": {
"match": "true",
"result": {
"text": "Yes",
"color": "green",
"index": 3
}
}
},
{
"type": "special",
"options": {
"match": "false",
"result": {
"text": "No",
"color": "red",
"index": 4
}
}
},
{
"type": "special",
"options": {
"match": "empty",
"result": {
"text": "Empty",
"color": "gray",
"index": 5
}
}
}
]
},
"overrides": [
{
"matcher": {
"id": "byFrameRefID",
"options": "A"
},
"properties": [
{
"id": "color",
"value": {
"fixedColor": "blue",
"mode": "fixed"
}
}
]
}
]
}
}
}
}
},
"panel-5": {
"kind": "Panel",
"spec": {
"id": 5,
"title": "Combined Mappings and Overrides Example",
"description": "Panel with all mapping types combined - demonstrates mixing different mapping types and multiple override matchers",
"links": [],
"data": {
"kind": "QueryGroup",
"spec": {
"queries": [
{
"kind": "PanelQuery",
"spec": {
"query": {
"kind": "prometheus",
"spec": {
"expr": "combined_metric"
}
},
"datasource": {
"type": "prometheus",
"uid": "prometheus-uid"
},
"refId": "A",
"hidden": false
}
},
{
"kind": "PanelQuery",
"spec": {
"query": {
"kind": "prometheus",
"spec": {
"expr": "secondary_metric"
}
},
"datasource": {
"type": "prometheus",
"uid": "prometheus-uid"
},
"refId": "B",
"hidden": false
}
}
],
"transformations": [],
"queryOptions": {}
}
},
"vizConfig": {
"kind": "table",
"spec": {
"pluginVersion": "",
"options": {},
"fieldConfig": {
"defaults": {
"mappings": [
{
"type": "value",
"options": {
"failure": {
"text": "Failure",
"color": "red",
"index": 1
},
"success": {
"text": "Success",
"color": "green",
"index": 0
}
}
},
{
"type": "range",
"options": {
"from": 0,
"to": 100,
"result": {
"text": "In Range",
"color": "blue",
"index": 2
}
}
},
{
"type": "regex",
"options": {
"pattern": "/^[A-Z]{3}-\\d+$/",
"result": {
"text": "ID Format",
"color": "purple",
"index": 3
}
}
},
{
"type": "special",
"options": {
"match": "null",
"result": {
"text": "Missing",
"color": "gray",
"index": 4
}
}
}
]
},
"overrides": [
{
"matcher": {
"id": "byName",
"options": "status"
},
"properties": [
{
"id": "custom.width",
"value": 120
},
{
"id": "custom.cellOptions",
"value": {
"type": "color-background"
}
}
]
},
{
"matcher": {
"id": "byRegexp",
"options": "/^value_/"
},
"properties": [
{
"id": "unit",
"value": "short"
},
{
"id": "min",
"value": 0
},
{
"id": "max",
"value": 100
}
]
},
{
"matcher": {
"id": "byType",
"options": "number"
},
"properties": [
{
"id": "decimals",
"value": 2
},
{
"id": "thresholds",
"value": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "yellow",
"value": 50
},
{
"color": "red",
"value": 80
}
]
}
}
]
},
{
"matcher": {
"id": "byFrameRefID",
"options": "B"
},
"properties": [
{
"id": "displayName",
"value": "Secondary Query"
}
]
},
{
"matcher": {
"id": "byValue",
"options": {
"op": "gte",
"reducer": "allIsNull",
"value": 0
}
},
"properties": [
{
"id": "custom.hidden",
"value": true
}
]
}
]
}
}
}
}
}
},
"layout": {
"kind": "GridLayout",
"spec": {
"items": [
{
"kind": "GridLayoutItem",
"spec": {
"x": 0,
"y": 0,
"width": 12,
"height": 8,
"element": {
"kind": "ElementReference",
"name": "panel-1"
}
}
},
{
"kind": "GridLayoutItem",
"spec": {
"x": 12,
"y": 0,
"width": 12,
"height": 8,
"element": {
"kind": "ElementReference",
"name": "panel-2"
}
}
},
{
"kind": "GridLayoutItem",
"spec": {
"x": 0,
"y": 8,
"width": 12,
"height": 8,
"element": {
"kind": "ElementReference",
"name": "panel-3"
}
}
},
{
"kind": "GridLayoutItem",
"spec": {
"x": 12,
"y": 8,
"width": 12,
"height": 8,
"element": {
"kind": "ElementReference",
"name": "panel-4"
}
}
},
{
"kind": "GridLayoutItem",
"spec": {
"x": 0,
"y": 16,
"width": 24,
"height": 8,
"element": {
"kind": "ElementReference",
"name": "panel-5"
}
}
}
]
}
},
"links": [],
"liveNow": false,
"preload": false,
"tags": [
"value-mapping",
"overrides",
"test"
],
"timeSettings": {
"timezone": "browser",
"from": "now-6h",
"to": "now",
"autoRefresh": "",
"autoRefreshIntervals": [
"5s",
"10s",
"30s",
"1m",
"5m",
"15m",
"30m",
"1h",
"2h",
"1d"
],
"hideTimepicker": false,
"fiscalYearStartMonth": 0
},
"title": "Value Mapping and Overrides Test",
"variables": []
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v1beta1"
}
}
}

View File

@@ -1,795 +0,0 @@
{
"kind": "DashboardWithAccessInfo",
"apiVersion": "dashboard.grafana.app/v2beta1",
"metadata": {
"name": "value-mapping-test",
"namespace": "default",
"uid": "value-mapping-test",
"resourceVersion": "1765384157199094",
"generation": 2,
"creationTimestamp": "2025-11-19T20:09:28Z",
"labels": {
"grafana.app/deprecatedInternalID": "646372978987008"
}
},
"spec": {
"annotations": [
{
"kind": "AnnotationQuery",
"spec": {
"query": {
"kind": "DataQuery",
"group": "grafana",
"version": "v0",
"datasource": {
"name": "-- Grafana --"
},
"spec": {}
},
"enable": true,
"hide": true,
"iconColor": "rgba(0, 211, 255, 1)",
"name": "Annotations \u0026 Alerts",
"builtIn": true,
"legacyOptions": {
"type": "dashboard"
}
}
}
],
"cursorSync": "Off",
"description": "Test dashboard for all value mapping types and override matcher types",
"editable": true,
"elements": {
"panel-1": {
"kind": "Panel",
"spec": {
"id": 1,
"title": "ValueMap Example",
"description": "Panel with ValueMap mapping type - maps specific text values to colors and display text",
"links": [],
"data": {
"kind": "QueryGroup",
"spec": {
"queries": [
{
"kind": "PanelQuery",
"spec": {
"query": {
"kind": "DataQuery",
"group": "prometheus",
"version": "v0",
"datasource": {
"name": "prometheus-uid"
},
"spec": {
"expr": "up"
}
},
"refId": "A",
"hidden": false
}
}
],
"transformations": [],
"queryOptions": {}
}
},
"vizConfig": {
"kind": "VizConfig",
"group": "stat",
"version": "",
"spec": {
"options": {},
"fieldConfig": {
"defaults": {
"mappings": [
{
"type": "value",
"options": {
"critical": {
"text": "Critical!",
"color": "red",
"index": 0
},
"ok": {
"text": "OK",
"color": "green",
"index": 2
},
"warning": {
"text": "Warning",
"color": "orange",
"index": 1
}
}
}
]
},
"overrides": [
{
"matcher": {
"id": "byName",
"options": "status"
},
"properties": [
{
"id": "custom.width",
"value": 100
},
{
"id": "custom.align",
"value": "center"
}
]
}
]
}
}
}
}
},
"panel-2": {
"kind": "Panel",
"spec": {
"id": 2,
"title": "RangeMap Example",
"description": "Panel with RangeMap mapping type - maps numerical ranges to colors and display text",
"links": [],
"data": {
"kind": "QueryGroup",
"spec": {
"queries": [
{
"kind": "PanelQuery",
"spec": {
"query": {
"kind": "DataQuery",
"group": "prometheus",
"version": "v0",
"datasource": {
"name": "prometheus-uid"
},
"spec": {
"expr": "cpu_usage_percent"
}
},
"refId": "A",
"hidden": false
}
}
],
"transformations": [],
"queryOptions": {}
}
},
"vizConfig": {
"kind": "VizConfig",
"group": "gauge",
"version": "",
"spec": {
"options": {},
"fieldConfig": {
"defaults": {
"mappings": [
{
"type": "range",
"options": {
"from": 0,
"to": 50,
"result": {
"text": "Low",
"color": "green",
"index": 0
}
}
},
{
"type": "range",
"options": {
"from": 50,
"to": 80,
"result": {
"text": "Medium",
"color": "orange",
"index": 1
}
}
},
{
"type": "range",
"options": {
"from": 80,
"to": 100,
"result": {
"text": "High",
"color": "red",
"index": 2
}
}
}
]
},
"overrides": [
{
"matcher": {
"id": "byRegexp",
"options": "/^cpu_/"
},
"properties": [
{
"id": "unit",
"value": "percent"
},
{
"id": "decimals",
"value": 2
}
]
}
]
}
}
}
}
},
"panel-3": {
"kind": "Panel",
"spec": {
"id": 3,
"title": "RegexMap Example",
"description": "Panel with RegexMap mapping type - maps values matching regex patterns to colors",
"links": [],
"data": {
"kind": "QueryGroup",
"spec": {
"queries": [
{
"kind": "PanelQuery",
"spec": {
"query": {
"kind": "DataQuery",
"group": "prometheus",
"version": "v0",
"datasource": {
"name": "prometheus-uid"
},
"spec": {
"expr": "log_level"
}
},
"refId": "A",
"hidden": false
}
}
],
"transformations": [],
"queryOptions": {}
}
},
"vizConfig": {
"kind": "VizConfig",
"group": "stat",
"version": "",
"spec": {
"options": {},
"fieldConfig": {
"defaults": {
"mappings": [
{
"type": "regex",
"options": {
"pattern": "/^error.*/",
"result": {
"text": "Error",
"color": "red",
"index": 0
}
}
},
{
"type": "regex",
"options": {
"pattern": "/^warn.*/",
"result": {
"text": "Warning",
"color": "orange",
"index": 1
}
}
},
{
"type": "regex",
"options": {
"pattern": "/^info.*/",
"result": {
"text": "Info",
"color": "blue",
"index": 2
}
}
}
]
},
"overrides": [
{
"matcher": {
"id": "byType",
"options": "string"
},
"properties": [
{
"id": "custom.cellOptions",
"value": {
"type": "color-text"
}
}
]
}
]
}
}
}
}
},
"panel-4": {
"kind": "Panel",
"spec": {
"id": 4,
"title": "SpecialValueMap Example",
"description": "Panel with SpecialValueMap mapping type - maps special values like null, NaN, true, false to display text",
"links": [],
"data": {
"kind": "QueryGroup",
"spec": {
"queries": [
{
"kind": "PanelQuery",
"spec": {
"query": {
"kind": "DataQuery",
"group": "prometheus",
"version": "v0",
"datasource": {
"name": "prometheus-uid"
},
"spec": {
"expr": "some_metric"
}
},
"refId": "A",
"hidden": false
}
}
],
"transformations": [],
"queryOptions": {}
}
},
"vizConfig": {
"kind": "VizConfig",
"group": "stat",
"version": "",
"spec": {
"options": {},
"fieldConfig": {
"defaults": {
"mappings": [
{
"type": "special",
"options": {
"match": "null",
"result": {
"text": "No Data",
"color": "gray",
"index": 0
}
}
},
{
"type": "special",
"options": {
"match": "nan",
"result": {
"text": "Not a Number",
"color": "gray",
"index": 1
}
}
},
{
"type": "special",
"options": {
"match": "null+nan",
"result": {
"text": "N/A",
"color": "gray",
"index": 2
}
}
},
{
"type": "special",
"options": {
"match": "true",
"result": {
"text": "Yes",
"color": "green",
"index": 3
}
}
},
{
"type": "special",
"options": {
"match": "false",
"result": {
"text": "No",
"color": "red",
"index": 4
}
}
},
{
"type": "special",
"options": {
"match": "empty",
"result": {
"text": "Empty",
"color": "gray",
"index": 5
}
}
}
]
},
"overrides": [
{
"matcher": {
"id": "byFrameRefID",
"options": "A"
},
"properties": [
{
"id": "color",
"value": {
"fixedColor": "blue",
"mode": "fixed"
}
}
]
}
]
}
}
}
}
},
"panel-5": {
"kind": "Panel",
"spec": {
"id": 5,
"title": "Combined Mappings and Overrides Example",
"description": "Panel with all mapping types combined - demonstrates mixing different mapping types and multiple override matchers",
"links": [],
"data": {
"kind": "QueryGroup",
"spec": {
"queries": [
{
"kind": "PanelQuery",
"spec": {
"query": {
"kind": "DataQuery",
"group": "prometheus",
"version": "v0",
"datasource": {
"name": "prometheus-uid"
},
"spec": {
"expr": "combined_metric"
}
},
"refId": "A",
"hidden": false
}
},
{
"kind": "PanelQuery",
"spec": {
"query": {
"kind": "DataQuery",
"group": "prometheus",
"version": "v0",
"datasource": {
"name": "prometheus-uid"
},
"spec": {
"expr": "secondary_metric"
}
},
"refId": "B",
"hidden": false
}
}
],
"transformations": [],
"queryOptions": {}
}
},
"vizConfig": {
"kind": "VizConfig",
"group": "table",
"version": "",
"spec": {
"options": {},
"fieldConfig": {
"defaults": {
"mappings": [
{
"type": "value",
"options": {
"failure": {
"text": "Failure",
"color": "red",
"index": 1
},
"success": {
"text": "Success",
"color": "green",
"index": 0
}
}
},
{
"type": "range",
"options": {
"from": 0,
"to": 100,
"result": {
"text": "In Range",
"color": "blue",
"index": 2
}
}
},
{
"type": "regex",
"options": {
"pattern": "/^[A-Z]{3}-\\d+$/",
"result": {
"text": "ID Format",
"color": "purple",
"index": 3
}
}
},
{
"type": "special",
"options": {
"match": "null",
"result": {
"text": "Missing",
"color": "gray",
"index": 4
}
}
}
]
},
"overrides": [
{
"matcher": {
"id": "byName",
"options": "status"
},
"properties": [
{
"id": "custom.width",
"value": 120
},
{
"id": "custom.cellOptions",
"value": {
"type": "color-background"
}
}
]
},
{
"matcher": {
"id": "byRegexp",
"options": "/^value_/"
},
"properties": [
{
"id": "unit",
"value": "short"
},
{
"id": "min",
"value": 0
},
{
"id": "max",
"value": 100
}
]
},
{
"matcher": {
"id": "byType",
"options": "number"
},
"properties": [
{
"id": "decimals",
"value": 2
},
{
"id": "thresholds",
"value": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "yellow",
"value": 50
},
{
"color": "red",
"value": 80
}
]
}
}
]
},
{
"matcher": {
"id": "byFrameRefID",
"options": "B"
},
"properties": [
{
"id": "displayName",
"value": "Secondary Query"
}
]
},
{
"matcher": {
"id": "byValue",
"options": {
"op": "gte",
"reducer": "allIsNull",
"value": 0
}
},
"properties": [
{
"id": "custom.hidden",
"value": true
}
]
}
]
}
}
}
}
}
},
"layout": {
"kind": "GridLayout",
"spec": {
"items": [
{
"kind": "GridLayoutItem",
"spec": {
"x": 0,
"y": 0,
"width": 12,
"height": 8,
"element": {
"kind": "ElementReference",
"name": "panel-1"
}
}
},
{
"kind": "GridLayoutItem",
"spec": {
"x": 12,
"y": 0,
"width": 12,
"height": 8,
"element": {
"kind": "ElementReference",
"name": "panel-2"
}
}
},
{
"kind": "GridLayoutItem",
"spec": {
"x": 0,
"y": 8,
"width": 12,
"height": 8,
"element": {
"kind": "ElementReference",
"name": "panel-3"
}
}
},
{
"kind": "GridLayoutItem",
"spec": {
"x": 12,
"y": 8,
"width": 12,
"height": 8,
"element": {
"kind": "ElementReference",
"name": "panel-4"
}
}
},
{
"kind": "GridLayoutItem",
"spec": {
"x": 0,
"y": 16,
"width": 24,
"height": 8,
"element": {
"kind": "ElementReference",
"name": "panel-5"
}
}
}
]
}
},
"links": [],
"liveNow": false,
"preload": false,
"tags": [
"value-mapping",
"overrides",
"test"
],
"timeSettings": {
"timezone": "browser",
"from": "now-6h",
"to": "now",
"autoRefresh": "",
"autoRefreshIntervals": [
"5s",
"10s",
"30s",
"1m",
"5m",
"15m",
"30m",
"1h",
"2h",
"1d"
],
"hideTimepicker": false,
"fiscalYearStartMonth": 0
},
"title": "Value Mapping and Overrides Test",
"variables": []
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v1beta1"
}
}
}

View File

@@ -1,511 +0,0 @@
{
"kind": "DashboardWithAccessInfo",
"apiVersion": "dashboard.grafana.app/v0alpha1",
"metadata": {
"name": "adt885j",
"namespace": "default",
"uid": "yTWet6JgBjlRIWnqRE9ZOmUycfT0tEkr2mljaln1GWIX",
"resourceVersion": "2",
"generation": 2,
"creationTimestamp": "2025-12-16T10:44:31Z",
"labels": {
"grafana.app/deprecatedInternalID": "2409"
},
"annotations": {
"grafana.app/createdBy": "user:u000000001",
"grafana.app/updatedBy": "user:u000000001",
"grafana.app/updatedTimestamp": "2025-12-16T10:51:14Z"
}
},
"spec": {
"annotations": {
"list": [
{
"builtIn": 1,
"datasource": {
"type": "grafana",
"uid": "-- Grafana --"
},
"enable": true,
"hide": true,
"iconColor": "rgba(0, 211, 255, 1)",
"name": "Annotations \u0026 Alerts",
"type": "dashboard"
}
]
},
"description": "",
"editable": true,
"fiscalYearStartMonth": 0,
"graphTooltip": 0,
"liveNow": false,
"panels": [
{
"collapsed": false,
"gridPos": {
"h": 1,
"w": 24,
"x": 0,
"y": 0
},
"id": -1,
"panels": [],
"title": "Tab1",
"type": "row"
},
{
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisBorderShow": false,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"barWidthFactor": 0.6,
"drawStyle": "line",
"fillOpacity": 0,
"gradientMode": "none",
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
},
"insertNulls": false,
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "auto",
"showValues": false,
"spanNulls": false,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
},
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": 0
},
{
"color": "red",
"value": 80
}
]
}
}
},
"gridPos": {
"h": 8,
"w": 7,
"x": 0,
"y": 1
},
"id": 1,
"options": {
"legend": {
"calcs": [],
"displayMode": "list",
"placement": "bottom",
"showLegend": true
},
"tooltip": {
"hideZeros": false,
"mode": "single",
"sort": "none"
}
},
"pluginVersion": "12.4.0-pre",
"targets": [
{
"datasource": {
"type": "grafana-testdata-datasource",
"uid": "PD8C576611E62080A"
},
"refId": "A"
}
],
"title": "Panel1",
"type": "timeseries"
},
{
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisBorderShow": false,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"barWidthFactor": 0.6,
"drawStyle": "line",
"fillOpacity": 0,
"gradientMode": "none",
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
},
"insertNulls": false,
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "auto",
"showValues": false,
"spanNulls": false,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
},
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": 0
},
{
"color": "red",
"value": 80
}
]
}
}
},
"gridPos": {
"h": 8,
"w": 8,
"x": 7,
"y": 1
},
"id": 2,
"options": {
"legend": {
"calcs": [],
"displayMode": "list",
"placement": "bottom",
"showLegend": true
},
"tooltip": {
"hideZeros": false,
"mode": "single",
"sort": "none"
}
},
"pluginVersion": "12.4.0-pre",
"targets": [
{
"refId": "A"
}
],
"title": "Panel2",
"type": "timeseries"
},
{
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisBorderShow": false,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"barWidthFactor": 0.6,
"drawStyle": "line",
"fillOpacity": 0,
"gradientMode": "none",
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
},
"insertNulls": false,
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "auto",
"showValues": false,
"spanNulls": false,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
},
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": 0
},
{
"color": "red",
"value": 80
}
]
}
}
},
"gridPos": {
"h": 8,
"w": 9,
"x": 15,
"y": 1
},
"id": 3,
"options": {
"legend": {
"calcs": [],
"displayMode": "list",
"placement": "bottom",
"showLegend": true
},
"tooltip": {
"hideZeros": false,
"mode": "single",
"sort": "none"
}
},
"pluginVersion": "12.4.0-pre",
"targets": [
{
"refId": "A"
}
],
"title": "Panel3",
"type": "timeseries"
},
{
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisBorderShow": false,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"barWidthFactor": 0.6,
"drawStyle": "line",
"fillOpacity": 0,
"gradientMode": "none",
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
},
"insertNulls": false,
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "auto",
"showValues": false,
"spanNulls": false,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
},
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": 0
},
{
"color": "red",
"value": 80
}
]
}
}
},
"gridPos": {
"h": 8,
"w": 12,
"x": 0,
"y": 9
},
"id": 4,
"options": {
"legend": {
"calcs": [],
"displayMode": "list",
"placement": "bottom",
"showLegend": true
},
"tooltip": {
"hideZeros": false,
"mode": "single",
"sort": "none"
}
},
"pluginVersion": "12.4.0-pre",
"targets": [
{
"refId": "A"
}
],
"title": "Panel4",
"type": "timeseries"
},
{
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisBorderShow": false,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"barWidthFactor": 0.6,
"drawStyle": "line",
"fillOpacity": 0,
"gradientMode": "none",
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
},
"insertNulls": false,
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "auto",
"showValues": false,
"spanNulls": false,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
},
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": 0
},
{
"color": "red",
"value": 80
}
]
}
}
},
"gridPos": {
"h": 8,
"w": 12,
"x": 12,
"y": 9
},
"id": 5,
"options": {
"legend": {
"calcs": [],
"displayMode": "list",
"placement": "bottom",
"showLegend": true
},
"tooltip": {
"hideZeros": false,
"mode": "single",
"sort": "none"
}
},
"pluginVersion": "12.4.0-pre",
"targets": [
{
"refId": "A"
}
],
"title": "Panel5",
"type": "timeseries"
}
],
"preload": false,
"refresh": "",
"schemaVersion": 42,
"time": {
"from": "now-6h",
"to": "now"
},
"timepicker": {
"refresh_intervals": [
"5s",
"10s",
"30s",
"1m",
"5m",
"15m",
"30m",
"1h",
"2h",
"1d"
]
},
"timezone": "browser",
"title": "Dashboard with tabs"
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v2beta1"
}
}
}

View File

@@ -1,511 +0,0 @@
{
"kind": "DashboardWithAccessInfo",
"apiVersion": "dashboard.grafana.app/v1beta1",
"metadata": {
"name": "adt885j",
"namespace": "default",
"uid": "yTWet6JgBjlRIWnqRE9ZOmUycfT0tEkr2mljaln1GWIX",
"resourceVersion": "2",
"generation": 2,
"creationTimestamp": "2025-12-16T10:44:31Z",
"labels": {
"grafana.app/deprecatedInternalID": "2409"
},
"annotations": {
"grafana.app/createdBy": "user:u000000001",
"grafana.app/updatedBy": "user:u000000001",
"grafana.app/updatedTimestamp": "2025-12-16T10:51:14Z"
}
},
"spec": {
"annotations": {
"list": [
{
"builtIn": 1,
"datasource": {
"type": "grafana",
"uid": "-- Grafana --"
},
"enable": true,
"hide": true,
"iconColor": "rgba(0, 211, 255, 1)",
"name": "Annotations \u0026 Alerts",
"type": "dashboard"
}
]
},
"description": "",
"editable": true,
"fiscalYearStartMonth": 0,
"graphTooltip": 0,
"liveNow": false,
"panels": [
{
"collapsed": false,
"gridPos": {
"h": 1,
"w": 24,
"x": 0,
"y": 0
},
"id": -1,
"panels": [],
"title": "Tab1",
"type": "row"
},
{
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisBorderShow": false,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"barWidthFactor": 0.6,
"drawStyle": "line",
"fillOpacity": 0,
"gradientMode": "none",
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
},
"insertNulls": false,
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "auto",
"showValues": false,
"spanNulls": false,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
},
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": 0
},
{
"color": "red",
"value": 80
}
]
}
}
},
"gridPos": {
"h": 8,
"w": 7,
"x": 0,
"y": 1
},
"id": 1,
"options": {
"legend": {
"calcs": [],
"displayMode": "list",
"placement": "bottom",
"showLegend": true
},
"tooltip": {
"hideZeros": false,
"mode": "single",
"sort": "none"
}
},
"pluginVersion": "12.4.0-pre",
"targets": [
{
"datasource": {
"type": "grafana-testdata-datasource",
"uid": "PD8C576611E62080A"
},
"refId": "A"
}
],
"title": "Panel1",
"type": "timeseries"
},
{
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisBorderShow": false,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"barWidthFactor": 0.6,
"drawStyle": "line",
"fillOpacity": 0,
"gradientMode": "none",
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
},
"insertNulls": false,
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "auto",
"showValues": false,
"spanNulls": false,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
},
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": 0
},
{
"color": "red",
"value": 80
}
]
}
}
},
"gridPos": {
"h": 8,
"w": 8,
"x": 7,
"y": 1
},
"id": 2,
"options": {
"legend": {
"calcs": [],
"displayMode": "list",
"placement": "bottom",
"showLegend": true
},
"tooltip": {
"hideZeros": false,
"mode": "single",
"sort": "none"
}
},
"pluginVersion": "12.4.0-pre",
"targets": [
{
"refId": "A"
}
],
"title": "Panel2",
"type": "timeseries"
},
{
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisBorderShow": false,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"barWidthFactor": 0.6,
"drawStyle": "line",
"fillOpacity": 0,
"gradientMode": "none",
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
},
"insertNulls": false,
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "auto",
"showValues": false,
"spanNulls": false,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
},
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": 0
},
{
"color": "red",
"value": 80
}
]
}
}
},
"gridPos": {
"h": 8,
"w": 9,
"x": 15,
"y": 1
},
"id": 3,
"options": {
"legend": {
"calcs": [],
"displayMode": "list",
"placement": "bottom",
"showLegend": true
},
"tooltip": {
"hideZeros": false,
"mode": "single",
"sort": "none"
}
},
"pluginVersion": "12.4.0-pre",
"targets": [
{
"refId": "A"
}
],
"title": "Panel3",
"type": "timeseries"
},
{
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisBorderShow": false,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"barWidthFactor": 0.6,
"drawStyle": "line",
"fillOpacity": 0,
"gradientMode": "none",
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
},
"insertNulls": false,
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "auto",
"showValues": false,
"spanNulls": false,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
},
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": 0
},
{
"color": "red",
"value": 80
}
]
}
}
},
"gridPos": {
"h": 8,
"w": 12,
"x": 0,
"y": 9
},
"id": 4,
"options": {
"legend": {
"calcs": [],
"displayMode": "list",
"placement": "bottom",
"showLegend": true
},
"tooltip": {
"hideZeros": false,
"mode": "single",
"sort": "none"
}
},
"pluginVersion": "12.4.0-pre",
"targets": [
{
"refId": "A"
}
],
"title": "Panel4",
"type": "timeseries"
},
{
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisBorderShow": false,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"barWidthFactor": 0.6,
"drawStyle": "line",
"fillOpacity": 0,
"gradientMode": "none",
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
},
"insertNulls": false,
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "auto",
"showValues": false,
"spanNulls": false,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
},
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": 0
},
{
"color": "red",
"value": 80
}
]
}
}
},
"gridPos": {
"h": 8,
"w": 12,
"x": 12,
"y": 9
},
"id": 5,
"options": {
"legend": {
"calcs": [],
"displayMode": "list",
"placement": "bottom",
"showLegend": true
},
"tooltip": {
"hideZeros": false,
"mode": "single",
"sort": "none"
}
},
"pluginVersion": "12.4.0-pre",
"targets": [
{
"refId": "A"
}
],
"title": "Panel5",
"type": "timeseries"
}
],
"preload": false,
"refresh": "",
"schemaVersion": 42,
"time": {
"from": "now-6h",
"to": "now"
},
"timepicker": {
"refresh_intervals": [
"5s",
"10s",
"30s",
"1m",
"5m",
"15m",
"30m",
"1h",
"2h",
"1d"
]
},
"timezone": "browser",
"title": "Dashboard with tabs"
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v2beta1"
}
}
}

View File

@@ -1,683 +0,0 @@
{
"kind": "DashboardWithAccessInfo",
"apiVersion": "dashboard.grafana.app/v2alpha1",
"metadata": {
"name": "adt885j",
"namespace": "default",
"uid": "yTWet6JgBjlRIWnqRE9ZOmUycfT0tEkr2mljaln1GWIX",
"resourceVersion": "2",
"generation": 2,
"creationTimestamp": "2025-12-16T10:44:31Z",
"labels": {
"grafana.app/deprecatedInternalID": "2409"
},
"annotations": {
"grafana.app/createdBy": "user:u000000001",
"grafana.app/updatedBy": "user:u000000001",
"grafana.app/updatedTimestamp": "2025-12-16T10:51:14Z"
}
},
"spec": {
"annotations": [
{
"kind": "AnnotationQuery",
"spec": {
"datasource": {
"type": "grafana",
"uid": "-- Grafana --"
},
"query": {
"kind": "grafana",
"spec": {}
},
"enable": true,
"hide": true,
"iconColor": "rgba(0, 211, 255, 1)",
"name": "Annotations \u0026 Alerts",
"builtIn": true
}
}
],
"cursorSync": "Off",
"description": "",
"editable": true,
"elements": {
"panel-1": {
"kind": "Panel",
"spec": {
"id": 1,
"title": "Panel1",
"description": "",
"links": [],
"data": {
"kind": "QueryGroup",
"spec": {
"queries": [
{
"kind": "PanelQuery",
"spec": {
"query": {
"kind": "grafana-testdata-datasource",
"spec": {}
},
"datasource": {
"type": "grafana-testdata-datasource",
"uid": "PD8C576611E62080A"
},
"refId": "A",
"hidden": false
}
}
],
"transformations": [],
"queryOptions": {}
}
},
"vizConfig": {
"kind": "timeseries",
"spec": {
"pluginVersion": "12.4.0-pre",
"options": {
"legend": {
"calcs": [],
"displayMode": "list",
"placement": "bottom",
"showLegend": true
},
"tooltip": {
"hideZeros": false,
"mode": "single",
"sort": "none"
}
},
"fieldConfig": {
"defaults": {
"thresholds": {
"mode": "absolute",
"steps": [
{
"value": 0,
"color": "green"
},
{
"value": 80,
"color": "red"
}
]
},
"color": {
"mode": "palette-classic"
},
"custom": {
"axisBorderShow": false,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"barWidthFactor": 0.6,
"drawStyle": "line",
"fillOpacity": 0,
"gradientMode": "none",
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
},
"insertNulls": false,
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "auto",
"showValues": false,
"spanNulls": false,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
}
},
"overrides": []
}
}
}
}
},
"panel-2": {
"kind": "Panel",
"spec": {
"id": 2,
"title": "Panel2",
"description": "",
"links": [],
"data": {
"kind": "QueryGroup",
"spec": {
"queries": [
{
"kind": "PanelQuery",
"spec": {
"query": {
"kind": "",
"spec": {}
},
"refId": "A",
"hidden": false
}
}
],
"transformations": [],
"queryOptions": {}
}
},
"vizConfig": {
"kind": "timeseries",
"spec": {
"pluginVersion": "12.4.0-pre",
"options": {
"legend": {
"calcs": [],
"displayMode": "list",
"placement": "bottom",
"showLegend": true
},
"tooltip": {
"hideZeros": false,
"mode": "single",
"sort": "none"
}
},
"fieldConfig": {
"defaults": {
"thresholds": {
"mode": "absolute",
"steps": [
{
"value": 0,
"color": "green"
},
{
"value": 80,
"color": "red"
}
]
},
"color": {
"mode": "palette-classic"
},
"custom": {
"axisBorderShow": false,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"barWidthFactor": 0.6,
"drawStyle": "line",
"fillOpacity": 0,
"gradientMode": "none",
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
},
"insertNulls": false,
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "auto",
"showValues": false,
"spanNulls": false,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
}
},
"overrides": []
}
}
}
}
},
"panel-3": {
"kind": "Panel",
"spec": {
"id": 3,
"title": "Panel3",
"description": "",
"links": [],
"data": {
"kind": "QueryGroup",
"spec": {
"queries": [
{
"kind": "PanelQuery",
"spec": {
"query": {
"kind": "",
"spec": {}
},
"refId": "A",
"hidden": false
}
}
],
"transformations": [],
"queryOptions": {}
}
},
"vizConfig": {
"kind": "timeseries",
"spec": {
"pluginVersion": "12.4.0-pre",
"options": {
"legend": {
"calcs": [],
"displayMode": "list",
"placement": "bottom",
"showLegend": true
},
"tooltip": {
"hideZeros": false,
"mode": "single",
"sort": "none"
}
},
"fieldConfig": {
"defaults": {
"thresholds": {
"mode": "absolute",
"steps": [
{
"value": 0,
"color": "green"
},
{
"value": 80,
"color": "red"
}
]
},
"color": {
"mode": "palette-classic"
},
"custom": {
"axisBorderShow": false,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"barWidthFactor": 0.6,
"drawStyle": "line",
"fillOpacity": 0,
"gradientMode": "none",
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
},
"insertNulls": false,
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "auto",
"showValues": false,
"spanNulls": false,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
}
},
"overrides": []
}
}
}
}
},
"panel-4": {
"kind": "Panel",
"spec": {
"id": 4,
"title": "Panel4",
"description": "",
"links": [],
"data": {
"kind": "QueryGroup",
"spec": {
"queries": [
{
"kind": "PanelQuery",
"spec": {
"query": {
"kind": "",
"spec": {}
},
"refId": "A",
"hidden": false
}
}
],
"transformations": [],
"queryOptions": {}
}
},
"vizConfig": {
"kind": "timeseries",
"spec": {
"pluginVersion": "12.4.0-pre",
"options": {
"legend": {
"calcs": [],
"displayMode": "list",
"placement": "bottom",
"showLegend": true
},
"tooltip": {
"hideZeros": false,
"mode": "single",
"sort": "none"
}
},
"fieldConfig": {
"defaults": {
"thresholds": {
"mode": "absolute",
"steps": [
{
"value": 0,
"color": "green"
},
{
"value": 80,
"color": "red"
}
]
},
"color": {
"mode": "palette-classic"
},
"custom": {
"axisBorderShow": false,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"barWidthFactor": 0.6,
"drawStyle": "line",
"fillOpacity": 0,
"gradientMode": "none",
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
},
"insertNulls": false,
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "auto",
"showValues": false,
"spanNulls": false,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
}
},
"overrides": []
}
}
}
}
},
"panel-5": {
"kind": "Panel",
"spec": {
"id": 5,
"title": "Panel5",
"description": "",
"links": [],
"data": {
"kind": "QueryGroup",
"spec": {
"queries": [
{
"kind": "PanelQuery",
"spec": {
"query": {
"kind": "",
"spec": {}
},
"refId": "A",
"hidden": false
}
}
],
"transformations": [],
"queryOptions": {}
}
},
"vizConfig": {
"kind": "timeseries",
"spec": {
"pluginVersion": "12.4.0-pre",
"options": {
"legend": {
"calcs": [],
"displayMode": "list",
"placement": "bottom",
"showLegend": true
},
"tooltip": {
"hideZeros": false,
"mode": "single",
"sort": "none"
}
},
"fieldConfig": {
"defaults": {
"thresholds": {
"mode": "absolute",
"steps": [
{
"value": 0,
"color": "green"
},
{
"value": 80,
"color": "red"
}
]
},
"color": {
"mode": "palette-classic"
},
"custom": {
"axisBorderShow": false,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"barWidthFactor": 0.6,
"drawStyle": "line",
"fillOpacity": 0,
"gradientMode": "none",
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
},
"insertNulls": false,
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "auto",
"showValues": false,
"spanNulls": false,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
}
},
"overrides": []
}
}
}
}
}
},
"layout": {
"kind": "TabsLayout",
"spec": {
"tabs": [
{
"kind": "TabsLayoutTab",
"spec": {
"title": "Tab1",
"layout": {
"kind": "GridLayout",
"spec": {
"items": [
{
"kind": "GridLayoutItem",
"spec": {
"x": 0,
"y": 0,
"width": 7,
"height": 8,
"element": {
"kind": "ElementReference",
"name": "panel-1"
}
}
},
{
"kind": "GridLayoutItem",
"spec": {
"x": 7,
"y": 0,
"width": 8,
"height": 8,
"element": {
"kind": "ElementReference",
"name": "panel-2"
}
}
},
{
"kind": "GridLayoutItem",
"spec": {
"x": 15,
"y": 0,
"width": 9,
"height": 8,
"element": {
"kind": "ElementReference",
"name": "panel-3"
}
}
},
{
"kind": "GridLayoutItem",
"spec": {
"x": 0,
"y": 8,
"width": 12,
"height": 8,
"element": {
"kind": "ElementReference",
"name": "panel-4"
}
}
},
{
"kind": "GridLayoutItem",
"spec": {
"x": 12,
"y": 8,
"width": 12,
"height": 8,
"element": {
"kind": "ElementReference",
"name": "panel-5"
}
}
}
]
}
}
}
}
]
}
},
"links": [],
"liveNow": false,
"preload": false,
"tags": [],
"timeSettings": {
"timezone": "browser",
"from": "now-6h",
"to": "now",
"autoRefresh": "",
"autoRefreshIntervals": [
"5s",
"10s",
"30s",
"1m",
"5m",
"15m",
"30m",
"1h",
"2h",
"1d"
],
"hideTimepicker": false,
"fiscalYearStartMonth": 0
},
"title": "Dashboard with tabs",
"variables": []
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v2beta1"
}
}
}

View File

@@ -501,9 +501,11 @@ func convertToRowsLayout(ctx context.Context, panels []interface{}, dsIndexProvi
if currentRow != nil {
// If currentRow is a hidden-header row (panels before first explicit row),
// it should not be collapsed because it will disappear and be visible only in edit mode
// set its collapse to match the first explicit row's collapsed value
// This matches frontend behavior: collapse: panel.collapsed
if currentRow.Spec.HideHeader != nil && *currentRow.Spec.HideHeader {
currentRow.Spec.Collapse = &[]bool{false}[0]
rowCollapsed := getBoolField(panelMap, "collapsed", false)
currentRow.Spec.Collapse = &rowCollapsed
}
// Flush current row to layout
rows = append(rows, *currentRow)
@@ -2020,9 +2022,6 @@ func transformPanelQueries(ctx context.Context, panelMap map[string]interface{},
func transformSingleQuery(ctx context.Context, targetMap map[string]interface{}, panelDatasource *dashv2alpha1.DashboardDataSourceRef, dsIndexProvider schemaversion.DataSourceIndexProvider) dashv2alpha1.DashboardPanelQueryKind {
refId := schemaversion.GetStringValue(targetMap, "refId", "A")
if refId == "" {
refId = "A"
}
hidden := getBoolField(targetMap, "hide", false)
// Extract datasource from query or use panel datasource
@@ -2519,15 +2518,22 @@ func buildRegexMap(mappingMap map[string]interface{}) *dashv2alpha1.DashboardReg
regexMap := &dashv2alpha1.DashboardRegexMap{}
regexMap.Type = dashv2alpha1.DashboardMappingTypeRegex
optMap, ok := mappingMap["options"].(map[string]interface{})
opts, ok := mappingMap["options"].([]interface{})
if !ok || len(opts) == 0 {
return nil
}
optMap, ok := opts[0].(map[string]interface{})
if !ok {
return nil
}
r := dashv2alpha1.DashboardV2alpha1RegexMapOptions{}
if pattern, ok := optMap["pattern"].(string); ok {
if pattern, ok := optMap["regex"].(string); ok {
r.Pattern = pattern
}
// Result is a DashboardValueMappingResult
if resMap, ok := optMap["result"].(map[string]interface{}); ok {
r.Result = buildValueMappingResult(resMap)
}

View File

@@ -495,9 +495,6 @@ func processTabItem(elements map[string]dashv2alpha1.DashboardElement, tab *dash
currentY = getMaxYFromPanels(nestedPanels, currentY)
} else if tab.Spec.Layout.GridLayoutKind != nil {
// GridLayout inside tab
baseY := currentY
maxY := currentY
for _, item := range tab.Spec.Layout.GridLayoutKind.Spec.Items {
element, ok := elements[item.Spec.Element.Name]
if !ok {
@@ -505,7 +502,7 @@ func processTabItem(elements map[string]dashv2alpha1.DashboardElement, tab *dash
}
adjustedItem := item
adjustedItem.Spec.Y = item.Spec.Y + baseY
adjustedItem.Spec.Y = item.Spec.Y + currentY
panel, err := convertPanelFromElement(&element, &adjustedItem)
if err != nil {
@@ -514,12 +511,10 @@ func processTabItem(elements map[string]dashv2alpha1.DashboardElement, tab *dash
panels = append(panels, panel)
panelEndY := adjustedItem.Spec.Y + item.Spec.Height
if panelEndY > maxY {
maxY = panelEndY
if panelEndY > currentY {
currentY = panelEndY
}
}
currentY = maxY
} else if tab.Spec.Layout.AutoGridLayoutKind != nil {
// AutoGridLayout inside tab - convert with Y offset
autoGridPanels, err := convertAutoGridLayoutToPanelsWithOffset(elements, tab.Spec.Layout.AutoGridLayoutKind, currentY)

View File

@@ -5,11 +5,12 @@ import (
"sync"
"time"
"github.com/hashicorp/golang-lru/v2/expirable"
"k8s.io/apiserver/pkg/endpoints/request"
"github.com/grafana/authlib/types"
"github.com/grafana/grafana-app-sdk/logging"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/hashicorp/golang-lru/v2/expirable"
k8srequest "k8s.io/apiserver/pkg/endpoints/request"
"github.com/grafana/grafana/pkg/services/apiserver/endpoints/request"
)
const defaultCacheSize = 1000
@@ -31,15 +32,17 @@ type cachedProvider[T any] struct {
fetch func(context.Context) T
cache *expirable.LRU[string, T] // LRU cache: namespace to cache entry
inFlight sync.Map // map[string]*sync.Mutex - per-namespace fetch locks
logger log.Logger
}
// newCachedProvider creates a new cachedProvider.
// The fetch function should be able to handle context with different namespaces.
// A non-positive size turns LRU mechanism off (cache of unlimited size).
// A non-positive cacheTTL disables TTL expiration.
func newCachedProvider[T any](fetch func(context.Context) T, size int, cacheTTL time.Duration) *cachedProvider[T] {
func newCachedProvider[T any](fetch func(context.Context) T, size int, cacheTTL time.Duration, logger log.Logger) *cachedProvider[T] {
cacheProvider := &cachedProvider[T]{
fetch: fetch,
fetch: fetch,
logger: logger,
}
cacheProvider.cache = expirable.NewLRU(size, func(key string, value T) {
cacheProvider.inFlight.Delete(key)
@@ -50,13 +53,14 @@ func newCachedProvider[T any](fetch func(context.Context) T, size int, cacheTTL
// Get returns the cached value if it's still valid, otherwise calls fetch and caches the result.
func (p *cachedProvider[T]) Get(ctx context.Context) T {
// Get namespace info from ctx
namespace, ok := request.NamespaceFrom(ctx)
if !ok {
nsInfo, err := request.NamespaceInfoFrom(ctx, true)
if err != nil {
// No namespace, fall back to direct fetch call without caching
logging.FromContext(ctx).Warn("Unable to get namespace info from context, skipping cache")
p.logger.Warn("Unable to get namespace info from context, skipping cache", "error", err)
return p.fetch(ctx)
}
namespace := nsInfo.Value
// Fast path: check if cache is still valid
if entry, ok := p.cache.Get(namespace); ok {
return entry
@@ -77,7 +81,7 @@ func (p *cachedProvider[T]) Get(ctx context.Context) T {
}
// Fetch outside the main lock - only this namespace is blocked
logging.FromContext(ctx).Debug("cache miss or expired, fetching new value", "namespace", namespace)
p.logger.Debug("cache miss or expired, fetching new value", "namespace", namespace)
value := p.fetch(ctx)
// Update the cache for this namespace
@@ -89,12 +93,12 @@ func (p *cachedProvider[T]) Get(ctx context.Context) T {
// Preload loads data into the cache for the given namespaces.
func (p *cachedProvider[T]) Preload(ctx context.Context, nsInfos []types.NamespaceInfo) {
// Build the cache using a context with the namespace
logging.FromContext(ctx).Info("preloading cache", "nsInfos", len(nsInfos))
p.logger.Info("preloading cache", "nsInfos", len(nsInfos))
startedAt := time.Now()
defer func() {
logging.FromContext(ctx).Info("finished preloading cache", "nsInfos", len(nsInfos), "elapsed", time.Since(startedAt))
p.logger.Info("finished preloading cache", "nsInfos", len(nsInfos), "elapsed", time.Since(startedAt))
}()
for _, nsInfo := range nsInfos {
p.cache.Add(nsInfo.Value, p.fetch(request.WithNamespace(ctx, nsInfo.Value)))
p.cache.Add(nsInfo.Value, p.fetch(k8srequest.WithNamespace(ctx, nsInfo.Value)))
}
}

View File

@@ -8,11 +8,11 @@ import (
"testing"
"time"
authlib "github.com/grafana/authlib/types"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"k8s.io/apiserver/pkg/endpoints/request"
authlib "github.com/grafana/authlib/types"
)
// testProvider tracks how many times get() is called
@@ -44,7 +44,7 @@ func TestCachedProvider_CacheHit(t *testing.T) {
underlying := newTestProvider(datasources)
// Test newCachedProvider directly instead of the wrapper
cached := newCachedProvider(underlying.get, defaultCacheSize, time.Minute)
cached := newCachedProvider(underlying.get, defaultCacheSize, time.Minute, log.New("test"))
// Use "default" namespace (org 1) - this is the standard Grafana namespace format
ctx := request.WithNamespace(context.Background(), "default")
@@ -69,7 +69,7 @@ func TestCachedProvider_NamespaceIsolation(t *testing.T) {
}
underlying := newTestProvider(datasources)
cached := newCachedProvider(underlying.get, defaultCacheSize, time.Minute)
cached := newCachedProvider(underlying.get, defaultCacheSize, time.Minute, log.New("test"))
// Use "default" (org 1) and "org-2" (org 2) - standard Grafana namespace formats
ctx1 := request.WithNamespace(context.Background(), "default")
@@ -102,7 +102,7 @@ func TestCachedProvider_NoNamespaceFallback(t *testing.T) {
}
underlying := newTestProvider(datasources)
cached := newCachedProvider(underlying.get, defaultCacheSize, time.Minute)
cached := newCachedProvider(underlying.get, defaultCacheSize, time.Minute, log.New("test"))
// Context without namespace - should fall back to direct provider call
ctx := context.Background()
@@ -123,7 +123,7 @@ func TestCachedProvider_ConcurrentAccess(t *testing.T) {
}
underlying := newTestProvider(datasources)
cached := newCachedProvider(underlying.get, defaultCacheSize, time.Minute)
cached := newCachedProvider(underlying.get, defaultCacheSize, time.Minute, log.New("test"))
// Use "default" namespace (org 1)
ctx := request.WithNamespace(context.Background(), "default")
@@ -155,7 +155,7 @@ func TestCachedProvider_ConcurrentNamespaces(t *testing.T) {
}
underlying := newTestProvider(datasources)
cached := newCachedProvider(underlying.get, defaultCacheSize, time.Minute)
cached := newCachedProvider(underlying.get, defaultCacheSize, time.Minute, log.New("test"))
var wg sync.WaitGroup
numOrgs := 10
@@ -198,7 +198,7 @@ func TestCachedProvider_CorrectDataPerNamespace(t *testing.T) {
"org-2": {{UID: "org2-ds", Type: "loki", Name: "Org2 DS", Default: true}},
},
}
cached := newCachedProvider(underlying.Index, defaultCacheSize, time.Minute)
cached := newCachedProvider(underlying.Index, defaultCacheSize, time.Minute, log.New("test"))
// Use valid namespace formats
ctx1 := request.WithNamespace(context.Background(), "default")
@@ -228,7 +228,7 @@ func TestCachedProvider_PreloadMultipleNamespaces(t *testing.T) {
"org-3": {{UID: "org3-ds", Type: "tempo", Name: "Org3 DS", Default: true}},
},
}
cached := newCachedProvider(underlying.Index, defaultCacheSize, time.Minute)
cached := newCachedProvider(underlying.Index, defaultCacheSize, time.Minute, log.New("test"))
// Preload multiple namespaces
nsInfos := []authlib.NamespaceInfo{
@@ -346,7 +346,7 @@ func TestCachedProvider_TTLExpiration(t *testing.T) {
underlying := newTestProvider(datasources)
// Use a very short TTL for testing
shortTTL := 50 * time.Millisecond
cached := newCachedProvider(underlying.get, defaultCacheSize, shortTTL)
cached := newCachedProvider(underlying.get, defaultCacheSize, shortTTL, log.New("test"))
ctx := request.WithNamespace(context.Background(), "default")
@@ -379,7 +379,7 @@ func TestCachedProvider_ParallelNamespacesFetch(t *testing.T) {
{UID: "ds1", Type: "prometheus", Name: "Prometheus", Default: true},
},
}
cached := newCachedProvider(provider.get, defaultCacheSize, time.Minute)
cached := newCachedProvider(provider.get, defaultCacheSize, time.Minute, log.New("test"))
numNamespaces := 5
var wg sync.WaitGroup
@@ -421,7 +421,7 @@ func TestCachedProvider_SameNamespaceSerialFetch(t *testing.T) {
{UID: "ds1", Type: "prometheus", Name: "Prometheus", Default: true},
},
}
cached := newCachedProvider(provider.get, defaultCacheSize, time.Minute)
cached := newCachedProvider(provider.get, defaultCacheSize, time.Minute, log.New("test"))
numGoroutines := 10
var wg sync.WaitGroup

View File

@@ -3,6 +3,8 @@ package schemaversion
import (
"context"
"time"
"github.com/grafana/grafana/pkg/infra/log"
)
// Shared utility functions for datasource migrations across different schema versions.
@@ -34,7 +36,7 @@ func WrapIndexProviderWithCache(provider DataSourceIndexProvider, cacheTTL time.
return provider
}
return &cachedIndexProvider{
newCachedProvider[*DatasourceIndex](provider.Index, defaultCacheSize, cacheTTL),
newCachedProvider[*DatasourceIndex](provider.Index, defaultCacheSize, cacheTTL, log.New("schemaversion.dsindexprovider")),
}
}
@@ -44,7 +46,7 @@ func WrapLibraryElementProviderWithCache(provider LibraryElementIndexProvider, c
return provider
}
return &cachedLibraryElementProvider{
newCachedProvider[[]LibraryElementInfo](provider.GetLibraryElementInfo, defaultCacheSize, cacheTTL),
newCachedProvider[[]LibraryElementInfo](provider.GetLibraryElementInfo, defaultCacheSize, cacheTTL, log.New("schemaversion.leindexprovider")),
}
}

View File

@@ -75,9 +75,9 @@
"effects": {
"barGlow": false,
"centerGlow": false,
"gradient": false,
"rounded": true,
"spotlight": false
"spotlight": false,
"gradient": false
},
"orientation": "auto",
"reduceOptions": {
@@ -154,9 +154,9 @@
"effects": {
"barGlow": false,
"centerGlow": true,
"gradient": false,
"rounded": true,
"spotlight": false
"spotlight": false,
"gradient": false
},
"orientation": "auto",
"reduceOptions": {
@@ -233,9 +233,9 @@
"effects": {
"barGlow": true,
"centerGlow": true,
"gradient": false,
"rounded": true,
"spotlight": false
"spotlight": false,
"gradient": false
},
"orientation": "auto",
"reduceOptions": {
@@ -312,9 +312,9 @@
"effects": {
"barGlow": true,
"centerGlow": true,
"gradient": false,
"rounded": true,
"spotlight": true
"spotlight": true,
"gradient": false
},
"orientation": "auto",
"reduceOptions": {
@@ -391,9 +391,9 @@
"effects": {
"barGlow": true,
"centerGlow": true,
"gradient": false,
"rounded": true,
"spotlight": true
"spotlight": true,
"gradient": false
},
"orientation": "auto",
"reduceOptions": {
@@ -470,9 +470,9 @@
"effects": {
"barGlow": true,
"centerGlow": true,
"gradient": false,
"rounded": false,
"spotlight": true
"spotlight": true,
"gradient": false
},
"orientation": "auto",
"reduceOptions": {
@@ -549,9 +549,9 @@
"effects": {
"barGlow": true,
"centerGlow": true,
"gradient": false,
"rounded": false,
"spotlight": true
"spotlight": true,
"gradient": false
},
"orientation": "auto",
"reduceOptions": {
@@ -641,9 +641,9 @@
"effects": {
"barGlow": true,
"centerGlow": true,
"gradient": false,
"rounded": true,
"spotlight": true
"spotlight": true,
"gradient": false
},
"orientation": "auto",
"reduceOptions": {
@@ -720,9 +720,9 @@
"effects": {
"barGlow": true,
"centerGlow": true,
"gradient": false,
"rounded": true,
"spotlight": true
"spotlight": true,
"gradient": false
},
"orientation": "auto",
"reduceOptions": {
@@ -799,9 +799,9 @@
"effects": {
"barGlow": true,
"centerGlow": true,
"gradient": false,
"rounded": true,
"spotlight": true
"spotlight": true,
"gradient": false
},
"orientation": "auto",
"reduceOptions": {
@@ -878,9 +878,9 @@
"effects": {
"barGlow": true,
"centerGlow": true,
"gradient": false,
"rounded": true,
"spotlight": true
"spotlight": true,
"gradient": false
},
"orientation": "auto",
"reduceOptions": {
@@ -974,9 +974,9 @@
"effects": {
"barGlow": false,
"centerGlow": false,
"gradient": false,
"rounded": false,
"spotlight": false
"spotlight": false,
"gradient": false
},
"orientation": "auto",
"reduceOptions": {
@@ -1053,9 +1053,9 @@
"effects": {
"barGlow": false,
"centerGlow": false,
"gradient": false,
"rounded": false,
"spotlight": false
"spotlight": false,
"gradient": false
},
"orientation": "auto",
"reduceOptions": {
@@ -1132,9 +1132,9 @@
"effects": {
"barGlow": false,
"centerGlow": false,
"gradient": true,
"rounded": false,
"spotlight": false
"spotlight": false,
"gradient": true
},
"orientation": "auto",
"reduceOptions": {
@@ -1211,9 +1211,9 @@
"effects": {
"barGlow": false,
"centerGlow": false,
"gradient": false,
"rounded": false,
"spotlight": false
"spotlight": false,
"gradient": false
},
"orientation": "auto",
"reduceOptions": {
@@ -1290,9 +1290,9 @@
"effects": {
"barGlow": false,
"centerGlow": false,
"gradient": false,
"rounded": false,
"spotlight": false
"spotlight": false,
"gradient": false
},
"orientation": "auto",
"reduceOptions": {
@@ -1386,9 +1386,9 @@
"effects": {
"barGlow": false,
"centerGlow": false,
"gradient": true,
"rounded": false,
"spotlight": false
"spotlight": false,
"gradient": true
},
"orientation": "auto",
"reduceOptions": {
@@ -1469,9 +1469,9 @@
"effects": {
"barGlow": false,
"centerGlow": false,
"gradient": true,
"rounded": false,
"spotlight": false
"spotlight": false,
"gradient": true
},
"orientation": "auto",
"reduceOptions": {
@@ -1552,9 +1552,9 @@
"effects": {
"barGlow": false,
"centerGlow": false,
"gradient": true,
"rounded": false,
"spotlight": false
"spotlight": false,
"gradient": true
},
"orientation": "auto",
"reduceOptions": {
@@ -1603,6 +1603,7 @@
"datasource": {
"type": "grafana-testdata-datasource"
},
"description": "",
"fieldConfig": {
"defaults": {
"color": {
@@ -1643,9 +1644,9 @@
"effects": {
"barGlow": true,
"centerGlow": true,
"gradient": true,
"rounded": true,
"spotlight": true
"spotlight": true,
"gradient": true
},
"glow": "both",
"orientation": "auto",
@@ -1670,6 +1671,7 @@
"datasource": {
"type": "grafana-testdata-datasource"
},
"hide": false,
"max": 98,
"min": 5,
"noise": 22,
@@ -1687,6 +1689,7 @@
"datasource": {
"type": "grafana-testdata-datasource"
},
"description": "",
"fieldConfig": {
"defaults": {
"color": {
@@ -1727,9 +1730,9 @@
"effects": {
"barGlow": true,
"centerGlow": true,
"gradient": true,
"rounded": true,
"spotlight": true
"spotlight": true,
"gradient": true
},
"glow": "both",
"orientation": "auto",
@@ -1754,6 +1757,7 @@
"datasource": {
"type": "grafana-testdata-datasource"
},
"hide": false,
"max": 98,
"min": 5,
"noise": 22,
@@ -1784,6 +1788,7 @@
"datasource": {
"type": "grafana-testdata-datasource"
},
"description": "",
"fieldConfig": {
"defaults": {
"color": {
@@ -1825,9 +1830,9 @@
"effects": {
"barGlow": true,
"centerGlow": true,
"gradient": true,
"rounded": true,
"spotlight": true
"spotlight": true,
"gradient": true
},
"glow": "both",
"orientation": "auto",
@@ -1852,6 +1857,7 @@
"datasource": {
"type": "grafana-testdata-datasource"
},
"hide": false,
"max": 8,
"min": 1,
"noise": 2,
@@ -1869,6 +1875,7 @@
"datasource": {
"type": "grafana-testdata-datasource"
},
"description": "",
"fieldConfig": {
"defaults": {
"color": {
@@ -1910,9 +1917,9 @@
"effects": {
"barGlow": true,
"centerGlow": true,
"gradient": true,
"rounded": true,
"spotlight": true
"spotlight": true,
"gradient": true
},
"glow": "both",
"orientation": "auto",
@@ -1937,6 +1944,7 @@
"datasource": {
"type": "grafana-testdata-datasource"
},
"hide": false,
"max": 12,
"min": 1,
"noise": 2,
@@ -1954,6 +1962,7 @@
"datasource": {
"type": "grafana-testdata-datasource"
},
"description": "",
"fieldConfig": {
"defaults": {
"color": {
@@ -1994,9 +2003,9 @@
"effects": {
"barGlow": true,
"centerGlow": true,
"gradient": true,
"rounded": true,
"spotlight": true
"spotlight": true,
"gradient": true
},
"glow": "both",
"orientation": "auto",
@@ -2021,6 +2030,7 @@
"datasource": {
"type": "grafana-testdata-datasource"
},
"hide": false,
"max": 100,
"min": 10,
"noise": 22,
@@ -2038,6 +2048,7 @@
"datasource": {
"type": "grafana-testdata-datasource"
},
"description": "",
"fieldConfig": {
"defaults": {
"color": {
@@ -2078,9 +2089,9 @@
"effects": {
"barGlow": true,
"centerGlow": true,
"gradient": true,
"rounded": true,
"spotlight": true
"spotlight": true,
"gradient": true
},
"glow": "both",
"orientation": "auto",
@@ -2105,6 +2116,7 @@
"datasource": {
"type": "grafana-testdata-datasource"
},
"hide": false,
"max": 100,
"min": 10,
"noise": 22,
@@ -2117,151 +2129,6 @@
],
"title": "Backend",
"type": "radialbar"
},
{
"collapsed": false,
"gridPos": {
"h": 1,
"w": 24,
"x": 0,
"y": 66
},
"id": 35,
"panels": [],
"title": "Empty data",
"type": "row"
},
{
"datasource": {
"type": "grafana-testdata-datasource"
},
"fieldConfig": {
"defaults": {
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": 0
},
{
"color": "red",
"value": 80
}
]
}
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 6,
"x": 0,
"y": 67
},
"id": 36,
"options": {
"barWidthFactor": 0.5,
"effects": {
"barGlow": false,
"centerGlow": false,
"gradient": true,
"rounded": false,
"spotlight": false
},
"orientation": "auto",
"reduceOptions": {
"calcs": [
"lastNotNull"
],
"fields": "",
"values": false
},
"segmentCount": 1,
"segmentSpacing": 0.3,
"shape": "gauge",
"showThresholdLabels": false,
"showThresholdMarkers": true,
"sparkline": true
},
"pluginVersion": "13.0.0-pre",
"targets": [
{
"refId": "A",
"scenarioId": "random_walk",
"seriesCount": 0
}
],
"title": "Numeric, no series",
"type": "gauge"
},
{
"datasource": {
"type": "grafana-testdata-datasource"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "thresholds"
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": 0
},
{
"color": "red",
"value": 80
}
]
}
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 6,
"x": 6,
"y": 67
},
"id": 37,
"options": {
"barWidthFactor": 0.5,
"effects": {
"barGlow": false,
"centerGlow": false,
"gradient": true,
"rounded": false,
"spotlight": false
},
"orientation": "auto",
"reduceOptions": {
"calcs": [
"lastNotNull"
],
"fields": "",
"values": false
},
"segmentCount": 1,
"segmentSpacing": 0.3,
"shape": "gauge",
"showThresholdLabels": false,
"showThresholdMarkers": true,
"sparkline": true
},
"pluginVersion": "13.0.0-pre",
"targets": [
{
"refId": "A",
"scenarioId": "logs"
}
],
"title": "Non-numeric",
"type": "gauge"
}
],
"preload": false,
@@ -2279,4 +2146,4 @@
"title": "Panel tests - Gauge (new)",
"uid": "panel-tests-gauge-new",
"weekStart": ""
}
}

View File

@@ -955,9 +955,9 @@
"effects": {
"barGlow": false,
"centerGlow": false,
"gradient": false,
"rounded": false,
"spotlight": false
"spotlight": false,
"gradient": false
},
"orientation": "auto",
"reduceOptions": {
@@ -1162,4 +1162,4 @@
"title": "Panel tests - Old gauge to new",
"uid": "panel-tests-old-gauge-to-new",
"weekStart": ""
}
}

View File

@@ -8,6 +8,12 @@ foldersV1beta1: {
spec: {
title: string
description?: string
foo: bool
bar: int
}
}
}
selectableFields: [
"spec.title",
]
}

View File

@@ -5,13 +5,26 @@
package v1beta1
import (
"errors"
"github.com/grafana/grafana-app-sdk/resource"
)
// schema is unexported to prevent accidental overwrites
var (
schemaFolder = resource.NewSimpleSchema("folder.grafana.app", "v1beta1", NewFolder(), &FolderList{}, resource.WithKind("Folder"),
resource.WithPlural("folders"), resource.WithScope(resource.NamespacedScope))
resource.WithPlural("folders"), resource.WithScope(resource.NamespacedScope), resource.WithSelectableFields([]resource.SelectableField{resource.SelectableField{
FieldSelector: "spec.title",
FieldValueFunc: func(o resource.Object) (string, error) {
cast, ok := o.(*Folder)
if !ok {
return "", errors.New("provided object must be of type *Folder")
}
return cast.Spec.Title, nil
},
},
}))
kindFolder = resource.Kind{
Schema: schemaFolder,
Codecs: map[resource.KindEncoding]resource.Codec{

View File

@@ -18,6 +18,8 @@ import (
v1beta1 "github.com/grafana/grafana/apps/folder/pkg/apis/folder/v1beta1"
)
var ()
var appManifestData = app.ManifestData{
AppName: "folder",
Group: "folder.grafana.app",
@@ -32,6 +34,9 @@ var appManifestData = app.ManifestData{
Plural: "Folders",
Scope: "Namespaced",
Conversion: false,
SelectableFields: []string{
"spec.title",
},
},
},
Routes: app.ManifestVersionRoutes{

View File

@@ -221,7 +221,7 @@ require (
github.com/googleapis/enterprise-certificate-proxy v0.3.6 // indirect
github.com/googleapis/gax-go/v2 v2.15.0 // indirect
github.com/gorilla/mux v1.8.1 // indirect
github.com/grafana/alerting v0.0.0-20251212143239-491433b332b7 // indirect
github.com/grafana/alerting v0.0.0-20251204145817-de8c2bbf9eba // indirect
github.com/grafana/authlib v0.0.0-20250930082137-a40e2c2b094f // indirect
github.com/grafana/authlib/types v0.0.0-20251119142549-be091cf2f4d4 // indirect
github.com/grafana/dataplane/sdata v0.0.9 // indirect

View File

@@ -377,10 +377,10 @@ github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyY
github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM=
github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/centrifugal/centrifuge v0.38.0 h1:UJTowwc5lSwnpvd3vbrTseODbU7osSggN67RTrJ8EfQ=
github.com/centrifugal/centrifuge v0.38.0/go.mod h1:rcZLARnO5GXOeE9qG7iIPMvERxESespqkSX4cGLCAzo=
github.com/centrifugal/protocol v0.17.0 h1:hD0WczyiG7zrVJcgkQsd5/nhfFXt0Y04SJHV2Z7B1rg=
github.com/centrifugal/protocol v0.17.0/go.mod h1:9MdiYyjw5Bw1+d5Sp4Y0NK+qiuTNyd88nrHJsUUh8k4=
github.com/centrifugal/centrifuge v0.37.2 h1:rerQNvDfYN2FZEkVtb/hvGV7SIrJfEQrKF3MaE8GDlo=
github.com/centrifugal/centrifuge v0.37.2/go.mod h1:aj4iRJGhzi3SlL8iUtVezxway1Xf8g+hmNQkLLO7sS8=
github.com/centrifugal/protocol v0.16.2 h1:KoIHgDeX1fFxyxQoKW+6E8ZTCf5mwGm8JyGoJ5NBMbQ=
github.com/centrifugal/protocol v0.16.2/go.mod h1:Q7OpS/8HMXDnL7f9DpNx24IhG96MP88WPpVTTCdrokI=
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
@@ -817,8 +817,8 @@ github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 h1:JeSE6pjso5THxAzdVpqr6/geYxZytqFMBCOtn/ujyeo=
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674/go.mod h1:r4w70xmWCQKmi1ONH4KIaBptdivuRPyosB9RmPlGEwA=
github.com/grafana/alerting v0.0.0-20251212143239-491433b332b7 h1:ZzG/gCclEit9w0QUfQt9GURcOycAIGcsQAhY1u0AEX0=
github.com/grafana/alerting v0.0.0-20251212143239-491433b332b7/go.mod h1:l7v67cgP7x72ajB9UPZlumdrHqNztpKoqQ52cU8T3LU=
github.com/grafana/alerting v0.0.0-20251204145817-de8c2bbf9eba h1:psKWNETD5nGxmFAlqnWsXoRyUwSa2GHNEMSEDKGKfQ4=
github.com/grafana/alerting v0.0.0-20251204145817-de8c2bbf9eba/go.mod h1:l7v67cgP7x72ajB9UPZlumdrHqNztpKoqQ52cU8T3LU=
github.com/grafana/authlib v0.0.0-20250930082137-a40e2c2b094f h1:Cbm6OKkOcJ+7CSZsGsEJzktC/SIa5bxVeYKQLuYK86o=
github.com/grafana/authlib v0.0.0-20250930082137-a40e2c2b094f/go.mod h1:axY0cdOg3q0TZHwpHnIz5x16xZ8ZBxJHShsSHHXcHQg=
github.com/grafana/authlib/types v0.0.0-20251119142549-be091cf2f4d4 h1:Muoy+FMGrHj3GdFbvsMzUT7eusgii9PKf9L1ZaXDDbY=
@@ -1376,13 +1376,11 @@ github.com/puzpuzpuz/xsync/v2 v2.5.1 h1:mVGYAvzDSu52+zaGyNjC+24Xw2bQi3kTr4QJ6N9p
github.com/puzpuzpuz/xsync/v2 v2.5.1/go.mod h1:gD2H2krq/w52MfPLE+Uy64TzJDVY7lP2znR9qmR35kU=
github.com/puzpuzpuz/xsync/v4 v4.2.0 h1:dlxm77dZj2c3rxq0/XNvvUKISAmovoXF4a4qM6Wvkr0=
github.com/puzpuzpuz/xsync/v4 v4.2.0/go.mod h1:VJDmTCJMBt8igNxnkQd86r+8KUeN1quSfNKu5bLYFQo=
github.com/quagmt/udecimal v1.9.0 h1:TLuZiFeg0HhS6X8VDa78Y6XTaitZZfh+z5q4SXMzpDQ=
github.com/quagmt/udecimal v1.9.0/go.mod h1:ScmJ/xTGZcEoYiyMMzgDLn79PEJHcMBiJ4NNRT3FirA=
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/redis/go-redis/v9 v9.14.0 h1:u4tNCjXOyzfgeLN+vAZaW1xUooqWDqVEsZN0U01jfAE=
github.com/redis/go-redis/v9 v9.14.0/go.mod h1:huWgSWd8mW6+m0VPhJjSSQ+d6Nh1VICQ6Q5lHuCH/Iw=
github.com/redis/rueidis v1.0.68 h1:gept0E45JGxVigWb3zoWHvxEc4IOC7kc4V/4XvN8eG8=
github.com/redis/rueidis v1.0.68/go.mod h1:Lkhr2QTgcoYBhxARU7kJRO8SyVlgUuEkcJO1Y8MCluA=
github.com/redis/rueidis v1.0.64 h1:XqgbueDuNV3qFdVdQwAHJl1uNt90zUuAJuzqjH4cw6Y=
github.com/redis/rueidis v1.0.64/go.mod h1:Lkhr2QTgcoYBhxARU7kJRO8SyVlgUuEkcJO1Y8MCluA=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=

View File

@@ -22,40 +22,13 @@ v0alpha1: {
serviceaccountv0alpha1,
externalGroupMappingv0alpha1
]
routes: {
namespaced: {
"/searchUsers": {
"GET": {
request: {
query: {
query?: string
limit?: int64 | 10
offset?: int64 | 0
page?: int64 | 1
}
}
response: {
offset: int64
totalHits: int64
hits: [...#UserHit]
queryCost: float64
maxScore: float64
}
responseMetadata: {
typeMeta: false
objectMeta: false
}
}
}
"/searchTeams": {
"GET": {
request: {
query: {
query?: string
limit?: int64 | 50
offset?: int64 | 0
page?: int64 | 1
}
}
response: {
@@ -78,15 +51,3 @@ v0alpha1: {
}
}
}
#UserHit: {
name: string
title: string
login: string
email: string
role: string
lastSeenAt: int64
lastSeenAtAge: string
provisioned: bool
score: float64
}

View File

@@ -14,7 +14,7 @@ userKind: {
}
userv0alpha1: userKind & {
// TODO: Uncomment this when User will be added to ManagedKinds
// TODO: Uncomment this when User will be added to ManagedKinds
// validation: {
// operations: [
// "CREATE",
@@ -29,9 +29,6 @@ userv0alpha1: userKind & {
// }
schema: {
spec: v0alpha1.UserSpec
status: {
lastSeenAt: int64 | 0
}
}
// TODO: Uncomment when the custom routes implementation is done
// routes: {

View File

@@ -3,10 +3,7 @@
package v0alpha1
type GetSearchTeamsRequestParams struct {
Query *string `json:"query,omitempty"`
Limit int64 `json:"limit,omitempty"`
Offset int64 `json:"offset,omitempty"`
Page int64 `json:"page,omitempty"`
Query *string `json:"query,omitempty"`
}
// NewGetSearchTeamsRequestParams creates a new GetSearchTeamsRequestParams object.

View File

@@ -1,33 +0,0 @@
// Code generated - EDITING IS FUTILE. DO NOT EDIT.
package v0alpha1
import (
"github.com/grafana/grafana-app-sdk/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
)
type GetSearchUsersRequestParamsObject struct {
metav1.TypeMeta `json:",inline"`
GetSearchUsersRequestParams `json:",inline"`
}
func NewGetSearchUsersRequestParamsObject() *GetSearchUsersRequestParamsObject {
return &GetSearchUsersRequestParamsObject{}
}
func (o *GetSearchUsersRequestParamsObject) DeepCopyObject() runtime.Object {
dst := NewGetSearchUsersRequestParamsObject()
o.DeepCopyInto(dst)
return dst
}
func (o *GetSearchUsersRequestParamsObject) DeepCopyInto(dst *GetSearchUsersRequestParamsObject) {
dst.TypeMeta.APIVersion = o.TypeMeta.APIVersion
dst.TypeMeta.Kind = o.TypeMeta.Kind
dstGetSearchUsersRequestParams := GetSearchUsersRequestParams{}
_ = resource.CopyObjectInto(&dstGetSearchUsersRequestParams, &o.GetSearchUsersRequestParams)
}
var _ runtime.Object = NewGetSearchUsersRequestParamsObject()

View File

@@ -1,15 +0,0 @@
// Code generated - EDITING IS FUTILE. DO NOT EDIT.
package v0alpha1
type GetSearchUsersRequestParams struct {
Query *string `json:"query,omitempty"`
Limit int64 `json:"limit,omitempty"`
Offset int64 `json:"offset,omitempty"`
Page int64 `json:"page,omitempty"`
}
// NewGetSearchUsersRequestParams creates a new GetSearchUsersRequestParams object.
func NewGetSearchUsersRequestParams() *GetSearchUsersRequestParams {
return &GetSearchUsersRequestParams{}
}

View File

@@ -1,37 +0,0 @@
// Code generated - EDITING IS FUTILE. DO NOT EDIT.
package v0alpha1
// +k8s:openapi-gen=true
type UserHit struct {
Name string `json:"name"`
Title string `json:"title"`
Login string `json:"login"`
Email string `json:"email"`
Role string `json:"role"`
LastSeenAt int64 `json:"lastSeenAt"`
LastSeenAtAge string `json:"lastSeenAtAge"`
Provisioned bool `json:"provisioned"`
Score float64 `json:"score"`
}
// NewUserHit creates a new UserHit object.
func NewUserHit() *UserHit {
return &UserHit{}
}
// +k8s:openapi-gen=true
type GetSearchUsers struct {
Offset int64 `json:"offset"`
TotalHits int64 `json:"totalHits"`
Hits []UserHit `json:"hits"`
QueryCost float64 `json:"queryCost"`
MaxScore float64 `json:"maxScore"`
}
// NewGetSearchUsers creates a new GetSearchUsers object.
func NewGetSearchUsers() *GetSearchUsers {
return &GetSearchUsers{
Hits: []UserHit{},
}
}

View File

@@ -4,7 +4,6 @@ import (
"context"
"github.com/grafana/grafana-app-sdk/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
type UserClient struct {
@@ -76,24 +75,6 @@ func (c *UserClient) Patch(ctx context.Context, identifier resource.Identifier,
return c.client.Patch(ctx, identifier, req, opts)
}
func (c *UserClient) UpdateStatus(ctx context.Context, identifier resource.Identifier, newStatus UserStatus, opts resource.UpdateOptions) (*User, error) {
return c.client.Update(ctx, &User{
TypeMeta: metav1.TypeMeta{
Kind: UserKind().Kind(),
APIVersion: GroupVersion.Identifier(),
},
ObjectMeta: metav1.ObjectMeta{
ResourceVersion: opts.ResourceVersion,
Namespace: identifier.Namespace,
Name: identifier.Name,
},
Status: newStatus,
}, resource.UpdateOptions{
Subresource: "status",
ResourceVersion: opts.ResourceVersion,
})
}
func (c *UserClient) Delete(ctx context.Context, identifier resource.Identifier, opts resource.DeleteOptions) error {
return c.client.Delete(ctx, identifier, opts)
}

View File

@@ -21,14 +21,11 @@ type User struct {
// Spec is the spec of the User
Spec UserSpec `json:"spec" yaml:"spec"`
Status UserStatus `json:"status" yaml:"status"`
}
func NewUser() *User {
return &User{
Spec: *NewUserSpec(),
Status: *NewUserStatus(),
Spec: *NewUserSpec(),
}
}
@@ -46,15 +43,11 @@ func (o *User) SetSpec(spec any) error {
}
func (o *User) GetSubresources() map[string]any {
return map[string]any{
"status": o.Status,
}
return map[string]any{}
}
func (o *User) GetSubresource(name string) (any, bool) {
switch name {
case "status":
return o.Status, true
default:
return nil, false
}
@@ -62,13 +55,6 @@ func (o *User) GetSubresource(name string) (any, bool) {
func (o *User) SetSubresource(name string, value any) error {
switch name {
case "status":
cast, ok := value.(UserStatus)
if !ok {
return fmt.Errorf("cannot set status type %#v, not of type UserStatus", value)
}
o.Status = cast
return nil
default:
return fmt.Errorf("subresource '%s' does not exist", name)
}
@@ -240,7 +226,6 @@ func (o *User) DeepCopyInto(dst *User) {
dst.TypeMeta.Kind = o.TypeMeta.Kind
o.ObjectMeta.DeepCopyInto(&dst.ObjectMeta)
o.Spec.DeepCopyInto(&dst.Spec)
o.Status.DeepCopyInto(&dst.Status)
}
// Interface compliance compile-time check
@@ -312,15 +297,3 @@ func (s *UserSpec) DeepCopy() *UserSpec {
func (s *UserSpec) DeepCopyInto(dst *UserSpec) {
resource.CopyObjectInto(dst, s)
}
// DeepCopy creates a full deep copy of UserStatus
func (s *UserStatus) DeepCopy() *UserStatus {
cpy := &UserStatus{}
s.DeepCopyInto(cpy)
return cpy
}
// DeepCopyInto deep copies UserStatus into another UserStatus object
func (s *UserStatus) DeepCopyInto(dst *UserStatus) {
resource.CopyObjectInto(dst, s)
}

View File

@@ -2,12 +2,43 @@
package v0alpha1
// +k8s:openapi-gen=true
type UserstatusOperatorState struct {
// lastEvaluation is the ResourceVersion last evaluated
LastEvaluation string `json:"lastEvaluation"`
// state describes the state of the lastEvaluation.
// It is limited to three possible states for machine evaluation.
State UserStatusOperatorStateState `json:"state"`
// descriptiveState is an optional more descriptive state field which has no requirements on format
DescriptiveState *string `json:"descriptiveState,omitempty"`
// details contains any extra information that is operator-specific
Details map[string]interface{} `json:"details,omitempty"`
}
// NewUserstatusOperatorState creates a new UserstatusOperatorState object.
func NewUserstatusOperatorState() *UserstatusOperatorState {
return &UserstatusOperatorState{}
}
// +k8s:openapi-gen=true
type UserStatus struct {
LastSeenAt int64 `json:"lastSeenAt"`
// operatorStates is a map of operator ID to operator state evaluations.
// Any operator which consumes this kind SHOULD add its state evaluation information to this field.
OperatorStates map[string]UserstatusOperatorState `json:"operatorStates,omitempty"`
// additionalFields is reserved for future use
AdditionalFields map[string]interface{} `json:"additionalFields,omitempty"`
}
// NewUserStatus creates a new UserStatus object.
func NewUserStatus() *UserStatus {
return &UserStatus{}
}
// +k8s:openapi-gen=true
type UserStatusOperatorStateState string
const (
UserStatusOperatorStateStateSuccess UserStatusOperatorStateState = "success"
UserStatusOperatorStateStateInProgress UserStatusOperatorStateState = "in_progress"
UserStatusOperatorStateStateFailed UserStatusOperatorStateState = "failed"
)

View File

@@ -21,7 +21,6 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA
"github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.GetGroupsBody": schema_pkg_apis_iam_v0alpha1_GetGroupsBody(ref),
"github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.GetSearchTeams": schema_pkg_apis_iam_v0alpha1_GetSearchTeams(ref),
"github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.GetSearchTeamsBody": schema_pkg_apis_iam_v0alpha1_GetSearchTeamsBody(ref),
"github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.GetSearchUsers": schema_pkg_apis_iam_v0alpha1_GetSearchUsers(ref),
"github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.GlobalRole": schema_pkg_apis_iam_v0alpha1_GlobalRole(ref),
"github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.GlobalRoleBinding": schema_pkg_apis_iam_v0alpha1_GlobalRoleBinding(ref),
"github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.GlobalRoleBindingList": schema_pkg_apis_iam_v0alpha1_GlobalRoleBindingList(ref),
@@ -73,10 +72,10 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA
"github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.TeamStatus": schema_pkg_apis_iam_v0alpha1_TeamStatus(ref),
"github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.TeamstatusOperatorState": schema_pkg_apis_iam_v0alpha1_TeamstatusOperatorState(ref),
"github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.User": schema_pkg_apis_iam_v0alpha1_User(ref),
"github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.UserHit": schema_pkg_apis_iam_v0alpha1_UserHit(ref),
"github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.UserList": schema_pkg_apis_iam_v0alpha1_UserList(ref),
"github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.UserSpec": schema_pkg_apis_iam_v0alpha1_UserSpec(ref),
"github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.UserStatus": schema_pkg_apis_iam_v0alpha1_UserStatus(ref),
"github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.UserstatusOperatorState": schema_pkg_apis_iam_v0alpha1_UserstatusOperatorState(ref),
"github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.VersionsV0alpha1Kinds7RoutesGroupsGETResponseExternalGroupMapping": schema_pkg_apis_iam_v0alpha1_VersionsV0alpha1Kinds7RoutesGroupsGETResponseExternalGroupMapping(ref),
"github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.VersionsV0alpha1RoutesNamespacedSearchTeamsGETResponseTeamHit": schema_pkg_apis_iam_v0alpha1_VersionsV0alpha1RoutesNamespacedSearchTeamsGETResponseTeamHit(ref),
}
@@ -689,62 +688,6 @@ func schema_pkg_apis_iam_v0alpha1_GetSearchTeamsBody(ref common.ReferenceCallbac
}
}
func schema_pkg_apis_iam_v0alpha1_GetSearchUsers(ref common.ReferenceCallback) common.OpenAPIDefinition {
return common.OpenAPIDefinition{
Schema: spec.Schema{
SchemaProps: spec.SchemaProps{
Type: []string{"object"},
Properties: map[string]spec.Schema{
"offset": {
SchemaProps: spec.SchemaProps{
Default: 0,
Type: []string{"integer"},
Format: "int64",
},
},
"totalHits": {
SchemaProps: spec.SchemaProps{
Default: 0,
Type: []string{"integer"},
Format: "int64",
},
},
"hits": {
SchemaProps: spec.SchemaProps{
Type: []string{"array"},
Items: &spec.SchemaOrArray{
Schema: &spec.Schema{
SchemaProps: spec.SchemaProps{
Default: map[string]interface{}{},
Ref: ref("github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.UserHit"),
},
},
},
},
},
"queryCost": {
SchemaProps: spec.SchemaProps{
Default: 0,
Type: []string{"number"},
Format: "double",
},
},
"maxScore": {
SchemaProps: spec.SchemaProps{
Default: 0,
Type: []string{"number"},
Format: "double",
},
},
},
Required: []string{"offset", "totalHits", "hits", "queryCost", "maxScore"},
},
},
Dependencies: []string{
"github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.UserHit"},
}
}
func schema_pkg_apis_iam_v0alpha1_GlobalRole(ref common.ReferenceCallback) common.OpenAPIDefinition {
return common.OpenAPIDefinition{
Schema: spec.Schema{
@@ -2890,94 +2833,12 @@ func schema_pkg_apis_iam_v0alpha1_User(ref common.ReferenceCallback) common.Open
Ref: ref("github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.UserSpec"),
},
},
"status": {
SchemaProps: spec.SchemaProps{
Default: map[string]interface{}{},
Ref: ref("github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.UserStatus"),
},
},
},
Required: []string{"metadata", "spec", "status"},
Required: []string{"metadata", "spec"},
},
},
Dependencies: []string{
"github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.UserSpec", "github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.UserStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"},
}
}
func schema_pkg_apis_iam_v0alpha1_UserHit(ref common.ReferenceCallback) common.OpenAPIDefinition {
return common.OpenAPIDefinition{
Schema: spec.Schema{
SchemaProps: spec.SchemaProps{
Type: []string{"object"},
Properties: map[string]spec.Schema{
"name": {
SchemaProps: spec.SchemaProps{
Default: "",
Type: []string{"string"},
Format: "",
},
},
"title": {
SchemaProps: spec.SchemaProps{
Default: "",
Type: []string{"string"},
Format: "",
},
},
"login": {
SchemaProps: spec.SchemaProps{
Default: "",
Type: []string{"string"},
Format: "",
},
},
"email": {
SchemaProps: spec.SchemaProps{
Default: "",
Type: []string{"string"},
Format: "",
},
},
"role": {
SchemaProps: spec.SchemaProps{
Default: "",
Type: []string{"string"},
Format: "",
},
},
"lastSeenAt": {
SchemaProps: spec.SchemaProps{
Default: 0,
Type: []string{"integer"},
Format: "int64",
},
},
"lastSeenAtAge": {
SchemaProps: spec.SchemaProps{
Default: "",
Type: []string{"string"},
Format: "",
},
},
"provisioned": {
SchemaProps: spec.SchemaProps{
Default: false,
Type: []string{"boolean"},
Format: "",
},
},
"score": {
SchemaProps: spec.SchemaProps{
Default: 0,
Type: []string{"number"},
Format: "double",
},
},
},
Required: []string{"name", "title", "login", "email", "role", "lastSeenAt", "lastSeenAtAge", "provisioned", "score"},
},
},
"github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.UserSpec", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"},
}
}
@@ -3104,15 +2965,90 @@ func schema_pkg_apis_iam_v0alpha1_UserStatus(ref common.ReferenceCallback) commo
SchemaProps: spec.SchemaProps{
Type: []string{"object"},
Properties: map[string]spec.Schema{
"lastSeenAt": {
"operatorStates": {
SchemaProps: spec.SchemaProps{
Default: 0,
Type: []string{"integer"},
Format: "int64",
Description: "operatorStates is a map of operator ID to operator state evaluations. Any operator which consumes this kind SHOULD add its state evaluation information to this field.",
Type: []string{"object"},
AdditionalProperties: &spec.SchemaOrBool{
Allows: true,
Schema: &spec.Schema{
SchemaProps: spec.SchemaProps{
Default: map[string]interface{}{},
Ref: ref("github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.UserstatusOperatorState"),
},
},
},
},
},
"additionalFields": {
SchemaProps: spec.SchemaProps{
Description: "additionalFields is reserved for future use",
Type: []string{"object"},
AdditionalProperties: &spec.SchemaOrBool{
Allows: true,
Schema: &spec.Schema{
SchemaProps: spec.SchemaProps{
Type: []string{"object"},
Format: "",
},
},
},
},
},
},
Required: []string{"lastSeenAt"},
},
},
Dependencies: []string{
"github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.UserstatusOperatorState"},
}
}
func schema_pkg_apis_iam_v0alpha1_UserstatusOperatorState(ref common.ReferenceCallback) common.OpenAPIDefinition {
return common.OpenAPIDefinition{
Schema: spec.Schema{
SchemaProps: spec.SchemaProps{
Type: []string{"object"},
Properties: map[string]spec.Schema{
"lastEvaluation": {
SchemaProps: spec.SchemaProps{
Description: "lastEvaluation is the ResourceVersion last evaluated",
Default: "",
Type: []string{"string"},
Format: "",
},
},
"state": {
SchemaProps: spec.SchemaProps{
Description: "state describes the state of the lastEvaluation. It is limited to three possible states for machine evaluation.",
Default: "",
Type: []string{"string"},
Format: "",
},
},
"descriptiveState": {
SchemaProps: spec.SchemaProps{
Description: "descriptiveState is an optional more descriptive state field which has no requirements on format",
Type: []string{"string"},
Format: "",
},
},
"details": {
SchemaProps: spec.SchemaProps{
Description: "details contains any extra information that is operator-specific",
Type: []string{"object"},
AdditionalProperties: &spec.SchemaOrBool{
Allows: true,
Schema: &spec.Schema{
SchemaProps: spec.SchemaProps{
Type: []string{"object"},
Format: "",
},
},
},
},
},
},
Required: []string{"lastEvaluation", "state"},
},
},
}

View File

@@ -74,6 +74,10 @@ var appManifestData = app.ManifestData{
Plural: "Users",
Scope: "Namespaced",
Conversion: false,
SelectableFields: []string{
"spec.email",
"spec.login",
},
},
{
@@ -173,36 +177,6 @@ var appManifestData = app.ManifestData{
Parameters: []*spec3.Parameter{
{
ParameterProps: spec3.ParameterProps{
Name: "limit",
In: "query",
Schema: &spec.Schema{
SchemaProps: spec.SchemaProps{},
},
},
},
{
ParameterProps: spec3.ParameterProps{
Name: "offset",
In: "query",
Schema: &spec.Schema{
SchemaProps: spec.SchemaProps{},
},
},
},
{
ParameterProps: spec3.ParameterProps{
Name: "page",
In: "query",
Schema: &spec.Schema{
SchemaProps: spec.SchemaProps{},
},
},
},
{
ParameterProps: spec3.ParameterProps{
Name: "query",
@@ -291,118 +265,6 @@ var appManifestData = app.ManifestData{
},
},
},
"/searchUsers": {
Get: &spec3.Operation{
OperationProps: spec3.OperationProps{
OperationId: "getSearchUsers",
Parameters: []*spec3.Parameter{
{
ParameterProps: spec3.ParameterProps{
Name: "limit",
In: "query",
Schema: &spec.Schema{
SchemaProps: spec.SchemaProps{},
},
},
},
{
ParameterProps: spec3.ParameterProps{
Name: "offset",
In: "query",
Schema: &spec.Schema{
SchemaProps: spec.SchemaProps{},
},
},
},
{
ParameterProps: spec3.ParameterProps{
Name: "page",
In: "query",
Schema: &spec.Schema{
SchemaProps: spec.SchemaProps{},
},
},
},
{
ParameterProps: spec3.ParameterProps{
Name: "query",
In: "query",
Schema: &spec.Schema{
SchemaProps: spec.SchemaProps{
Type: []string{"string"},
},
},
},
},
},
Responses: &spec3.Responses{
ResponsesProps: spec3.ResponsesProps{
Default: &spec3.Response{
ResponseProps: spec3.ResponseProps{
Description: "Default OK response",
Content: map[string]*spec3.MediaType{
"application/json": {
MediaTypeProps: spec3.MediaTypeProps{
Schema: &spec.Schema{
SchemaProps: spec.SchemaProps{
Type: []string{"object"},
Properties: map[string]spec.Schema{
"hits": {
SchemaProps: spec.SchemaProps{
Type: []string{"array"},
Items: &spec.SchemaOrArray{
Schema: &spec.Schema{
SchemaProps: spec.SchemaProps{
Ref: spec.MustCreateRef("#/components/schemas/getSearchUsersUserHit"),
}},
},
},
},
"maxScore": {
SchemaProps: spec.SchemaProps{
Type: []string{"number"},
},
},
"offset": {
SchemaProps: spec.SchemaProps{
Type: []string{"integer"},
},
},
"queryCost": {
SchemaProps: spec.SchemaProps{
Type: []string{"number"},
},
},
"totalHits": {
SchemaProps: spec.SchemaProps{
Type: []string{"integer"},
},
},
},
Required: []string{
"offset",
"totalHits",
"hits",
"queryCost",
"maxScore",
},
}},
}},
},
},
},
}},
},
},
},
},
Cluster: map[string]spec3.PathProps{},
Schemas: map[string]spec.Schema{
@@ -445,69 +307,6 @@ var appManifestData = app.ManifestData{
},
},
},
"getSearchUsersUserHit": {
SchemaProps: spec.SchemaProps{
Type: []string{"object"},
Properties: map[string]spec.Schema{
"email": {
SchemaProps: spec.SchemaProps{
Type: []string{"string"},
},
},
"lastSeenAt": {
SchemaProps: spec.SchemaProps{
Type: []string{"integer"},
},
},
"lastSeenAtAge": {
SchemaProps: spec.SchemaProps{
Type: []string{"string"},
},
},
"login": {
SchemaProps: spec.SchemaProps{
Type: []string{"string"},
},
},
"name": {
SchemaProps: spec.SchemaProps{
Type: []string{"string"},
},
},
"provisioned": {
SchemaProps: spec.SchemaProps{
Type: []string{"boolean"},
},
},
"role": {
SchemaProps: spec.SchemaProps{
Type: []string{"string"},
},
},
"score": {
SchemaProps: spec.SchemaProps{
Type: []string{"number"},
},
},
"title": {
SchemaProps: spec.SchemaProps{
Type: []string{"string"},
},
},
},
Required: []string{
"name",
"title",
"login",
"email",
"role",
"lastSeenAt",
"lastSeenAtAge",
"provisioned",
"score",
},
},
},
},
},
},
@@ -547,7 +346,6 @@ var customRouteToGoResponseType = map[string]any{
"v0alpha1|Team|groups|GET": v0alpha1.GetGroups{},
"v0alpha1||<namespace>/searchTeams|GET": v0alpha1.GetSearchTeams{},
"v0alpha1||<namespace>/searchUsers|GET": v0alpha1.GetSearchUsers{},
}
// ManifestCustomRouteResponsesAssociator returns the associated response go type for a given kind, version, custom route path, and method, if one exists.

View File

@@ -4,8 +4,6 @@ import (
"context"
"fmt"
"github.com/prometheus/client_golang/prometheus"
"github.com/grafana/grafana-app-sdk/app"
"github.com/grafana/grafana-app-sdk/logging"
"github.com/grafana/grafana-app-sdk/operator"
@@ -14,6 +12,7 @@ import (
foldersKind "github.com/grafana/grafana/apps/folder/pkg/apis/folder/v1beta1"
"github.com/grafana/grafana/apps/iam/pkg/reconcilers"
"github.com/grafana/grafana/pkg/services/authz"
"github.com/prometheus/client_golang/prometheus"
)
var appManifestData = app.ManifestData{
@@ -79,7 +78,7 @@ func New(cfg app.Config) (app.App, error) {
folderReconciler, err := reconcilers.NewFolderReconciler(reconcilers.ReconcilerConfig{
ZanzanaCfg: appSpecificConfig.ZanzanaClientCfg,
Metrics: metrics,
}, appSpecificConfig.MetricsRegisterer)
})
if err != nil {
return nil, fmt.Errorf("unable to create FolderReconciler: %w", err)
}

View File

@@ -5,7 +5,6 @@ import (
"fmt"
"time"
"github.com/prometheus/client_golang/prometheus"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/codes"
@@ -36,9 +35,9 @@ type FolderReconciler struct {
metrics *ReconcilerMetrics
}
func NewFolderReconciler(cfg ReconcilerConfig, reg prometheus.Registerer) (operator.Reconciler, error) {
func NewFolderReconciler(cfg ReconcilerConfig) (operator.Reconciler, error) {
// Create Zanzana client
zanzanaClient, err := authz.NewRemoteZanzanaClient(cfg.ZanzanaCfg, reg)
zanzanaClient, err := authz.NewRemoteZanzanaClient("*", cfg.ZanzanaCfg)
if err != nil {
return nil, fmt.Errorf("unable to create zanzana client: %w", err)

View File

@@ -74,7 +74,7 @@ require (
github.com/google/gnostic-models v0.7.0 // indirect
github.com/google/go-cmp v0.7.0 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/grafana/alerting v0.0.0-20251212143239-491433b332b7 // indirect
github.com/grafana/alerting v0.0.0-20251204145817-de8c2bbf9eba // indirect
github.com/grafana/authlib v0.0.0-20250930082137-a40e2c2b094f // indirect
github.com/grafana/authlib/types v0.0.0-20251119142549-be091cf2f4d4 // indirect
github.com/grafana/dataplane/sdata v0.0.9 // indirect

View File

@@ -174,8 +174,8 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 h1:JeSE6pjso5THxAzdVpqr6/geYxZytqFMBCOtn/ujyeo=
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674/go.mod h1:r4w70xmWCQKmi1ONH4KIaBptdivuRPyosB9RmPlGEwA=
github.com/grafana/alerting v0.0.0-20251212143239-491433b332b7 h1:ZzG/gCclEit9w0QUfQt9GURcOycAIGcsQAhY1u0AEX0=
github.com/grafana/alerting v0.0.0-20251212143239-491433b332b7/go.mod h1:l7v67cgP7x72ajB9UPZlumdrHqNztpKoqQ52cU8T3LU=
github.com/grafana/alerting v0.0.0-20251204145817-de8c2bbf9eba h1:psKWNETD5nGxmFAlqnWsXoRyUwSa2GHNEMSEDKGKfQ4=
github.com/grafana/alerting v0.0.0-20251204145817-de8c2bbf9eba/go.mod h1:l7v67cgP7x72ajB9UPZlumdrHqNztpKoqQ52cU8T3LU=
github.com/grafana/authlib v0.0.0-20250930082137-a40e2c2b094f h1:Cbm6OKkOcJ+7CSZsGsEJzktC/SIa5bxVeYKQLuYK86o=
github.com/grafana/authlib v0.0.0-20250930082137-a40e2c2b094f/go.mod h1:axY0cdOg3q0TZHwpHnIz5x16xZ8ZBxJHShsSHHXcHQg=
github.com/grafana/authlib/types v0.0.0-20251119142549-be091cf2f4d4 h1:Muoy+FMGrHj3GdFbvsMzUT7eusgii9PKf9L1ZaXDDbY=

View File

@@ -1,73 +0,0 @@
package repository
connection: {
kind: "Connection"
pluralName: "Connections"
current: "v0alpha1"
validation: {
operations: [
"CREATE",
"UPDATE",
]
}
versions: {
"v0alpha1": {
codegen: {
ts: {enabled: false}
go: {enabled: true}
}
schema: {
#GitHubConnectionConfig: {
// App-level information
// GitHub App ID
appID: int
// Installation-level information
// GitHub App installation ID
installationID: int
}
#BitbucketConnectionConfig: {
// The app clientID
clientID: string
}
#GitlabConnectionConfig: {
// The app clientID
clientID: string
}
#HealthStatus: {
// When not healthy, requests will not be executed
healthy: bool
// When the health was checked last time
checked?: int
// Summary messages (can be shown to users)
// Will only be populated when not healthy
message?: [...string]
}
spec: {
// The connection provider type
type: "github" | "bitbucket" | "gitlab"
// The connection URL
url: *"" | string
// GitHub connection configuration
// Only applicable when provider is "github"
github?: #GitHubConnectionConfig
// Bitbucket connection configuration
// Only applicable when provider is "bitbucket"
bitbucket?: #BitbucketConnectionConfig
// Gitlab connection configuration
// Only applicable when provider is "gitlab"
gitlab?: #GitlabConnectionConfig
}
status: {
// The generation of the spec last time reconciliation ran
observedGeneration?: int
// Connection state
state: "connected" | "disconnected"
// The connection health status
health: #HealthStatus
}
}
}
}
}

View File

@@ -5,6 +5,5 @@ manifest: {
groupOverride: "provisioning.grafana.app"
kinds: [
repository,
connection
]
}
}

View File

@@ -1,118 +0,0 @@
package v0alpha1
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
common "github.com/grafana/grafana/pkg/apimachinery/apis/common/v0alpha1"
)
// When this code is changed, make sure to update the code generation.
// As of writing, this can be done via the hack dir in the root of the repo: ./hack/update-codegen.sh provisioning
// If you've opened the generated files in this dir at some point in VSCode, you may also have to re-open them to clear errors.
// +genclient
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
type Connection struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Spec ConnectionSpec `json:"spec,omitempty"`
Secure ConnectionSecure `json:"secure,omitzero,omitempty"`
Status ConnectionStatus `json:"status,omitempty"`
}
type ConnectionSecure struct {
// PrivateKey is the reference to the private key used for GitHub App authentication.
// This value is stored securely and cannot be read back
PrivateKey common.InlineSecureValue `json:"privateKey,omitzero,omitempty"`
// ClientSecret is the reference to the secret used for other providers authentication,
// and Github on-behalf-of authentication.
// This value is stored securely and cannot be read back
ClientSecret common.InlineSecureValue `json:"clientSecret,omitzero,omitempty"`
// Token is the reference of the token used to act as the Connection.
// This value is stored securely and cannot be read back
Token common.InlineSecureValue `json:"webhook,omitzero,omitempty"`
}
func (v ConnectionSecure) IsZero() bool {
return v.PrivateKey.IsZero() && v.Token.IsZero()
}
type GitHubConnectionConfig struct {
// GitHub App ID
AppID string `json:"appID"`
// GitHub App installation ID
InstallationID string `json:"installationID"`
}
type BitbucketConnectionConfig struct {
// App client ID
ClientID string `json:"clientID"`
}
type GitlabConnectionConfig struct {
// App client ID
ClientID string `json:"clientID"`
}
// ConnectionType defines the types of Connection providers
// +enum
type ConnectionType string
// ConnectionType values.
const (
GithubConnectionType ConnectionType = "github"
GitlabConnectionType ConnectionType = "gitlab"
BitbucketConnectionType ConnectionType = "bitbucket"
)
type ConnectionSpec struct {
// The connection provider type
Type ConnectionType `json:"type"`
// The connection URL
URL string `json:"url,omitempty"`
// GitHub connection configuration
// Only applicable when provider is "github"
GitHub *GitHubConnectionConfig `json:"github,omitempty"`
// Bitbucket connection configuration
// Only applicable when provider is "bitbucket"
Bitbucket *BitbucketConnectionConfig `json:"bitbucket,omitempty"`
// Gitlab connection configuration
// Only applicable when provider is "gitlab"
Gitlab *GitlabConnectionConfig `json:"gitlab,omitempty"`
}
// ConnectionState defines the state of a Connection
// +enum
type ConnectionState string
// ConnectionState values
const (
ConnectionStateConnected ConnectionState = "connected"
ConnectionStateDisconnected ConnectionState = "disconnected"
)
// The status of a Connection.
// This is expected never to be created by a kubectl call or similar, and is expected to rarely (if ever) be edited manually.
type ConnectionStatus struct {
// The generation of the spec last time reconciliation ran
ObservedGeneration int64 `json:"observedGeneration"`
// Connection state
State ConnectionState `json:"state"`
// The connection health status
Health HealthStatus `json:"health"`
}
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
type ConnectionList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
// +listType=atomic
Items []Connection `json:"items"`
}

View File

@@ -1,26 +0,0 @@
package v0alpha1
// HealthFailureType represents different types of healthcheck failures
// +enum
type HealthFailureType string
const (
HealthFailureHook HealthFailureType = "hook"
HealthFailureHealth HealthFailureType = "health"
)
type HealthStatus struct {
// When not healthy, requests will not be executed
Healthy bool `json:"healthy"`
// The type of the error
Error HealthFailureType `json:"error,omitempty"`
// When the health was checked last time
Checked int64 `json:"checked,omitempty"`
// Summary messages (can be shown to users)
// Will only be populated when not healthy
// +listType=atomic
Message []string `json:"message,omitempty"`
}

View File

@@ -198,7 +198,6 @@ type JobStatus struct {
Finished int64 `json:"finished,omitempty"`
Message string `json:"message,omitempty"`
Errors []string `json:"errors,omitempty"`
Warnings []string `json:"warnings,omitempty"`
// Optional value 0-100 that can be set while running
Progress float64 `json:"progress,omitempty"`
@@ -226,20 +225,18 @@ type JobResourceSummary struct {
Kind string `json:"kind,omitempty"`
Total int64 `json:"total,omitempty"` // the count (if known)
Create int64 `json:"create,omitempty"`
Update int64 `json:"update,omitempty"`
Delete int64 `json:"delete,omitempty"`
Write int64 `json:"write,omitempty"` // Create or update (export)
Error int64 `json:"error,omitempty"` // The error count
Warning int64 `json:"warning,omitempty"` // The warning count
Create int64 `json:"create,omitempty"`
Update int64 `json:"update,omitempty"`
Delete int64 `json:"delete,omitempty"`
Write int64 `json:"write,omitempty"` // Create or update (export)
Error int64 `json:"error,omitempty"` // The error count
// No action required (useful for sync)
Noop int64 `json:"noop,omitempty"`
// Report errors/warnings for this resource type
// Report errors for this resource type
// This may not be an exhaustive list and recommend looking at the logs for more info
Errors []string `json:"errors,omitempty"`
Warnings []string `json:"warnings,omitempty"`
Errors []string `json:"errors,omitempty"`
}
// HistoricJob is an append only log, saving all jobs that have been processed.

View File

@@ -115,47 +115,6 @@ var HistoricJobResourceInfo = utils.NewResourceInfo(GROUP, VERSION,
},
})
var ConnectionResourceInfo = utils.NewResourceInfo(GROUP, VERSION,
"connections", "connection", "Connection",
func() runtime.Object { return &Connection{} }, // newObj
func() runtime.Object { return &ConnectionList{} }, // newList
utils.TableColumns{ // Returned by `kubectl get`. Doesn't affect disk storage.
Definition: []metav1.TableColumnDefinition{
{Name: "Name", Type: "string", Format: "name"},
{Name: "Created At", Type: "date"},
{Name: "Type", Type: "string"},
{Name: "AppID", Type: "string"},
{Name: "InstallationID", Type: "string"},
{Name: "ClientID", Type: "string"},
},
Reader: func(obj any) ([]interface{}, error) {
m, ok := obj.(*Connection)
if !ok {
return nil, errors.New("expected Repository")
}
var appID, installationID, clientID string
switch m.Spec.Type {
case GithubConnectionType:
appID = m.Spec.GitHub.AppID
installationID = m.Spec.GitHub.InstallationID
case BitbucketConnectionType:
clientID = m.Spec.Bitbucket.ClientID
case GitlabConnectionType:
clientID = m.Spec.Gitlab.ClientID
}
return []interface{}{
m.Name,
m.CreationTimestamp.UTC().Format(time.RFC3339),
m.Spec.Type,
appID,
installationID,
clientID,
}, nil
},
})
var (
// SchemeGroupVersion is group version used to register these objects
SchemeGroupVersion = schema.GroupVersion{Group: GROUP, Version: VERSION}
@@ -195,8 +154,6 @@ func AddKnownTypes(gv schema.GroupVersion, scheme *runtime.Scheme) error {
&RefList{},
&HistoricJob{},
&HistoricJobList{},
&Connection{},
&ConnectionList{},
)
return nil
}

View File

@@ -315,6 +315,31 @@ type RepositoryStatus struct {
DeleteError string `json:"deleteError,omitempty"`
}
// HealthFailureType represents different types of repository failures
// +enum
type HealthFailureType string
const (
HealthFailureHook HealthFailureType = "hook"
HealthFailureHealth HealthFailureType = "health"
)
type HealthStatus struct {
// When not healthy, requests will not be executed
Healthy bool `json:"healthy"`
// The type of the error
Error HealthFailureType `json:"error,omitempty"`
// When the health was checked last time
Checked int64 `json:"checked,omitempty"`
// Summary messages (can be shown to users)
// Will only be populated when not healthy
// +listType=atomic
Message []string `json:"message,omitempty"`
}
type SyncStatus struct {
// pending, running, success, error
State JobState `json:"state"`

View File

@@ -27,22 +27,6 @@ func (in *Author) DeepCopy() *Author {
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *BitbucketConnectionConfig) DeepCopyInto(out *BitbucketConnectionConfig) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BitbucketConnectionConfig.
func (in *BitbucketConnectionConfig) DeepCopy() *BitbucketConnectionConfig {
if in == nil {
return nil
}
out := new(BitbucketConnectionConfig)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *BitbucketRepositoryConfig) DeepCopyInto(out *BitbucketRepositoryConfig) {
*out = *in
@@ -59,135 +43,6 @@ func (in *BitbucketRepositoryConfig) DeepCopy() *BitbucketRepositoryConfig {
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Connection) DeepCopyInto(out *Connection) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
in.Spec.DeepCopyInto(&out.Spec)
out.Secure = in.Secure
in.Status.DeepCopyInto(&out.Status)
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Connection.
func (in *Connection) DeepCopy() *Connection {
if in == nil {
return nil
}
out := new(Connection)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *Connection) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ConnectionList) DeepCopyInto(out *ConnectionList) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ListMeta.DeepCopyInto(&out.ListMeta)
if in.Items != nil {
in, out := &in.Items, &out.Items
*out = make([]Connection, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConnectionList.
func (in *ConnectionList) DeepCopy() *ConnectionList {
if in == nil {
return nil
}
out := new(ConnectionList)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *ConnectionList) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ConnectionSecure) DeepCopyInto(out *ConnectionSecure) {
*out = *in
out.PrivateKey = in.PrivateKey
out.ClientSecret = in.ClientSecret
out.Token = in.Token
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConnectionSecure.
func (in *ConnectionSecure) DeepCopy() *ConnectionSecure {
if in == nil {
return nil
}
out := new(ConnectionSecure)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ConnectionSpec) DeepCopyInto(out *ConnectionSpec) {
*out = *in
if in.GitHub != nil {
in, out := &in.GitHub, &out.GitHub
*out = new(GitHubConnectionConfig)
**out = **in
}
if in.Bitbucket != nil {
in, out := &in.Bitbucket, &out.Bitbucket
*out = new(BitbucketConnectionConfig)
**out = **in
}
if in.Gitlab != nil {
in, out := &in.Gitlab, &out.Gitlab
*out = new(GitlabConnectionConfig)
**out = **in
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConnectionSpec.
func (in *ConnectionSpec) DeepCopy() *ConnectionSpec {
if in == nil {
return nil
}
out := new(ConnectionSpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ConnectionStatus) DeepCopyInto(out *ConnectionStatus) {
*out = *in
in.Health.DeepCopyInto(&out.Health)
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConnectionStatus.
func (in *ConnectionStatus) DeepCopy() *ConnectionStatus {
if in == nil {
return nil
}
out := new(ConnectionStatus)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *DeleteJobOptions) DeepCopyInto(out *DeleteJobOptions) {
*out = *in
@@ -293,22 +148,6 @@ func (in *FileList) DeepCopyObject() runtime.Object {
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *GitHubConnectionConfig) DeepCopyInto(out *GitHubConnectionConfig) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GitHubConnectionConfig.
func (in *GitHubConnectionConfig) DeepCopy() *GitHubConnectionConfig {
if in == nil {
return nil
}
out := new(GitHubConnectionConfig)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *GitHubRepositoryConfig) DeepCopyInto(out *GitHubRepositoryConfig) {
*out = *in
@@ -357,22 +196,6 @@ func (in *GitRepositoryConfig) DeepCopy() *GitRepositoryConfig {
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *GitlabConnectionConfig) DeepCopyInto(out *GitlabConnectionConfig) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GitlabConnectionConfig.
func (in *GitlabConnectionConfig) DeepCopy() *GitlabConnectionConfig {
if in == nil {
return nil
}
out := new(GitlabConnectionConfig)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *HealthStatus) DeepCopyInto(out *HealthStatus) {
*out = *in
@@ -578,11 +401,6 @@ func (in *JobResourceSummary) DeepCopyInto(out *JobResourceSummary) {
*out = make([]string, len(*in))
copy(*out, *in)
}
if in.Warnings != nil {
in, out := &in.Warnings, &out.Warnings
*out = make([]string, len(*in))
copy(*out, *in)
}
return
}
@@ -650,11 +468,6 @@ func (in *JobStatus) DeepCopyInto(out *JobStatus) {
*out = make([]string, len(*in))
copy(*out, *in)
}
if in.Warnings != nil {
in, out := &in.Warnings, &out.Warnings
*out = make([]string, len(*in))
copy(*out, *in)
}
if in.Summary != nil {
in, out := &in.Summary, &out.Summary
*out = make([]*JobResourceSummary, len(*in))

View File

@@ -15,23 +15,15 @@ import (
func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenAPIDefinition {
return map[string]common.OpenAPIDefinition{
"github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1.Author": schema_pkg_apis_provisioning_v0alpha1_Author(ref),
"github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1.BitbucketConnectionConfig": schema_pkg_apis_provisioning_v0alpha1_BitbucketConnectionConfig(ref),
"github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1.BitbucketRepositoryConfig": schema_pkg_apis_provisioning_v0alpha1_BitbucketRepositoryConfig(ref),
"github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1.Connection": schema_pkg_apis_provisioning_v0alpha1_Connection(ref),
"github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1.ConnectionList": schema_pkg_apis_provisioning_v0alpha1_ConnectionList(ref),
"github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1.ConnectionSecure": schema_pkg_apis_provisioning_v0alpha1_ConnectionSecure(ref),
"github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1.ConnectionSpec": schema_pkg_apis_provisioning_v0alpha1_ConnectionSpec(ref),
"github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1.ConnectionStatus": schema_pkg_apis_provisioning_v0alpha1_ConnectionStatus(ref),
"github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1.DeleteJobOptions": schema_pkg_apis_provisioning_v0alpha1_DeleteJobOptions(ref),
"github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1.ErrorDetails": schema_pkg_apis_provisioning_v0alpha1_ErrorDetails(ref),
"github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1.ExportJobOptions": schema_pkg_apis_provisioning_v0alpha1_ExportJobOptions(ref),
"github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1.FileItem": schema_pkg_apis_provisioning_v0alpha1_FileItem(ref),
"github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1.FileList": schema_pkg_apis_provisioning_v0alpha1_FileList(ref),
"github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1.GitHubConnectionConfig": schema_pkg_apis_provisioning_v0alpha1_GitHubConnectionConfig(ref),
"github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1.GitHubRepositoryConfig": schema_pkg_apis_provisioning_v0alpha1_GitHubRepositoryConfig(ref),
"github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1.GitLabRepositoryConfig": schema_pkg_apis_provisioning_v0alpha1_GitLabRepositoryConfig(ref),
"github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1.GitRepositoryConfig": schema_pkg_apis_provisioning_v0alpha1_GitRepositoryConfig(ref),
"github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1.GitlabConnectionConfig": schema_pkg_apis_provisioning_v0alpha1_GitlabConnectionConfig(ref),
"github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1.HealthStatus": schema_pkg_apis_provisioning_v0alpha1_HealthStatus(ref),
"github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1.HistoricJob": schema_pkg_apis_provisioning_v0alpha1_HistoricJob(ref),
"github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1.HistoricJobList": schema_pkg_apis_provisioning_v0alpha1_HistoricJobList(ref),
@@ -108,27 +100,6 @@ func schema_pkg_apis_provisioning_v0alpha1_Author(ref common.ReferenceCallback)
}
}
func schema_pkg_apis_provisioning_v0alpha1_BitbucketConnectionConfig(ref common.ReferenceCallback) common.OpenAPIDefinition {
return common.OpenAPIDefinition{
Schema: spec.Schema{
SchemaProps: spec.SchemaProps{
Type: []string{"object"},
Properties: map[string]spec.Schema{
"clientID": {
SchemaProps: spec.SchemaProps{
Description: "App client ID",
Default: "",
Type: []string{"string"},
Format: "",
},
},
},
Required: []string{"clientID"},
},
},
}
}
func schema_pkg_apis_provisioning_v0alpha1_BitbucketRepositoryConfig(ref common.ReferenceCallback) common.OpenAPIDefinition {
return common.OpenAPIDefinition{
Schema: spec.Schema{
@@ -171,236 +142,6 @@ func schema_pkg_apis_provisioning_v0alpha1_BitbucketRepositoryConfig(ref common.
}
}
func schema_pkg_apis_provisioning_v0alpha1_Connection(ref common.ReferenceCallback) common.OpenAPIDefinition {
return common.OpenAPIDefinition{
Schema: spec.Schema{
SchemaProps: spec.SchemaProps{
Description: "When this code is changed, make sure to update the code generation. As of writing, this can be done via the hack dir in the root of the repo: ./hack/update-codegen.sh provisioning If you've opened the generated files in this dir at some point in VSCode, you may also have to re-open them to clear errors.",
Type: []string{"object"},
Properties: map[string]spec.Schema{
"kind": {
SchemaProps: spec.SchemaProps{
Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds",
Type: []string{"string"},
Format: "",
},
},
"apiVersion": {
SchemaProps: spec.SchemaProps{
Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources",
Type: []string{"string"},
Format: "",
},
},
"metadata": {
SchemaProps: spec.SchemaProps{
Default: map[string]interface{}{},
Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"),
},
},
"spec": {
SchemaProps: spec.SchemaProps{
Default: map[string]interface{}{},
Ref: ref("github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1.ConnectionSpec"),
},
},
"secure": {
SchemaProps: spec.SchemaProps{
Default: map[string]interface{}{},
Ref: ref("github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1.ConnectionSecure"),
},
},
"status": {
SchemaProps: spec.SchemaProps{
Default: map[string]interface{}{},
Ref: ref("github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1.ConnectionStatus"),
},
},
},
},
},
Dependencies: []string{
"github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1.ConnectionSecure", "github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1.ConnectionSpec", "github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1.ConnectionStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"},
}
}
func schema_pkg_apis_provisioning_v0alpha1_ConnectionList(ref common.ReferenceCallback) common.OpenAPIDefinition {
return common.OpenAPIDefinition{
Schema: spec.Schema{
SchemaProps: spec.SchemaProps{
Type: []string{"object"},
Properties: map[string]spec.Schema{
"kind": {
SchemaProps: spec.SchemaProps{
Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds",
Type: []string{"string"},
Format: "",
},
},
"apiVersion": {
SchemaProps: spec.SchemaProps{
Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources",
Type: []string{"string"},
Format: "",
},
},
"metadata": {
SchemaProps: spec.SchemaProps{
Default: map[string]interface{}{},
Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"),
},
},
"items": {
VendorExtensible: spec.VendorExtensible{
Extensions: spec.Extensions{
"x-kubernetes-list-type": "atomic",
},
},
SchemaProps: spec.SchemaProps{
Type: []string{"array"},
Items: &spec.SchemaOrArray{
Schema: &spec.Schema{
SchemaProps: spec.SchemaProps{
Default: map[string]interface{}{},
Ref: ref("github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1.Connection"),
},
},
},
},
},
},
Required: []string{"items"},
},
},
Dependencies: []string{
"github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1.Connection", "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"},
}
}
func schema_pkg_apis_provisioning_v0alpha1_ConnectionSecure(ref common.ReferenceCallback) common.OpenAPIDefinition {
return common.OpenAPIDefinition{
Schema: spec.Schema{
SchemaProps: spec.SchemaProps{
Type: []string{"object"},
Properties: map[string]spec.Schema{
"privateKey": {
SchemaProps: spec.SchemaProps{
Description: "PrivateKey is the reference to the private key used for GitHub App authentication. This value is stored securely and cannot be read back",
Default: map[string]interface{}{},
Ref: ref("github.com/grafana/grafana/pkg/apimachinery/apis/common/v0alpha1.InlineSecureValue"),
},
},
"clientSecret": {
SchemaProps: spec.SchemaProps{
Description: "ClientSecret is the reference to the secret used for other providers authentication, and Github on-behalf-of authentication. This value is stored securely and cannot be read back",
Default: map[string]interface{}{},
Ref: ref("github.com/grafana/grafana/pkg/apimachinery/apis/common/v0alpha1.InlineSecureValue"),
},
},
"webhook": {
SchemaProps: spec.SchemaProps{
Description: "Token is the reference of the token used to act as the Connection. This value is stored securely and cannot be read back",
Default: map[string]interface{}{},
Ref: ref("github.com/grafana/grafana/pkg/apimachinery/apis/common/v0alpha1.InlineSecureValue"),
},
},
},
},
},
Dependencies: []string{
"github.com/grafana/grafana/pkg/apimachinery/apis/common/v0alpha1.InlineSecureValue"},
}
}
func schema_pkg_apis_provisioning_v0alpha1_ConnectionSpec(ref common.ReferenceCallback) common.OpenAPIDefinition {
return common.OpenAPIDefinition{
Schema: spec.Schema{
SchemaProps: spec.SchemaProps{
Type: []string{"object"},
Properties: map[string]spec.Schema{
"type": {
SchemaProps: spec.SchemaProps{
Description: "The connection provider type\n\nPossible enum values:\n - `\"bitbucket\"`\n - `\"github\"`\n - `\"gitlab\"`",
Default: "",
Type: []string{"string"},
Format: "",
Enum: []interface{}{"bitbucket", "github", "gitlab"},
},
},
"url": {
SchemaProps: spec.SchemaProps{
Description: "The connection URL",
Type: []string{"string"},
Format: "",
},
},
"github": {
SchemaProps: spec.SchemaProps{
Description: "GitHub connection configuration Only applicable when provider is \"github\"",
Ref: ref("github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1.GitHubConnectionConfig"),
},
},
"bitbucket": {
SchemaProps: spec.SchemaProps{
Description: "Bitbucket connection configuration Only applicable when provider is \"bitbucket\"",
Ref: ref("github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1.BitbucketConnectionConfig"),
},
},
"gitlab": {
SchemaProps: spec.SchemaProps{
Description: "Gitlab connection configuration Only applicable when provider is \"gitlab\"",
Ref: ref("github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1.GitlabConnectionConfig"),
},
},
},
Required: []string{"type"},
},
},
Dependencies: []string{
"github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1.BitbucketConnectionConfig", "github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1.GitHubConnectionConfig", "github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1.GitlabConnectionConfig"},
}
}
func schema_pkg_apis_provisioning_v0alpha1_ConnectionStatus(ref common.ReferenceCallback) common.OpenAPIDefinition {
return common.OpenAPIDefinition{
Schema: spec.Schema{
SchemaProps: spec.SchemaProps{
Description: "The status of a Connection. This is expected never to be created by a kubectl call or similar, and is expected to rarely (if ever) be edited manually.",
Type: []string{"object"},
Properties: map[string]spec.Schema{
"observedGeneration": {
SchemaProps: spec.SchemaProps{
Description: "The generation of the spec last time reconciliation ran",
Default: 0,
Type: []string{"integer"},
Format: "int64",
},
},
"state": {
SchemaProps: spec.SchemaProps{
Description: "Connection state\n\nPossible enum values:\n - `\"connected\"`\n - `\"disconnected\"`",
Default: "",
Type: []string{"string"},
Format: "",
Enum: []interface{}{"connected", "disconnected"},
},
},
"health": {
SchemaProps: spec.SchemaProps{
Description: "The connection health status",
Default: map[string]interface{}{},
Ref: ref("github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1.HealthStatus"),
},
},
},
Required: []string{"observedGeneration", "state", "health"},
},
},
Dependencies: []string{
"github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1.HealthStatus"},
}
}
func schema_pkg_apis_provisioning_v0alpha1_DeleteJobOptions(ref common.ReferenceCallback) common.OpenAPIDefinition {
return common.OpenAPIDefinition{
Schema: spec.Schema{
@@ -621,35 +362,6 @@ func schema_pkg_apis_provisioning_v0alpha1_FileList(ref common.ReferenceCallback
}
}
func schema_pkg_apis_provisioning_v0alpha1_GitHubConnectionConfig(ref common.ReferenceCallback) common.OpenAPIDefinition {
return common.OpenAPIDefinition{
Schema: spec.Schema{
SchemaProps: spec.SchemaProps{
Type: []string{"object"},
Properties: map[string]spec.Schema{
"appID": {
SchemaProps: spec.SchemaProps{
Description: "GitHub App ID",
Default: "",
Type: []string{"string"},
Format: "",
},
},
"installationID": {
SchemaProps: spec.SchemaProps{
Description: "GitHub App installation ID",
Default: "",
Type: []string{"string"},
Format: "",
},
},
},
Required: []string{"appID", "installationID"},
},
},
}
}
func schema_pkg_apis_provisioning_v0alpha1_GitHubRepositoryConfig(ref common.ReferenceCallback) common.OpenAPIDefinition {
return common.OpenAPIDefinition{
Schema: spec.Schema{
@@ -769,27 +481,6 @@ func schema_pkg_apis_provisioning_v0alpha1_GitRepositoryConfig(ref common.Refere
}
}
func schema_pkg_apis_provisioning_v0alpha1_GitlabConnectionConfig(ref common.ReferenceCallback) common.OpenAPIDefinition {
return common.OpenAPIDefinition{
Schema: spec.Schema{
SchemaProps: spec.SchemaProps{
Type: []string{"object"},
Properties: map[string]spec.Schema{
"clientID": {
SchemaProps: spec.SchemaProps{
Description: "App client ID",
Default: "",
Type: []string{"string"},
Format: "",
},
},
},
Required: []string{"clientID"},
},
},
}
}
func schema_pkg_apis_provisioning_v0alpha1_HealthStatus(ref common.ReferenceCallback) common.OpenAPIDefinition {
return common.OpenAPIDefinition{
Schema: spec.Schema{
@@ -1198,13 +889,6 @@ func schema_pkg_apis_provisioning_v0alpha1_JobResourceSummary(ref common.Referen
Format: "int64",
},
},
"warning": {
SchemaProps: spec.SchemaProps{
Description: "The error count",
Type: []string{"integer"},
Format: "int64",
},
},
"noop": {
SchemaProps: spec.SchemaProps{
Description: "No action required (useful for sync)",
@@ -1214,7 +898,7 @@ func schema_pkg_apis_provisioning_v0alpha1_JobResourceSummary(ref common.Referen
},
"errors": {
SchemaProps: spec.SchemaProps{
Description: "Report errors/warnings for this resource type This may not be an exhaustive list and recommend looking at the logs for more info",
Description: "Report errors for this resource type This may not be an exhaustive list and recommend looking at the logs for more info",
Type: []string{"array"},
Items: &spec.SchemaOrArray{
Schema: &spec.Schema{
@@ -1227,20 +911,6 @@ func schema_pkg_apis_provisioning_v0alpha1_JobResourceSummary(ref common.Referen
},
},
},
"warnings": {
SchemaProps: spec.SchemaProps{
Type: []string{"array"},
Items: &spec.SchemaOrArray{
Schema: &spec.Schema{
SchemaProps: spec.SchemaProps{
Default: "",
Type: []string{"string"},
Format: "",
},
},
},
},
},
},
},
},
@@ -1359,20 +1029,6 @@ func schema_pkg_apis_provisioning_v0alpha1_JobStatus(ref common.ReferenceCallbac
},
},
},
"warnings": {
SchemaProps: spec.SchemaProps{
Type: []string{"array"},
Items: &spec.SchemaOrArray{
Schema: &spec.Schema{
SchemaProps: spec.SchemaProps{
Default: "",
Type: []string{"string"},
Format: "",
},
},
},
},
},
"progress": {
SchemaProps: spec.SchemaProps{
Description: "Optional value 0-100 that can be set while running",

View File

@@ -1,13 +1,10 @@
API rule violation: list_type_missing,github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1,ConnectionList,Items
API rule violation: list_type_missing,github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1,DeleteJobOptions,Paths
API rule violation: list_type_missing,github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1,DeleteJobOptions,Resources
API rule violation: list_type_missing,github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1,FileList,Items
API rule violation: list_type_missing,github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1,HistoryList,Items
API rule violation: list_type_missing,github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1,JobResourceSummary,Errors
API rule violation: list_type_missing,github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1,JobResourceSummary,Warnings
API rule violation: list_type_missing,github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1,JobStatus,Errors
API rule violation: list_type_missing,github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1,JobStatus,Summary
API rule violation: list_type_missing,github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1,JobStatus,Warnings
API rule violation: list_type_missing,github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1,ManagerStats,Stats
API rule violation: list_type_missing,github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1,MoveJobOptions,Paths
API rule violation: list_type_missing,github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1,MoveJobOptions,Resources
@@ -21,8 +18,6 @@ API rule violation: list_type_missing,github.com/grafana/grafana/apps/provisioni
API rule violation: list_type_missing,github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1,ResourceList,Items
API rule violation: list_type_missing,github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1,TestResults,Errors
API rule violation: list_type_missing,github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1,WebhookStatus,SubscribedEvents
API rule violation: names_match,github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1,ConnectionSecure,Token
API rule violation: names_match,github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1,ConnectionSpec,GitHub
API rule violation: names_match,github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1,JobSpec,PullRequest
API rule violation: names_match,github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1,JobStatus,URLs
API rule violation: names_match,github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1,ManagerStats,Identity

View File

@@ -1,28 +0,0 @@
package connection
import (
"fmt"
provisioning "github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1"
)
const (
githubInstallationURL = "https://github.com/settings/installations"
)
func MutateConnection(connection *provisioning.Connection) error {
switch connection.Spec.Type {
case provisioning.GithubConnectionType:
// Do nothing in case spec.Github is nil.
// If this field is required, we should fail at validation time.
if connection.Spec.GitHub == nil {
return nil
}
connection.Spec.URL = fmt.Sprintf("%s/%s", githubInstallationURL, connection.Spec.GitHub.InstallationID)
return nil
default:
// TODO: we need to setup the URL for bitbucket and gitlab.
return nil
}
}

View File

@@ -1,35 +0,0 @@
package connection_test
import (
"testing"
provisioning "github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1"
"github.com/grafana/grafana/apps/provisioning/pkg/connection"
common "github.com/grafana/grafana/pkg/apimachinery/apis/common/v0alpha1"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
func TestMutateConnection(t *testing.T) {
t.Run("should add URL to Github connection", func(t *testing.T) {
c := &provisioning.Connection{
ObjectMeta: metav1.ObjectMeta{Name: "test-connection"},
Spec: provisioning.ConnectionSpec{
Type: provisioning.GithubConnectionType,
GitHub: &provisioning.GitHubConnectionConfig{
AppID: "123",
InstallationID: "456",
},
},
Secure: provisioning.ConnectionSecure{
PrivateKey: common.InlineSecureValue{
Name: "test-private-key",
},
},
}
require.NoError(t, connection.MutateConnection(c))
assert.Equal(t, "https://github.com/settings/installations/456", c.Spec.URL)
})
}

View File

@@ -1,104 +0,0 @@
package connection
import (
provisioning "github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/util/validation/field"
)
func ValidateConnection(connection *provisioning.Connection) error {
list := field.ErrorList{}
if connection.Spec.Type == "" {
list = append(list, field.Required(field.NewPath("spec", "type"), "type must be specified"))
}
switch connection.Spec.Type {
case provisioning.GithubConnectionType:
list = append(list, validateGithubConnection(connection)...)
case provisioning.BitbucketConnectionType:
list = append(list, validateBitbucketConnection(connection)...)
case provisioning.GitlabConnectionType:
list = append(list, validateGitlabConnection(connection)...)
default:
list = append(
list, field.NotSupported(
field.NewPath("spec", "type"),
connection.Spec.Type,
[]provisioning.ConnectionType{
provisioning.GithubConnectionType,
provisioning.BitbucketConnectionType,
provisioning.GitlabConnectionType,
}),
)
}
return toError(connection.GetName(), list)
}
func validateGithubConnection(connection *provisioning.Connection) field.ErrorList {
list := field.ErrorList{}
if connection.Spec.GitHub == nil {
list = append(
list, field.Required(field.NewPath("spec", "github"), "github info must be specified for GitHub connection"),
)
}
if connection.Secure.PrivateKey.IsZero() {
list = append(list, field.Required(field.NewPath("secure", "privateKey"), "privateKey must be specified for GitHub connection"))
}
if !connection.Secure.ClientSecret.IsZero() {
list = append(list, field.Forbidden(field.NewPath("secure", "clientSecret"), "clientSecret is forbidden in GitHub connection"))
}
return list
}
func validateBitbucketConnection(connection *provisioning.Connection) field.ErrorList {
list := field.ErrorList{}
if connection.Spec.Bitbucket == nil {
list = append(
list, field.Required(field.NewPath("spec", "bitbucket"), "bitbucket info must be specified in Bitbucket connection"),
)
}
if connection.Secure.ClientSecret.IsZero() {
list = append(list, field.Required(field.NewPath("secure", "clientSecret"), "clientSecret must be specified for Bitbucket connection"))
}
if !connection.Secure.PrivateKey.IsZero() {
list = append(list, field.Forbidden(field.NewPath("secure", "privateKey"), "privateKey is forbidden in Bitbucket connection"))
}
return list
}
func validateGitlabConnection(connection *provisioning.Connection) field.ErrorList {
list := field.ErrorList{}
if connection.Spec.Gitlab == nil {
list = append(
list, field.Required(field.NewPath("spec", "gitlab"), "gitlab info must be specified in Gitlab connection"),
)
}
if connection.Secure.ClientSecret.IsZero() {
list = append(list, field.Required(field.NewPath("secure", "clientSecret"), "clientSecret must be specified for Gitlab connection"))
}
if !connection.Secure.PrivateKey.IsZero() {
list = append(list, field.Forbidden(field.NewPath("secure", "privateKey"), "privateKey is forbidden in Gitlab connection"))
}
return list
}
// toError converts a field.ErrorList to an error, returning nil if the list is empty
func toError(name string, list field.ErrorList) error {
if len(list) == 0 {
return nil
}
return apierrors.NewInvalid(
provisioning.ConnectionResourceInfo.GroupVersionKind().GroupKind(),
name,
list,
)
}

View File

@@ -1,253 +0,0 @@
package connection_test
import (
"testing"
provisioning "github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1"
"github.com/grafana/grafana/apps/provisioning/pkg/connection"
common "github.com/grafana/grafana/pkg/apimachinery/apis/common/v0alpha1"
"github.com/stretchr/testify/assert"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
func TestValidateConnection(t *testing.T) {
tests := []struct {
name string
connection *provisioning.Connection
wantErr bool
errMsg string
}{
{
name: "empty type returns error",
connection: &provisioning.Connection{
ObjectMeta: metav1.ObjectMeta{Name: "test-connection"},
Spec: provisioning.ConnectionSpec{},
},
wantErr: true,
errMsg: "spec.type",
},
{
name: "invalid type returns error",
connection: &provisioning.Connection{
ObjectMeta: metav1.ObjectMeta{Name: "test-connection"},
Spec: provisioning.ConnectionSpec{
Type: "invalid",
},
},
wantErr: true,
errMsg: "spec.type",
},
{
name: "github type without github config returns error",
connection: &provisioning.Connection{
ObjectMeta: metav1.ObjectMeta{Name: "test-connection"},
Spec: provisioning.ConnectionSpec{
Type: provisioning.GithubConnectionType,
},
},
wantErr: true,
errMsg: "spec.github",
},
{
name: "github type without private key returns error",
connection: &provisioning.Connection{
ObjectMeta: metav1.ObjectMeta{Name: "test-connection"},
Spec: provisioning.ConnectionSpec{
Type: provisioning.GithubConnectionType,
GitHub: &provisioning.GitHubConnectionConfig{
AppID: "123",
InstallationID: "456",
},
},
},
wantErr: true,
errMsg: "secure.privateKey",
},
{
name: "github type with client secret returns error",
connection: &provisioning.Connection{
ObjectMeta: metav1.ObjectMeta{Name: "test-connection"},
Spec: provisioning.ConnectionSpec{
Type: provisioning.GithubConnectionType,
GitHub: &provisioning.GitHubConnectionConfig{
AppID: "123",
InstallationID: "456",
},
},
Secure: provisioning.ConnectionSecure{
PrivateKey: common.InlineSecureValue{
Name: "test-private-key",
},
ClientSecret: common.InlineSecureValue{
Name: "test-client-secret",
},
},
},
wantErr: true,
errMsg: "secure.clientSecret",
},
{
name: "github type with github config is valid",
connection: &provisioning.Connection{
ObjectMeta: metav1.ObjectMeta{Name: "test-connection"},
Spec: provisioning.ConnectionSpec{
Type: provisioning.GithubConnectionType,
GitHub: &provisioning.GitHubConnectionConfig{
AppID: "123",
InstallationID: "456",
},
},
Secure: provisioning.ConnectionSecure{
PrivateKey: common.InlineSecureValue{
Name: "test-private-key",
},
},
},
wantErr: false,
},
{
name: "bitbucket type without bitbucket config returns error",
connection: &provisioning.Connection{
ObjectMeta: metav1.ObjectMeta{Name: "test-connection"},
Spec: provisioning.ConnectionSpec{
Type: provisioning.BitbucketConnectionType,
},
},
wantErr: true,
errMsg: "spec.bitbucket",
},
{
name: "bitbucket type without client secret returns error",
connection: &provisioning.Connection{
ObjectMeta: metav1.ObjectMeta{Name: "test-connection"},
Spec: provisioning.ConnectionSpec{
Type: provisioning.BitbucketConnectionType,
Bitbucket: &provisioning.BitbucketConnectionConfig{
ClientID: "client-123",
},
},
},
wantErr: true,
errMsg: "secure.clientSecret",
},
{
name: "bitbucket type with private key returns error",
connection: &provisioning.Connection{
ObjectMeta: metav1.ObjectMeta{Name: "test-connection"},
Spec: provisioning.ConnectionSpec{
Type: provisioning.BitbucketConnectionType,
Bitbucket: &provisioning.BitbucketConnectionConfig{
ClientID: "client-123",
},
},
Secure: provisioning.ConnectionSecure{
PrivateKey: common.InlineSecureValue{
Name: "test-private-key",
},
ClientSecret: common.InlineSecureValue{
Name: "test-client-secret",
},
},
},
wantErr: true,
errMsg: "secure.privateKey",
},
{
name: "bitbucket type with bitbucket config is valid",
connection: &provisioning.Connection{
ObjectMeta: metav1.ObjectMeta{Name: "test-connection"},
Spec: provisioning.ConnectionSpec{
Type: provisioning.BitbucketConnectionType,
Bitbucket: &provisioning.BitbucketConnectionConfig{
ClientID: "client-123",
},
},
Secure: provisioning.ConnectionSecure{
ClientSecret: common.InlineSecureValue{
Name: "test-client-secret",
},
},
},
wantErr: false,
},
{
name: "gitlab type without gitlab config returns error",
connection: &provisioning.Connection{
ObjectMeta: metav1.ObjectMeta{Name: "test-connection"},
Spec: provisioning.ConnectionSpec{
Type: provisioning.GitlabConnectionType,
},
},
wantErr: true,
errMsg: "spec.gitlab",
},
{
name: "gitlab type without client secret returns error",
connection: &provisioning.Connection{
ObjectMeta: metav1.ObjectMeta{Name: "test-connection"},
Spec: provisioning.ConnectionSpec{
Type: provisioning.GitlabConnectionType,
Gitlab: &provisioning.GitlabConnectionConfig{
ClientID: "client-456",
},
},
},
wantErr: true,
errMsg: "secure.clientSecret",
},
{
name: "gitlab type with private key returns error",
connection: &provisioning.Connection{
ObjectMeta: metav1.ObjectMeta{Name: "test-connection"},
Spec: provisioning.ConnectionSpec{
Type: provisioning.GitlabConnectionType,
Gitlab: &provisioning.GitlabConnectionConfig{
ClientID: "client-456",
},
},
Secure: provisioning.ConnectionSecure{
PrivateKey: common.InlineSecureValue{
Name: "test-private-key",
},
ClientSecret: common.InlineSecureValue{
Name: "test-client-secret",
},
},
},
wantErr: true,
errMsg: "secure.privateKey",
},
{
name: "gitlab type with gitlab config is valid",
connection: &provisioning.Connection{
ObjectMeta: metav1.ObjectMeta{Name: "test-connection"},
Spec: provisioning.ConnectionSpec{
Type: provisioning.GitlabConnectionType,
Gitlab: &provisioning.GitlabConnectionConfig{
ClientID: "client-456",
},
},
Secure: provisioning.ConnectionSecure{
ClientSecret: common.InlineSecureValue{
Name: "test-client-secret",
},
},
},
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := connection.ValidateConnection(tt.connection)
if tt.wantErr {
assert.Error(t, err)
if tt.errMsg != "" {
assert.Contains(t, err.Error(), tt.errMsg)
}
} else {
assert.NoError(t, err)
}
})
}
}

View File

@@ -1,25 +0,0 @@
// SPDX-License-Identifier: AGPL-3.0-only
// Code generated by applyconfiguration-gen. DO NOT EDIT.
package v0alpha1
// BitbucketConnectionConfigApplyConfiguration represents a declarative configuration of the BitbucketConnectionConfig type for use
// with apply.
type BitbucketConnectionConfigApplyConfiguration struct {
ClientID *string `json:"clientID,omitempty"`
}
// BitbucketConnectionConfigApplyConfiguration constructs a declarative configuration of the BitbucketConnectionConfig type for use with
// apply.
func BitbucketConnectionConfig() *BitbucketConnectionConfigApplyConfiguration {
return &BitbucketConnectionConfigApplyConfiguration{}
}
// WithClientID sets the ClientID field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the ClientID field is set to the value of the last call.
func (b *BitbucketConnectionConfigApplyConfiguration) WithClientID(value string) *BitbucketConnectionConfigApplyConfiguration {
b.ClientID = &value
return b
}

View File

@@ -1,237 +0,0 @@
// SPDX-License-Identifier: AGPL-3.0-only
// Code generated by applyconfiguration-gen. DO NOT EDIT.
package v0alpha1
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
types "k8s.io/apimachinery/pkg/types"
v1 "k8s.io/client-go/applyconfigurations/meta/v1"
)
// ConnectionApplyConfiguration represents a declarative configuration of the Connection type for use
// with apply.
type ConnectionApplyConfiguration struct {
v1.TypeMetaApplyConfiguration `json:",inline"`
*v1.ObjectMetaApplyConfiguration `json:"metadata,omitempty"`
Spec *ConnectionSpecApplyConfiguration `json:"spec,omitempty"`
Secure *ConnectionSecureApplyConfiguration `json:"secure,omitempty"`
Status *ConnectionStatusApplyConfiguration `json:"status,omitempty"`
}
// Connection constructs a declarative configuration of the Connection type for use with
// apply.
func Connection(name, namespace string) *ConnectionApplyConfiguration {
b := &ConnectionApplyConfiguration{}
b.WithName(name)
b.WithNamespace(namespace)
b.WithKind("Connection")
b.WithAPIVersion("provisioning.grafana.app/v0alpha1")
return b
}
func (b ConnectionApplyConfiguration) IsApplyConfiguration() {}
// WithKind sets the Kind field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the Kind field is set to the value of the last call.
func (b *ConnectionApplyConfiguration) WithKind(value string) *ConnectionApplyConfiguration {
b.TypeMetaApplyConfiguration.Kind = &value
return b
}
// WithAPIVersion sets the APIVersion field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the APIVersion field is set to the value of the last call.
func (b *ConnectionApplyConfiguration) WithAPIVersion(value string) *ConnectionApplyConfiguration {
b.TypeMetaApplyConfiguration.APIVersion = &value
return b
}
// WithName sets the Name field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the Name field is set to the value of the last call.
func (b *ConnectionApplyConfiguration) WithName(value string) *ConnectionApplyConfiguration {
b.ensureObjectMetaApplyConfigurationExists()
b.ObjectMetaApplyConfiguration.Name = &value
return b
}
// WithGenerateName sets the GenerateName field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the GenerateName field is set to the value of the last call.
func (b *ConnectionApplyConfiguration) WithGenerateName(value string) *ConnectionApplyConfiguration {
b.ensureObjectMetaApplyConfigurationExists()
b.ObjectMetaApplyConfiguration.GenerateName = &value
return b
}
// WithNamespace sets the Namespace field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the Namespace field is set to the value of the last call.
func (b *ConnectionApplyConfiguration) WithNamespace(value string) *ConnectionApplyConfiguration {
b.ensureObjectMetaApplyConfigurationExists()
b.ObjectMetaApplyConfiguration.Namespace = &value
return b
}
// WithUID sets the UID field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the UID field is set to the value of the last call.
func (b *ConnectionApplyConfiguration) WithUID(value types.UID) *ConnectionApplyConfiguration {
b.ensureObjectMetaApplyConfigurationExists()
b.ObjectMetaApplyConfiguration.UID = &value
return b
}
// WithResourceVersion sets the ResourceVersion field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the ResourceVersion field is set to the value of the last call.
func (b *ConnectionApplyConfiguration) WithResourceVersion(value string) *ConnectionApplyConfiguration {
b.ensureObjectMetaApplyConfigurationExists()
b.ObjectMetaApplyConfiguration.ResourceVersion = &value
return b
}
// WithGeneration sets the Generation field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the Generation field is set to the value of the last call.
func (b *ConnectionApplyConfiguration) WithGeneration(value int64) *ConnectionApplyConfiguration {
b.ensureObjectMetaApplyConfigurationExists()
b.ObjectMetaApplyConfiguration.Generation = &value
return b
}
// WithCreationTimestamp sets the CreationTimestamp field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the CreationTimestamp field is set to the value of the last call.
func (b *ConnectionApplyConfiguration) WithCreationTimestamp(value metav1.Time) *ConnectionApplyConfiguration {
b.ensureObjectMetaApplyConfigurationExists()
b.ObjectMetaApplyConfiguration.CreationTimestamp = &value
return b
}
// WithDeletionTimestamp sets the DeletionTimestamp field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the DeletionTimestamp field is set to the value of the last call.
func (b *ConnectionApplyConfiguration) WithDeletionTimestamp(value metav1.Time) *ConnectionApplyConfiguration {
b.ensureObjectMetaApplyConfigurationExists()
b.ObjectMetaApplyConfiguration.DeletionTimestamp = &value
return b
}
// WithDeletionGracePeriodSeconds sets the DeletionGracePeriodSeconds field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the DeletionGracePeriodSeconds field is set to the value of the last call.
func (b *ConnectionApplyConfiguration) WithDeletionGracePeriodSeconds(value int64) *ConnectionApplyConfiguration {
b.ensureObjectMetaApplyConfigurationExists()
b.ObjectMetaApplyConfiguration.DeletionGracePeriodSeconds = &value
return b
}
// WithLabels puts the entries into the Labels field in the declarative configuration
// and returns the receiver, so that objects can be build by chaining "With" function invocations.
// If called multiple times, the entries provided by each call will be put on the Labels field,
// overwriting an existing map entries in Labels field with the same key.
func (b *ConnectionApplyConfiguration) WithLabels(entries map[string]string) *ConnectionApplyConfiguration {
b.ensureObjectMetaApplyConfigurationExists()
if b.ObjectMetaApplyConfiguration.Labels == nil && len(entries) > 0 {
b.ObjectMetaApplyConfiguration.Labels = make(map[string]string, len(entries))
}
for k, v := range entries {
b.ObjectMetaApplyConfiguration.Labels[k] = v
}
return b
}
// WithAnnotations puts the entries into the Annotations field in the declarative configuration
// and returns the receiver, so that objects can be build by chaining "With" function invocations.
// If called multiple times, the entries provided by each call will be put on the Annotations field,
// overwriting an existing map entries in Annotations field with the same key.
func (b *ConnectionApplyConfiguration) WithAnnotations(entries map[string]string) *ConnectionApplyConfiguration {
b.ensureObjectMetaApplyConfigurationExists()
if b.ObjectMetaApplyConfiguration.Annotations == nil && len(entries) > 0 {
b.ObjectMetaApplyConfiguration.Annotations = make(map[string]string, len(entries))
}
for k, v := range entries {
b.ObjectMetaApplyConfiguration.Annotations[k] = v
}
return b
}
// WithOwnerReferences adds the given value to the OwnerReferences field in the declarative configuration
// and returns the receiver, so that objects can be build by chaining "With" function invocations.
// If called multiple times, values provided by each call will be appended to the OwnerReferences field.
func (b *ConnectionApplyConfiguration) WithOwnerReferences(values ...*v1.OwnerReferenceApplyConfiguration) *ConnectionApplyConfiguration {
b.ensureObjectMetaApplyConfigurationExists()
for i := range values {
if values[i] == nil {
panic("nil value passed to WithOwnerReferences")
}
b.ObjectMetaApplyConfiguration.OwnerReferences = append(b.ObjectMetaApplyConfiguration.OwnerReferences, *values[i])
}
return b
}
// WithFinalizers adds the given value to the Finalizers field in the declarative configuration
// and returns the receiver, so that objects can be build by chaining "With" function invocations.
// If called multiple times, values provided by each call will be appended to the Finalizers field.
func (b *ConnectionApplyConfiguration) WithFinalizers(values ...string) *ConnectionApplyConfiguration {
b.ensureObjectMetaApplyConfigurationExists()
for i := range values {
b.ObjectMetaApplyConfiguration.Finalizers = append(b.ObjectMetaApplyConfiguration.Finalizers, values[i])
}
return b
}
func (b *ConnectionApplyConfiguration) ensureObjectMetaApplyConfigurationExists() {
if b.ObjectMetaApplyConfiguration == nil {
b.ObjectMetaApplyConfiguration = &v1.ObjectMetaApplyConfiguration{}
}
}
// WithSpec sets the Spec field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the Spec field is set to the value of the last call.
func (b *ConnectionApplyConfiguration) WithSpec(value *ConnectionSpecApplyConfiguration) *ConnectionApplyConfiguration {
b.Spec = value
return b
}
// WithSecure sets the Secure field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the Secure field is set to the value of the last call.
func (b *ConnectionApplyConfiguration) WithSecure(value *ConnectionSecureApplyConfiguration) *ConnectionApplyConfiguration {
b.Secure = value
return b
}
// WithStatus sets the Status field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the Status field is set to the value of the last call.
func (b *ConnectionApplyConfiguration) WithStatus(value *ConnectionStatusApplyConfiguration) *ConnectionApplyConfiguration {
b.Status = value
return b
}
// GetKind retrieves the value of the Kind field in the declarative configuration.
func (b *ConnectionApplyConfiguration) GetKind() *string {
return b.TypeMetaApplyConfiguration.Kind
}
// GetAPIVersion retrieves the value of the APIVersion field in the declarative configuration.
func (b *ConnectionApplyConfiguration) GetAPIVersion() *string {
return b.TypeMetaApplyConfiguration.APIVersion
}
// GetName retrieves the value of the Name field in the declarative configuration.
func (b *ConnectionApplyConfiguration) GetName() *string {
b.ensureObjectMetaApplyConfigurationExists()
return b.ObjectMetaApplyConfiguration.Name
}
// GetNamespace retrieves the value of the Namespace field in the declarative configuration.
func (b *ConnectionApplyConfiguration) GetNamespace() *string {
b.ensureObjectMetaApplyConfigurationExists()
return b.ObjectMetaApplyConfiguration.Namespace
}

View File

@@ -1,47 +0,0 @@
// SPDX-License-Identifier: AGPL-3.0-only
// Code generated by applyconfiguration-gen. DO NOT EDIT.
package v0alpha1
import (
commonv0alpha1 "github.com/grafana/grafana/pkg/apimachinery/apis/common/v0alpha1"
)
// ConnectionSecureApplyConfiguration represents a declarative configuration of the ConnectionSecure type for use
// with apply.
type ConnectionSecureApplyConfiguration struct {
PrivateKey *commonv0alpha1.InlineSecureValue `json:"privateKey,omitempty"`
ClientSecret *commonv0alpha1.InlineSecureValue `json:"clientSecret,omitempty"`
Token *commonv0alpha1.InlineSecureValue `json:"webhook,omitempty"`
}
// ConnectionSecureApplyConfiguration constructs a declarative configuration of the ConnectionSecure type for use with
// apply.
func ConnectionSecure() *ConnectionSecureApplyConfiguration {
return &ConnectionSecureApplyConfiguration{}
}
// WithPrivateKey sets the PrivateKey field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the PrivateKey field is set to the value of the last call.
func (b *ConnectionSecureApplyConfiguration) WithPrivateKey(value commonv0alpha1.InlineSecureValue) *ConnectionSecureApplyConfiguration {
b.PrivateKey = &value
return b
}
// WithClientSecret sets the ClientSecret field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the ClientSecret field is set to the value of the last call.
func (b *ConnectionSecureApplyConfiguration) WithClientSecret(value commonv0alpha1.InlineSecureValue) *ConnectionSecureApplyConfiguration {
b.ClientSecret = &value
return b
}
// WithToken sets the Token field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the Token field is set to the value of the last call.
func (b *ConnectionSecureApplyConfiguration) WithToken(value commonv0alpha1.InlineSecureValue) *ConnectionSecureApplyConfiguration {
b.Token = &value
return b
}

View File

@@ -1,65 +0,0 @@
// SPDX-License-Identifier: AGPL-3.0-only
// Code generated by applyconfiguration-gen. DO NOT EDIT.
package v0alpha1
import (
provisioningv0alpha1 "github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1"
)
// ConnectionSpecApplyConfiguration represents a declarative configuration of the ConnectionSpec type for use
// with apply.
type ConnectionSpecApplyConfiguration struct {
Type *provisioningv0alpha1.ConnectionType `json:"type,omitempty"`
URL *string `json:"url,omitempty"`
GitHub *GitHubConnectionConfigApplyConfiguration `json:"github,omitempty"`
Bitbucket *BitbucketConnectionConfigApplyConfiguration `json:"bitbucket,omitempty"`
Gitlab *GitlabConnectionConfigApplyConfiguration `json:"gitlab,omitempty"`
}
// ConnectionSpecApplyConfiguration constructs a declarative configuration of the ConnectionSpec type for use with
// apply.
func ConnectionSpec() *ConnectionSpecApplyConfiguration {
return &ConnectionSpecApplyConfiguration{}
}
// WithType sets the Type field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the Type field is set to the value of the last call.
func (b *ConnectionSpecApplyConfiguration) WithType(value provisioningv0alpha1.ConnectionType) *ConnectionSpecApplyConfiguration {
b.Type = &value
return b
}
// WithURL sets the URL field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the URL field is set to the value of the last call.
func (b *ConnectionSpecApplyConfiguration) WithURL(value string) *ConnectionSpecApplyConfiguration {
b.URL = &value
return b
}
// WithGitHub sets the GitHub field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the GitHub field is set to the value of the last call.
func (b *ConnectionSpecApplyConfiguration) WithGitHub(value *GitHubConnectionConfigApplyConfiguration) *ConnectionSpecApplyConfiguration {
b.GitHub = value
return b
}
// WithBitbucket sets the Bitbucket field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the Bitbucket field is set to the value of the last call.
func (b *ConnectionSpecApplyConfiguration) WithBitbucket(value *BitbucketConnectionConfigApplyConfiguration) *ConnectionSpecApplyConfiguration {
b.Bitbucket = value
return b
}
// WithGitlab sets the Gitlab field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the Gitlab field is set to the value of the last call.
func (b *ConnectionSpecApplyConfiguration) WithGitlab(value *GitlabConnectionConfigApplyConfiguration) *ConnectionSpecApplyConfiguration {
b.Gitlab = value
return b
}

View File

@@ -1,47 +0,0 @@
// SPDX-License-Identifier: AGPL-3.0-only
// Code generated by applyconfiguration-gen. DO NOT EDIT.
package v0alpha1
import (
provisioningv0alpha1 "github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1"
)
// ConnectionStatusApplyConfiguration represents a declarative configuration of the ConnectionStatus type for use
// with apply.
type ConnectionStatusApplyConfiguration struct {
ObservedGeneration *int64 `json:"observedGeneration,omitempty"`
State *provisioningv0alpha1.ConnectionState `json:"state,omitempty"`
Health *HealthStatusApplyConfiguration `json:"health,omitempty"`
}
// ConnectionStatusApplyConfiguration constructs a declarative configuration of the ConnectionStatus type for use with
// apply.
func ConnectionStatus() *ConnectionStatusApplyConfiguration {
return &ConnectionStatusApplyConfiguration{}
}
// WithObservedGeneration sets the ObservedGeneration field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the ObservedGeneration field is set to the value of the last call.
func (b *ConnectionStatusApplyConfiguration) WithObservedGeneration(value int64) *ConnectionStatusApplyConfiguration {
b.ObservedGeneration = &value
return b
}
// WithState sets the State field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the State field is set to the value of the last call.
func (b *ConnectionStatusApplyConfiguration) WithState(value provisioningv0alpha1.ConnectionState) *ConnectionStatusApplyConfiguration {
b.State = &value
return b
}
// WithHealth sets the Health field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the Health field is set to the value of the last call.
func (b *ConnectionStatusApplyConfiguration) WithHealth(value *HealthStatusApplyConfiguration) *ConnectionStatusApplyConfiguration {
b.Health = value
return b
}

View File

@@ -1,34 +0,0 @@
// SPDX-License-Identifier: AGPL-3.0-only
// Code generated by applyconfiguration-gen. DO NOT EDIT.
package v0alpha1
// GitHubConnectionConfigApplyConfiguration represents a declarative configuration of the GitHubConnectionConfig type for use
// with apply.
type GitHubConnectionConfigApplyConfiguration struct {
AppID *string `json:"appID,omitempty"`
InstallationID *string `json:"installationID,omitempty"`
}
// GitHubConnectionConfigApplyConfiguration constructs a declarative configuration of the GitHubConnectionConfig type for use with
// apply.
func GitHubConnectionConfig() *GitHubConnectionConfigApplyConfiguration {
return &GitHubConnectionConfigApplyConfiguration{}
}
// WithAppID sets the AppID field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the AppID field is set to the value of the last call.
func (b *GitHubConnectionConfigApplyConfiguration) WithAppID(value string) *GitHubConnectionConfigApplyConfiguration {
b.AppID = &value
return b
}
// WithInstallationID sets the InstallationID field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the InstallationID field is set to the value of the last call.
func (b *GitHubConnectionConfigApplyConfiguration) WithInstallationID(value string) *GitHubConnectionConfigApplyConfiguration {
b.InstallationID = &value
return b
}

View File

@@ -1,25 +0,0 @@
// SPDX-License-Identifier: AGPL-3.0-only
// Code generated by applyconfiguration-gen. DO NOT EDIT.
package v0alpha1
// GitlabConnectionConfigApplyConfiguration represents a declarative configuration of the GitlabConnectionConfig type for use
// with apply.
type GitlabConnectionConfigApplyConfiguration struct {
ClientID *string `json:"clientID,omitempty"`
}
// GitlabConnectionConfigApplyConfiguration constructs a declarative configuration of the GitlabConnectionConfig type for use with
// apply.
func GitlabConnectionConfig() *GitlabConnectionConfigApplyConfiguration {
return &GitlabConnectionConfigApplyConfiguration{}
}
// WithClientID sets the ClientID field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the ClientID field is set to the value of the last call.
func (b *GitlabConnectionConfigApplyConfiguration) WithClientID(value string) *GitlabConnectionConfigApplyConfiguration {
b.ClientID = &value
return b
}

View File

@@ -7,18 +7,16 @@ package v0alpha1
// JobResourceSummaryApplyConfiguration represents a declarative configuration of the JobResourceSummary type for use
// with apply.
type JobResourceSummaryApplyConfiguration struct {
Group *string `json:"group,omitempty"`
Kind *string `json:"kind,omitempty"`
Total *int64 `json:"total,omitempty"`
Create *int64 `json:"create,omitempty"`
Update *int64 `json:"update,omitempty"`
Delete *int64 `json:"delete,omitempty"`
Write *int64 `json:"write,omitempty"`
Error *int64 `json:"error,omitempty"`
Warning *int64 `json:"warning,omitempty"`
Noop *int64 `json:"noop,omitempty"`
Errors []string `json:"errors,omitempty"`
Warnings []string `json:"warnings,omitempty"`
Group *string `json:"group,omitempty"`
Kind *string `json:"kind,omitempty"`
Total *int64 `json:"total,omitempty"`
Create *int64 `json:"create,omitempty"`
Update *int64 `json:"update,omitempty"`
Delete *int64 `json:"delete,omitempty"`
Write *int64 `json:"write,omitempty"`
Error *int64 `json:"error,omitempty"`
Noop *int64 `json:"noop,omitempty"`
Errors []string `json:"errors,omitempty"`
}
// JobResourceSummaryApplyConfiguration constructs a declarative configuration of the JobResourceSummary type for use with
@@ -91,14 +89,6 @@ func (b *JobResourceSummaryApplyConfiguration) WithError(value int64) *JobResour
return b
}
// WithWarning sets the Warning field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the Warning field is set to the value of the last call.
func (b *JobResourceSummaryApplyConfiguration) WithWarning(value int64) *JobResourceSummaryApplyConfiguration {
b.Warning = &value
return b
}
// WithNoop sets the Noop field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the Noop field is set to the value of the last call.
@@ -116,13 +106,3 @@ func (b *JobResourceSummaryApplyConfiguration) WithErrors(values ...string) *Job
}
return b
}
// WithWarnings adds the given value to the Warnings field in the declarative configuration
// and returns the receiver, so that objects can be build by chaining "With" function invocations.
// If called multiple times, values provided by each call will be appended to the Warnings field.
func (b *JobResourceSummaryApplyConfiguration) WithWarnings(values ...string) *JobResourceSummaryApplyConfiguration {
for i := range values {
b.Warnings = append(b.Warnings, values[i])
}
return b
}

View File

@@ -16,7 +16,6 @@ type JobStatusApplyConfiguration struct {
Finished *int64 `json:"finished,omitempty"`
Message *string `json:"message,omitempty"`
Errors []string `json:"errors,omitempty"`
Warnings []string `json:"warnings,omitempty"`
Progress *float64 `json:"progress,omitempty"`
Summary []*provisioningv0alpha1.JobResourceSummary `json:"summary,omitempty"`
URLs *RepositoryURLsApplyConfiguration `json:"url,omitempty"`
@@ -70,16 +69,6 @@ func (b *JobStatusApplyConfiguration) WithErrors(values ...string) *JobStatusApp
return b
}
// WithWarnings adds the given value to the Warnings field in the declarative configuration
// and returns the receiver, so that objects can be build by chaining "With" function invocations.
// If called multiple times, values provided by each call will be appended to the Warnings field.
func (b *JobStatusApplyConfiguration) WithWarnings(values ...string) *JobStatusApplyConfiguration {
for i := range values {
b.Warnings = append(b.Warnings, values[i])
}
return b
}
// WithProgress sets the Progress field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the Progress field is set to the value of the last call.

View File

@@ -18,28 +18,14 @@ import (
func ForKind(kind schema.GroupVersionKind) interface{} {
switch kind {
// Group=provisioning.grafana.app, Version=v0alpha1
case v0alpha1.SchemeGroupVersion.WithKind("BitbucketConnectionConfig"):
return &provisioningv0alpha1.BitbucketConnectionConfigApplyConfiguration{}
case v0alpha1.SchemeGroupVersion.WithKind("BitbucketRepositoryConfig"):
return &provisioningv0alpha1.BitbucketRepositoryConfigApplyConfiguration{}
case v0alpha1.SchemeGroupVersion.WithKind("Connection"):
return &provisioningv0alpha1.ConnectionApplyConfiguration{}
case v0alpha1.SchemeGroupVersion.WithKind("ConnectionSecure"):
return &provisioningv0alpha1.ConnectionSecureApplyConfiguration{}
case v0alpha1.SchemeGroupVersion.WithKind("ConnectionSpec"):
return &provisioningv0alpha1.ConnectionSpecApplyConfiguration{}
case v0alpha1.SchemeGroupVersion.WithKind("ConnectionStatus"):
return &provisioningv0alpha1.ConnectionStatusApplyConfiguration{}
case v0alpha1.SchemeGroupVersion.WithKind("DeleteJobOptions"):
return &provisioningv0alpha1.DeleteJobOptionsApplyConfiguration{}
case v0alpha1.SchemeGroupVersion.WithKind("ExportJobOptions"):
return &provisioningv0alpha1.ExportJobOptionsApplyConfiguration{}
case v0alpha1.SchemeGroupVersion.WithKind("GitHubConnectionConfig"):
return &provisioningv0alpha1.GitHubConnectionConfigApplyConfiguration{}
case v0alpha1.SchemeGroupVersion.WithKind("GitHubRepositoryConfig"):
return &provisioningv0alpha1.GitHubRepositoryConfigApplyConfiguration{}
case v0alpha1.SchemeGroupVersion.WithKind("GitlabConnectionConfig"):
return &provisioningv0alpha1.GitlabConnectionConfigApplyConfiguration{}
case v0alpha1.SchemeGroupVersion.WithKind("GitLabRepositoryConfig"):
return &provisioningv0alpha1.GitLabRepositoryConfigApplyConfiguration{}
case v0alpha1.SchemeGroupVersion.WithKind("GitRepositoryConfig"):

View File

@@ -1,60 +0,0 @@
// SPDX-License-Identifier: AGPL-3.0-only
// Code generated by client-gen. DO NOT EDIT.
package v0alpha1
import (
context "context"
provisioningv0alpha1 "github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1"
applyconfigurationprovisioningv0alpha1 "github.com/grafana/grafana/apps/provisioning/pkg/generated/applyconfiguration/provisioning/v0alpha1"
scheme "github.com/grafana/grafana/apps/provisioning/pkg/generated/clientset/versioned/scheme"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
types "k8s.io/apimachinery/pkg/types"
watch "k8s.io/apimachinery/pkg/watch"
gentype "k8s.io/client-go/gentype"
)
// ConnectionsGetter has a method to return a ConnectionInterface.
// A group's client should implement this interface.
type ConnectionsGetter interface {
Connections(namespace string) ConnectionInterface
}
// ConnectionInterface has methods to work with Connection resources.
type ConnectionInterface interface {
Create(ctx context.Context, connection *provisioningv0alpha1.Connection, opts v1.CreateOptions) (*provisioningv0alpha1.Connection, error)
Update(ctx context.Context, connection *provisioningv0alpha1.Connection, opts v1.UpdateOptions) (*provisioningv0alpha1.Connection, error)
// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus().
UpdateStatus(ctx context.Context, connection *provisioningv0alpha1.Connection, opts v1.UpdateOptions) (*provisioningv0alpha1.Connection, error)
Delete(ctx context.Context, name string, opts v1.DeleteOptions) error
DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error
Get(ctx context.Context, name string, opts v1.GetOptions) (*provisioningv0alpha1.Connection, error)
List(ctx context.Context, opts v1.ListOptions) (*provisioningv0alpha1.ConnectionList, error)
Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error)
Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *provisioningv0alpha1.Connection, err error)
Apply(ctx context.Context, connection *applyconfigurationprovisioningv0alpha1.ConnectionApplyConfiguration, opts v1.ApplyOptions) (result *provisioningv0alpha1.Connection, err error)
// Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus().
ApplyStatus(ctx context.Context, connection *applyconfigurationprovisioningv0alpha1.ConnectionApplyConfiguration, opts v1.ApplyOptions) (result *provisioningv0alpha1.Connection, err error)
ConnectionExpansion
}
// connections implements ConnectionInterface
type connections struct {
*gentype.ClientWithListAndApply[*provisioningv0alpha1.Connection, *provisioningv0alpha1.ConnectionList, *applyconfigurationprovisioningv0alpha1.ConnectionApplyConfiguration]
}
// newConnections returns a Connections
func newConnections(c *ProvisioningV0alpha1Client, namespace string) *connections {
return &connections{
gentype.NewClientWithListAndApply[*provisioningv0alpha1.Connection, *provisioningv0alpha1.ConnectionList, *applyconfigurationprovisioningv0alpha1.ConnectionApplyConfiguration](
"connections",
c.RESTClient(),
scheme.ParameterCodec,
namespace,
func() *provisioningv0alpha1.Connection { return &provisioningv0alpha1.Connection{} },
func() *provisioningv0alpha1.ConnectionList { return &provisioningv0alpha1.ConnectionList{} },
),
}
}

View File

@@ -1,37 +0,0 @@
// SPDX-License-Identifier: AGPL-3.0-only
// Code generated by client-gen. DO NOT EDIT.
package fake
import (
v0alpha1 "github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1"
provisioningv0alpha1 "github.com/grafana/grafana/apps/provisioning/pkg/generated/applyconfiguration/provisioning/v0alpha1"
typedprovisioningv0alpha1 "github.com/grafana/grafana/apps/provisioning/pkg/generated/clientset/versioned/typed/provisioning/v0alpha1"
gentype "k8s.io/client-go/gentype"
)
// fakeConnections implements ConnectionInterface
type fakeConnections struct {
*gentype.FakeClientWithListAndApply[*v0alpha1.Connection, *v0alpha1.ConnectionList, *provisioningv0alpha1.ConnectionApplyConfiguration]
Fake *FakeProvisioningV0alpha1
}
func newFakeConnections(fake *FakeProvisioningV0alpha1, namespace string) typedprovisioningv0alpha1.ConnectionInterface {
return &fakeConnections{
gentype.NewFakeClientWithListAndApply[*v0alpha1.Connection, *v0alpha1.ConnectionList, *provisioningv0alpha1.ConnectionApplyConfiguration](
fake.Fake,
namespace,
v0alpha1.SchemeGroupVersion.WithResource("connections"),
v0alpha1.SchemeGroupVersion.WithKind("Connection"),
func() *v0alpha1.Connection { return &v0alpha1.Connection{} },
func() *v0alpha1.ConnectionList { return &v0alpha1.ConnectionList{} },
func(dst, src *v0alpha1.ConnectionList) { dst.ListMeta = src.ListMeta },
func(list *v0alpha1.ConnectionList) []*v0alpha1.Connection { return gentype.ToPointerSlice(list.Items) },
func(list *v0alpha1.ConnectionList, items []*v0alpha1.Connection) {
list.Items = gentype.FromPointerSlice(items)
},
),
fake,
}
}

View File

@@ -14,10 +14,6 @@ type FakeProvisioningV0alpha1 struct {
*testing.Fake
}
func (c *FakeProvisioningV0alpha1) Connections(namespace string) v0alpha1.ConnectionInterface {
return newFakeConnections(c, namespace)
}
func (c *FakeProvisioningV0alpha1) HistoricJobs(namespace string) v0alpha1.HistoricJobInterface {
return newFakeHistoricJobs(c, namespace)
}

View File

@@ -4,8 +4,6 @@
package v0alpha1
type ConnectionExpansion interface{}
type HistoricJobExpansion interface{}
type JobExpansion interface{}

View File

@@ -14,7 +14,6 @@ import (
type ProvisioningV0alpha1Interface interface {
RESTClient() rest.Interface
ConnectionsGetter
HistoricJobsGetter
JobsGetter
RepositoriesGetter
@@ -25,10 +24,6 @@ type ProvisioningV0alpha1Client struct {
restClient rest.Interface
}
func (c *ProvisioningV0alpha1Client) Connections(namespace string) ConnectionInterface {
return newConnections(c, namespace)
}
func (c *ProvisioningV0alpha1Client) HistoricJobs(namespace string) HistoricJobInterface {
return newHistoricJobs(c, namespace)
}

View File

@@ -39,8 +39,6 @@ func (f *genericInformer) Lister() cache.GenericLister {
func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource) (GenericInformer, error) {
switch resource {
// Group=provisioning.grafana.app, Version=v0alpha1
case v0alpha1.SchemeGroupVersion.WithResource("connections"):
return &genericInformer{resource: resource.GroupResource(), informer: f.Provisioning().V0alpha1().Connections().Informer()}, nil
case v0alpha1.SchemeGroupVersion.WithResource("historicjobs"):
return &genericInformer{resource: resource.GroupResource(), informer: f.Provisioning().V0alpha1().HistoricJobs().Informer()}, nil
case v0alpha1.SchemeGroupVersion.WithResource("jobs"):

View File

@@ -1,88 +0,0 @@
// SPDX-License-Identifier: AGPL-3.0-only
// Code generated by informer-gen. DO NOT EDIT.
package v0alpha1
import (
context "context"
time "time"
apisprovisioningv0alpha1 "github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1"
versioned "github.com/grafana/grafana/apps/provisioning/pkg/generated/clientset/versioned"
internalinterfaces "github.com/grafana/grafana/apps/provisioning/pkg/generated/informers/externalversions/internalinterfaces"
provisioningv0alpha1 "github.com/grafana/grafana/apps/provisioning/pkg/generated/listers/provisioning/v0alpha1"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
runtime "k8s.io/apimachinery/pkg/runtime"
watch "k8s.io/apimachinery/pkg/watch"
cache "k8s.io/client-go/tools/cache"
)
// ConnectionInformer provides access to a shared informer and lister for
// Connections.
type ConnectionInformer interface {
Informer() cache.SharedIndexInformer
Lister() provisioningv0alpha1.ConnectionLister
}
type connectionInformer struct {
factory internalinterfaces.SharedInformerFactory
tweakListOptions internalinterfaces.TweakListOptionsFunc
namespace string
}
// NewConnectionInformer constructs a new informer for Connection type.
// Always prefer using an informer factory to get a shared informer instead of getting an independent
// one. This reduces memory footprint and number of connections to the server.
func NewConnectionInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer {
return NewFilteredConnectionInformer(client, namespace, resyncPeriod, indexers, nil)
}
// NewFilteredConnectionInformer constructs a new informer for Connection type.
// Always prefer using an informer factory to get a shared informer instead of getting an independent
// one. This reduces memory footprint and number of connections to the server.
func NewFilteredConnectionInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer {
return cache.NewSharedIndexInformer(
&cache.ListWatch{
ListFunc: func(options v1.ListOptions) (runtime.Object, error) {
if tweakListOptions != nil {
tweakListOptions(&options)
}
return client.ProvisioningV0alpha1().Connections(namespace).List(context.Background(), options)
},
WatchFunc: func(options v1.ListOptions) (watch.Interface, error) {
if tweakListOptions != nil {
tweakListOptions(&options)
}
return client.ProvisioningV0alpha1().Connections(namespace).Watch(context.Background(), options)
},
ListWithContextFunc: func(ctx context.Context, options v1.ListOptions) (runtime.Object, error) {
if tweakListOptions != nil {
tweakListOptions(&options)
}
return client.ProvisioningV0alpha1().Connections(namespace).List(ctx, options)
},
WatchFuncWithContext: func(ctx context.Context, options v1.ListOptions) (watch.Interface, error) {
if tweakListOptions != nil {
tweakListOptions(&options)
}
return client.ProvisioningV0alpha1().Connections(namespace).Watch(ctx, options)
},
},
&apisprovisioningv0alpha1.Connection{},
resyncPeriod,
indexers,
)
}
func (f *connectionInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer {
return NewFilteredConnectionInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions)
}
func (f *connectionInformer) Informer() cache.SharedIndexInformer {
return f.factory.InformerFor(&apisprovisioningv0alpha1.Connection{}, f.defaultInformer)
}
func (f *connectionInformer) Lister() provisioningv0alpha1.ConnectionLister {
return provisioningv0alpha1.NewConnectionLister(f.Informer().GetIndexer())
}

View File

@@ -10,8 +10,6 @@ import (
// Interface provides access to all the informers in this group version.
type Interface interface {
// Connections returns a ConnectionInformer.
Connections() ConnectionInformer
// HistoricJobs returns a HistoricJobInformer.
HistoricJobs() HistoricJobInformer
// Jobs returns a JobInformer.
@@ -31,11 +29,6 @@ func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakList
return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions}
}
// Connections returns a ConnectionInformer.
func (v *version) Connections() ConnectionInformer {
return &connectionInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions}
}
// HistoricJobs returns a HistoricJobInformer.
func (v *version) HistoricJobs() HistoricJobInformer {
return &historicJobInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions}

View File

@@ -1,56 +0,0 @@
// SPDX-License-Identifier: AGPL-3.0-only
// Code generated by lister-gen. DO NOT EDIT.
package v0alpha1
import (
provisioningv0alpha1 "github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1"
labels "k8s.io/apimachinery/pkg/labels"
listers "k8s.io/client-go/listers"
cache "k8s.io/client-go/tools/cache"
)
// ConnectionLister helps list Connections.
// All objects returned here must be treated as read-only.
type ConnectionLister interface {
// List lists all Connections in the indexer.
// Objects returned here must be treated as read-only.
List(selector labels.Selector) (ret []*provisioningv0alpha1.Connection, err error)
// Connections returns an object that can list and get Connections.
Connections(namespace string) ConnectionNamespaceLister
ConnectionListerExpansion
}
// connectionLister implements the ConnectionLister interface.
type connectionLister struct {
listers.ResourceIndexer[*provisioningv0alpha1.Connection]
}
// NewConnectionLister returns a new ConnectionLister.
func NewConnectionLister(indexer cache.Indexer) ConnectionLister {
return &connectionLister{listers.New[*provisioningv0alpha1.Connection](indexer, provisioningv0alpha1.Resource("connection"))}
}
// Connections returns an object that can list and get Connections.
func (s *connectionLister) Connections(namespace string) ConnectionNamespaceLister {
return connectionNamespaceLister{listers.NewNamespaced[*provisioningv0alpha1.Connection](s.ResourceIndexer, namespace)}
}
// ConnectionNamespaceLister helps list and get Connections.
// All objects returned here must be treated as read-only.
type ConnectionNamespaceLister interface {
// List lists all Connections in the indexer for a given namespace.
// Objects returned here must be treated as read-only.
List(selector labels.Selector) (ret []*provisioningv0alpha1.Connection, err error)
// Get retrieves the Connection from the indexer for a given namespace and name.
// Objects returned here must be treated as read-only.
Get(name string) (*provisioningv0alpha1.Connection, error)
ConnectionNamespaceListerExpansion
}
// connectionNamespaceLister implements the ConnectionNamespaceLister
// interface.
type connectionNamespaceLister struct {
listers.ResourceIndexer[*provisioningv0alpha1.Connection]
}

View File

@@ -4,14 +4,6 @@
package v0alpha1
// ConnectionListerExpansion allows custom methods to be added to
// ConnectionLister.
type ConnectionListerExpansion interface{}
// ConnectionNamespaceListerExpansion allows custom methods to be added to
// ConnectionNamespaceLister.
type ConnectionNamespaceListerExpansion interface{}
// HistoricJobListerExpansion allows custom methods to be added to
// HistoricJobLister.
type HistoricJobListerExpansion interface{}

View File

@@ -211,12 +211,6 @@ type ScopeNavigationSpec struct {
Scope string `json:"scope"`
// Used to navigate to a sub-scope of the main scope. URL will not be used if this is set.
SubScope string `json:"subScope,omitempty"`
// Preload the subscope children, as soon as the ScopeNavigation is loaded.
PreLoadSubScopeChildren bool `json:"preLoadSubScopeChildren,omitempty"`
// Expands to display the subscope children when the ScopeNavigation is loaded.
ExpandOnLoad bool `json:"expandOnLoad,omitempty"`
// Makes the subscope not selectable, only serving as a way to build the tree.
DisableSubScopeSelection bool `json:"disableSubScopeSelection,omitempty"`
}
// Type of the item.

View File

@@ -642,27 +642,6 @@ func schema_pkg_apis_scope_v0alpha1_ScopeNavigationSpec(ref common.ReferenceCall
Format: "",
},
},
"preLoadSubScopeChildren": {
SchemaProps: spec.SchemaProps{
Description: "Preload the subscope children, as soon as the ScopeNavigation is loaded.",
Type: []string{"boolean"},
Format: "",
},
},
"expandOnLoad": {
SchemaProps: spec.SchemaProps{
Description: "Expands to display the subscope children when the ScopeNavigation is loaded.",
Type: []string{"boolean"},
Format: "",
},
},
"disableSubScopeSelection": {
SchemaProps: spec.SchemaProps{
Description: "Makes the subscope not selectable, only serving as a way to build the tree.",
Type: []string{"boolean"},
Format: "",
},
},
},
Required: []string{"url", "scope"},
},

View File

@@ -1327,10 +1327,6 @@ alertmanager_max_silences_count =
# Maximum silence size in bytes. Default: 0 (no limit).
alertmanager_max_silence_size_bytes =
# Maximum size of the expanded template output in bytes. Default: 10485760 (0 - no limit).
# The result of template expansion will be truncated to the limit.
alertmanager_max_template_output_bytes =
# Redis server address or addresses. It can be a single Redis address if using Redis standalone,
# or a list of comma-separated addresses if using Redis Cluster/Sentinel.
ha_redis_address =

View File

@@ -75,9 +75,9 @@
"effects": {
"barGlow": false,
"centerGlow": false,
"gradient": false,
"rounded": true,
"spotlight": false
"spotlight": false,
"gradient": false
},
"orientation": "auto",
"reduceOptions": {
@@ -152,9 +152,9 @@
"effects": {
"barGlow": false,
"centerGlow": true,
"gradient": false,
"rounded": true,
"spotlight": false
"spotlight": false,
"gradient": false
},
"orientation": "auto",
"reduceOptions": {
@@ -229,9 +229,9 @@
"effects": {
"barGlow": true,
"centerGlow": true,
"gradient": false,
"rounded": true,
"spotlight": false
"spotlight": false,
"gradient": false
},
"orientation": "auto",
"reduceOptions": {
@@ -306,9 +306,9 @@
"effects": {
"barGlow": true,
"centerGlow": true,
"gradient": false,
"rounded": true,
"spotlight": true
"spotlight": true,
"gradient": false
},
"orientation": "auto",
"reduceOptions": {
@@ -383,9 +383,9 @@
"effects": {
"barGlow": true,
"centerGlow": true,
"gradient": false,
"rounded": true,
"spotlight": true
"spotlight": true,
"gradient": false
},
"orientation": "auto",
"reduceOptions": {
@@ -460,9 +460,9 @@
"effects": {
"barGlow": true,
"centerGlow": true,
"gradient": false,
"rounded": false,
"spotlight": true
"spotlight": true,
"gradient": false
},
"orientation": "auto",
"reduceOptions": {
@@ -537,9 +537,9 @@
"effects": {
"barGlow": true,
"centerGlow": true,
"gradient": false,
"rounded": false,
"spotlight": true
"spotlight": true,
"gradient": false
},
"orientation": "auto",
"reduceOptions": {
@@ -627,9 +627,9 @@
"effects": {
"barGlow": true,
"centerGlow": true,
"gradient": false,
"rounded": true,
"spotlight": true
"spotlight": true,
"gradient": false
},
"orientation": "auto",
"reduceOptions": {
@@ -704,9 +704,9 @@
"effects": {
"barGlow": true,
"centerGlow": true,
"gradient": false,
"rounded": true,
"spotlight": true
"spotlight": true,
"gradient": false
},
"orientation": "auto",
"reduceOptions": {
@@ -781,9 +781,9 @@
"effects": {
"barGlow": true,
"centerGlow": true,
"gradient": false,
"rounded": true,
"spotlight": true
"spotlight": true,
"gradient": false
},
"orientation": "auto",
"reduceOptions": {
@@ -858,9 +858,9 @@
"effects": {
"barGlow": true,
"centerGlow": true,
"gradient": false,
"rounded": true,
"spotlight": true
"spotlight": true,
"gradient": false
},
"orientation": "auto",
"reduceOptions": {
@@ -952,9 +952,9 @@
"effects": {
"barGlow": false,
"centerGlow": false,
"gradient": false,
"rounded": false,
"spotlight": false
"spotlight": false,
"gradient": false
},
"orientation": "auto",
"reduceOptions": {
@@ -1029,9 +1029,9 @@
"effects": {
"barGlow": false,
"centerGlow": false,
"gradient": false,
"rounded": false,
"spotlight": false
"spotlight": false,
"gradient": false
},
"orientation": "auto",
"reduceOptions": {
@@ -1106,9 +1106,9 @@
"effects": {
"barGlow": false,
"centerGlow": false,
"gradient": true,
"rounded": false,
"spotlight": false
"spotlight": false,
"gradient": true
},
"orientation": "auto",
"reduceOptions": {
@@ -1183,9 +1183,9 @@
"effects": {
"barGlow": false,
"centerGlow": false,
"gradient": false,
"rounded": false,
"spotlight": false
"spotlight": false,
"gradient": false
},
"orientation": "auto",
"reduceOptions": {
@@ -1260,9 +1260,9 @@
"effects": {
"barGlow": false,
"centerGlow": false,
"gradient": false,
"rounded": false,
"spotlight": false
"spotlight": false,
"gradient": false
},
"orientation": "auto",
"reduceOptions": {
@@ -1354,9 +1354,9 @@
"effects": {
"barGlow": false,
"centerGlow": false,
"gradient": true,
"rounded": false,
"spotlight": false
"spotlight": false,
"gradient": true
},
"orientation": "auto",
"reduceOptions": {
@@ -1435,9 +1435,9 @@
"effects": {
"barGlow": false,
"centerGlow": false,
"gradient": true,
"rounded": false,
"spotlight": false
"spotlight": false,
"gradient": true
},
"orientation": "auto",
"reduceOptions": {
@@ -1516,9 +1516,9 @@
"effects": {
"barGlow": false,
"centerGlow": false,
"gradient": true,
"rounded": false,
"spotlight": false
"spotlight": false,
"gradient": true
},
"orientation": "auto",
"reduceOptions": {
@@ -1565,6 +1565,7 @@
"datasource": {
"type": "grafana-testdata-datasource"
},
"description": "",
"fieldConfig": {
"defaults": {
"color": {
@@ -1605,9 +1606,9 @@
"effects": {
"barGlow": true,
"centerGlow": true,
"gradient": true,
"rounded": true,
"spotlight": true
"spotlight": true,
"gradient": true
},
"glow": "both",
"orientation": "auto",
@@ -1630,6 +1631,7 @@
"datasource": {
"type": "grafana-testdata-datasource"
},
"hide": false,
"max": 98,
"min": 5,
"noise": 22,
@@ -1647,6 +1649,7 @@
"datasource": {
"type": "grafana-testdata-datasource"
},
"description": "",
"fieldConfig": {
"defaults": {
"color": {
@@ -1687,9 +1690,9 @@
"effects": {
"barGlow": true,
"centerGlow": true,
"gradient": true,
"rounded": true,
"spotlight": true
"spotlight": true,
"gradient": true
},
"glow": "both",
"orientation": "auto",
@@ -1712,6 +1715,7 @@
"datasource": {
"type": "grafana-testdata-datasource"
},
"hide": false,
"max": 98,
"min": 5,
"noise": 22,
@@ -1742,6 +1746,7 @@
"datasource": {
"type": "grafana-testdata-datasource"
},
"description": "",
"fieldConfig": {
"defaults": {
"color": {
@@ -1783,9 +1788,9 @@
"effects": {
"barGlow": true,
"centerGlow": true,
"gradient": true,
"rounded": true,
"spotlight": true
"spotlight": true,
"gradient": true
},
"glow": "both",
"orientation": "auto",
@@ -1808,6 +1813,7 @@
"datasource": {
"type": "grafana-testdata-datasource"
},
"hide": false,
"max": 8,
"min": 1,
"noise": 2,
@@ -1825,6 +1831,7 @@
"datasource": {
"type": "grafana-testdata-datasource"
},
"description": "",
"fieldConfig": {
"defaults": {
"color": {
@@ -1866,9 +1873,9 @@
"effects": {
"barGlow": true,
"centerGlow": true,
"gradient": true,
"rounded": true,
"spotlight": true
"spotlight": true,
"gradient": true
},
"glow": "both",
"orientation": "auto",
@@ -1891,6 +1898,7 @@
"datasource": {
"type": "grafana-testdata-datasource"
},
"hide": false,
"max": 12,
"min": 1,
"noise": 2,
@@ -1908,6 +1916,7 @@
"datasource": {
"type": "grafana-testdata-datasource"
},
"description": "",
"fieldConfig": {
"defaults": {
"color": {
@@ -1948,9 +1957,9 @@
"effects": {
"barGlow": true,
"centerGlow": true,
"gradient": true,
"rounded": true,
"spotlight": true
"spotlight": true,
"gradient": true
},
"glow": "both",
"orientation": "auto",
@@ -1973,6 +1982,7 @@
"datasource": {
"type": "grafana-testdata-datasource"
},
"hide": false,
"max": 100,
"min": 10,
"noise": 22,
@@ -1990,6 +2000,7 @@
"datasource": {
"type": "grafana-testdata-datasource"
},
"description": "",
"fieldConfig": {
"defaults": {
"color": {
@@ -2030,9 +2041,9 @@
"effects": {
"barGlow": true,
"centerGlow": true,
"gradient": true,
"rounded": true,
"spotlight": true
"spotlight": true,
"gradient": true
},
"glow": "both",
"orientation": "auto",
@@ -2055,6 +2066,7 @@
"datasource": {
"type": "grafana-testdata-datasource"
},
"hide": false,
"max": 100,
"min": 10,
"noise": 22,
@@ -2067,147 +2079,6 @@
],
"title": "Backend",
"type": "radialbar"
},
{
"collapsed": false,
"gridPos": {
"h": 1,
"w": 24,
"x": 0,
"y": 66
},
"id": 35,
"panels": [],
"title": "Empty data",
"type": "row"
},
{
"datasource": {
"type": "grafana-testdata-datasource"
},
"fieldConfig": {
"defaults": {
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": 0
},
{
"color": "red",
"value": 80
}
]
}
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 6,
"x": 0,
"y": 67
},
"id": 36,
"options": {
"barWidthFactor": 0.5,
"effects": {
"barGlow": false,
"centerGlow": false,
"gradient": true,
"rounded": false,
"spotlight": false
},
"orientation": "auto",
"reduceOptions": {
"calcs": ["lastNotNull"],
"fields": "",
"values": false
},
"segmentCount": 1,
"segmentSpacing": 0.3,
"shape": "gauge",
"showThresholdLabels": false,
"showThresholdMarkers": true,
"sparkline": true
},
"pluginVersion": "13.0.0-pre",
"targets": [
{
"refId": "A",
"scenarioId": "random_walk",
"seriesCount": 0
}
],
"title": "Numeric, no series",
"type": "gauge"
},
{
"datasource": {
"type": "grafana-testdata-datasource"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "thresholds"
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": 0
},
{
"color": "red",
"value": 80
}
]
}
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 6,
"x": 6,
"y": 67
},
"id": 37,
"options": {
"barWidthFactor": 0.5,
"effects": {
"barGlow": false,
"centerGlow": false,
"gradient": true,
"rounded": false,
"spotlight": false
},
"orientation": "auto",
"reduceOptions": {
"calcs": ["lastNotNull"],
"fields": "",
"values": false
},
"segmentCount": 1,
"segmentSpacing": 0.3,
"shape": "gauge",
"showThresholdLabels": false,
"showThresholdMarkers": true,
"sparkline": true
},
"pluginVersion": "13.0.0-pre",
"targets": [
{
"refId": "A",
"scenarioId": "logs"
}
],
"title": "Non-numeric",
"type": "gauge"
}
],
"preload": false,
@@ -2224,5 +2095,5 @@
"timezone": "browser",
"title": "Panel tests - Gauge (new)",
"uid": "panel-tests-gauge-new",
"version": 9
"version": 6
}

View File

@@ -83,12 +83,6 @@ tree:
nodeType: leaf
linkId: test-case-2
linkType: scope
test-case-redirect:
title: Test case with redirect
nodeType: leaf
linkId: shoe-org
linkType: scope
redirectPath: /d/dcb9f5e9-8066-4397-889e-864b99555dbb #Reliability dashboard
clusters:
title: Clusters
nodeType: container
@@ -125,7 +119,6 @@ navigationTree:
url: /d/_5rDmaQiz
scope: shoe-org
subScope: shoes
preLoadSubScopeChildren: true
children:
- name: shoes-overview
title: Overview
@@ -142,7 +135,6 @@ navigationTree:
url: /d/edediimbjhdz4b
scope: shoes
subScope: frontend
preLoadSubScopeChildren: true
children:
- name: frontend-api
title: API Metrics
@@ -212,7 +204,6 @@ navigationTree:
url: /d/UTv--wqMk
scope: shoe-org
subScope: apparel
disableSubScopeSelection: true
children:
- name: apparel-product-overview
title: Product Overview

View File

@@ -67,36 +67,30 @@ type ScopeFilterConfig struct {
type TreeNode struct {
Title string `yaml:"title"`
SubTitle string `yaml:"subTitle,omitempty"`
Description string `yaml:"description,omitempty"`
NodeType string `yaml:"nodeType"`
LinkID string `yaml:"linkId,omitempty"`
LinkType string `yaml:"linkType,omitempty"`
DisableMultiSelect bool `yaml:"disableMultiSelect,omitempty"`
RedirectPath string `yaml:"redirectPath,omitempty"`
Children map[string]TreeNode `yaml:"children,omitempty"`
}
type NavigationConfig struct {
URL string `yaml:"url"` // URL path (e.g., /d/abc123 or /explore)
Scope string `yaml:"scope"` // Required scope
SubScope string `yaml:"subScope"` // Optional subScope for hierarchical navigation
Title string `yaml:"title"` // Display title
Groups []string `yaml:"groups"` // Optional groups for categorization
DisableSubScopeSelection bool `yaml:"disableSubScopeSelection"` // Makes the subscope not selectable
PreLoadSubScopeChildren bool `yaml:"preLoadSubScopeChildren"` // Preload children of subScope without updating UI
URL string `yaml:"url"` // URL path (e.g., /d/abc123 or /explore)
Scope string `yaml:"scope"` // Required scope
SubScope string `yaml:"subScope"` // Optional subScope for hierarchical navigation
Title string `yaml:"title"` // Display title
Groups []string `yaml:"groups"` // Optional groups for categorization
}
// NavigationTreeNode represents a node in the navigation tree structure
type NavigationTreeNode struct {
Name string `yaml:"name"`
Title string `yaml:"title"`
URL string `yaml:"url"`
Scope string `yaml:"scope"`
SubScope string `yaml:"subScope,omitempty"`
Groups []string `yaml:"groups,omitempty"`
DisableSubScopeSelection bool `yaml:"disableSubScopeSelection,omitempty"`
PreLoadSubScopeChildren bool `yaml:"preLoadSubScopeChildren,omitempty"` // Preload children of subScope without updating UI
Children []NavigationTreeNode `yaml:"children,omitempty"`
Name string `yaml:"name"`
Title string `yaml:"title"`
URL string `yaml:"url"`
Scope string `yaml:"scope"`
SubScope string `yaml:"subScope,omitempty"`
Groups []string `yaml:"groups,omitempty"`
Children []NavigationTreeNode `yaml:"children,omitempty"`
}
// Helper function to convert ScopeFilterConfig to v0alpha1.ScopeFilter
@@ -265,7 +259,6 @@ func (c *Client) createScopeNode(name string, node TreeNode, parentName string)
spec := v0alpha1.ScopeNodeSpec{
Title: node.Title,
SubTitle: node.SubTitle,
Description: node.Description,
NodeType: nodeType,
DisableMultiSelect: node.DisableMultiSelect,
}
@@ -279,10 +272,6 @@ func (c *Client) createScopeNode(name string, node TreeNode, parentName string)
spec.LinkType = linkType
}
if node.RedirectPath != "" {
spec.RedirectPath = node.RedirectPath
}
resource := v0alpha1.ScopeNode{
TypeMeta: metav1.TypeMeta{
APIVersion: apiVersion,
@@ -317,10 +306,8 @@ func (c *Client) createScopeNavigation(name string, nav NavigationConfig) error
prefixedScope := prefix + "-" + nav.Scope
spec := v0alpha1.ScopeNavigationSpec{
URL: nav.URL,
Scope: prefixedScope,
DisableSubScopeSelection: nav.DisableSubScopeSelection,
PreLoadSubScopeChildren: nav.PreLoadSubScopeChildren,
URL: nav.URL,
Scope: prefixedScope,
}
if nav.SubScope != "" {
@@ -356,14 +343,14 @@ func (c *Client) createScopeNavigation(name string, nav NavigationConfig) error
return err
}
// Get the created resource to retrieve its resourceVersion for status update
createdNav, err := c.getScopeNavigation(prefixedName)
if err != nil {
return fmt.Errorf("failed to get created navigation: %w", err)
}
// Update status in a second request (status is a subresource)
if nav.Title != "" || len(nav.Groups) > 0 {
// Get the created resource to retrieve its resourceVersion and existing spec
createdNav, err := c.getScopeNavigation(prefixedName)
if err != nil {
return fmt.Errorf("failed to get created navigation: %w", err)
}
statusResource := v0alpha1.ScopeNavigation{
TypeMeta: metav1.TypeMeta{
APIVersion: apiVersion,
@@ -410,11 +397,9 @@ func treeToNavigations(node NavigationTreeNode, parentPath []string, dashboardCo
// Create navigation for this node
nav := NavigationConfig{
URL: url,
Scope: node.Scope,
Title: node.Title,
DisableSubScopeSelection: node.DisableSubScopeSelection,
PreLoadSubScopeChildren: node.PreLoadSubScopeChildren,
URL: url,
Scope: node.Scope,
Title: node.Title,
}
if node.SubScope != "" {
nav.SubScope = node.SubScope

View File

@@ -7,8 +7,8 @@ MAKEFLAGS += --no-builtin-rule
include docs.mk
.PHONY: sources/visualizations/panels-visualizations/query-transform-data/transform-data/index.md
sources/visualizations/panels-visualizations/query-transform-data/transform-data/index.md: ## Generate the Transform Data page source.
.PHONY: sources/panels-visualizations/query-transform-data/transform-data/index.md
sources/panels-visualizations/query-transform-data/transform-data/index.md: ## Generate the Transform Data page source.
cd $(CURDIR)/.. && \
npx tsx ./scripts/docs/generate-transformations.ts && \
npx prettier -w $(CURDIR)/$@

View File

@@ -21,28 +21,11 @@ weight: 120
# Install a plugin
{{< admonition type="note" >}}
Installing plugins from the Grafana website into a Grafana Cloud instance will be removed in February 2026.
If you're a Grafana Cloud user, follow [Install a plugin through the Grafana UI](#install-a-plugin-through-the-grafana-uiinstall-a-plugin-through-the-grafana-ui) instead.
{{< /admonition >}}
## Install a plugin through the Grafana UI
The most common way to install a plugin is through the Grafana UI.
1. In Grafana, click **Administration > Plugins and data > Plugins** in the side navigation menu to view all plugins.
1. Browse and find a plugin.
1. Click the plugin's logo.
1. Click **Install**.
You can use use the following alternative methods to install a plugin depending on your environment or setup.
Besides the UI, you can use alternative methods to install a plugin depending on your environment or set-up.
## Install a plugin using Grafana CLI
The Grafana CLI allows you to install, upgrade, and manage your Grafana plugins using a command line tool. For more information about Grafana CLI plugin commands, refer to [Plugin commands](https://grafana.com/docs/grafana/<GRAFANA_VERSION>/administration/cli/#plugins-commands).
The Grafana CLI allows you to install, upgrade, and manage your Grafana plugins using a command line tool. For more information about Grafana CLI plugin commands, refer to [Plugin commands](/docs/grafana/<GRAFANA_VERSION>/cli/#plugins-commands).
## Install a plugin from a ZIP file

View File

@@ -44,7 +44,7 @@ refs:
destination: /docs/grafana-cloud/alerting-and-irm/oncall/user-and-team-management/#available-grafana-oncall-rbac-roles--granted-actions
---
# Grafana RBAC role definitions
# RBAC role definitions
{{< admonition type="note" >}}
Available in [Grafana Enterprise](/docs/grafana/<GRAFANA_VERSION>/introduction/grafana-enterprise/) and [Grafana Cloud](/docs/grafana-cloud).
@@ -59,7 +59,7 @@ The following tables list permissions associated with basic and fixed roles. Thi
| Grafana Admin | `basic_grafana_admin` |
| `fixed:authentication.config:writer`<br>`fixed:general.auth.config:writer`<br>`fixed:ldap:writer`<br>`fixed:licensing:writer`<br>`fixed:migrationassistant:migrator`<br>`fixed:org.users:writer`<br>`fixed:organization:maintainer`<br>`fixed:plugins:maintainer`<br>`fixed:provisioning:writer`<br>`fixed:roles:writer`<br>`fixed:settings:reader`<br>`fixed:settings:writer`<br>`fixed:stats:reader`<br>`fixed:support.bundles:writer`<br>`fixed:usagestats:reader`<br>`fixed:users:writer` | Default [Grafana server administrator](/docs/grafana/<GRAFANA_VERSION>/administration/roles-and-permissions/#grafana-server-administrators) assignments. |
| Admin | `basic_admin` | All roles assigned to Editor and `fixed:reports:writer` <br>`fixed:datasources:writer`<br>`fixed:organization:writer`<br>`fixed:datasources.permissions:writer`<br>`fixed:teams:writer`<br>`fixed:dashboards:writer`<br>`fixed:dashboards.permissions:writer`<br>`fixed:dashboards.public:writer`<br>`fixed:folders:writer`<br>`fixed:folders.permissions:writer`<br>`fixed:alerting:writer`<br>`fixed:alerting.provisioning.secrets:reader`<br>`fixed:alerting.provisioning:writer`<br>`fixed:datasources.caching:writer`<br>`fixed:plugins:writer`<br>`fixed:library.panels:writer` | Default [Grafana organization administrator](ref:rbac-basic-roles) assignments. |
| Editor | `basic_editor` | All roles assigned to Viewer and `fixed:datasources:explorer` <br>`fixed:dashboards:creator`<br>`fixed:folders:creator`<br>`fixed:annotations:writer`<br>`fixed:alerting:writer`<br>`fixed:library.panels:creator`<br>`fixed:library.panels:general.writer`<br>`fixed:alerting.provisioning.provenance:writer` | Default [Editor](ref:rbac-basic-roles) assignments. |
| Editor | `basic_editor` | All roles assigned to Viewer and `fixed:datasources:explorer` <br>`fixed:dashboards:creator`<br>`fixed:folders:creator`<br>`fixed:annotations:writer`<br>`fixed:alerting:writer`<br>`fixed:library.panels:creator`<br>`fixed:library.panels:general.writer`<br>`fixed:alerting.provisioning.status:writer` | Default [Editor](ref:rbac-basic-roles) assignments. |
| Viewer | `basic_viewer` | `fixed:datasources.id:reader`<br>`fixed:organization:reader`<br>`fixed:annotations:reader`<br>`fixed:annotations.dashboard:writer`<br>`fixed:alerting:reader`<br>`fixed:plugins.app:reader`<br>`fixed:dashboards.insights:reader`<br>`fixed:datasources.insights:reader`<br>`fixed:library.panels:general.reader`<br>`fixed:folders.general:reader`<br>`fixed:datasources.builtin:reader` | Default [Viewer](ref:rbac-basic-roles) assignments. |
| No Basic Role | n/a | | Default [No Basic Role](ref:rbac-basic-roles) |
@@ -74,86 +74,86 @@ These UUIDs won't be available if your instance was created before Grafana v10.2
To learn how to use the roles API to determine the role UUIDs, refer to [Manage RBAC roles](ref:rbac-manage-rbac-roles).
{{< /admonition >}}
| Fixed role | UUID | Permissions | Description |
| ----------------------------------------------- | ----------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `fixed:alerting:reader` | `fixed_O2oP1_uBFozI2i93klAkcvEWR30` | All permissions from `fixed:alerting.rules:reader` <br>`fixed:alerting.instances:reader`<br>`fixed:alerting.notifications:reader` | Read-only permissions for all Grafana, Mimir, Loki and Alertmanager alert rules\*, alerts, contact points, and notification policies.[\*](#alerting-roles) |
| `fixed:alerting:writer` | `fixed_-PAZgSJsDlRD8NUg-PFSeH_BkJY` | All permissions from `fixed:alerting.rules:writer` <br>`fixed:alerting.instances:writer`<br>`fixed:alerting.notifications:writer` | Create, update, and delete Grafana, Mimir, Loki and Alertmanager alert rules\*, silences, contact points, templates, mute timings, and notification policies.[\*](#alerting-roles) |
| `fixed:alerting.instances:reader` | `fixed_ut5fVS-Ulh_ejFoskFhJT_rYg0Y` | `alert.instances:read` for organization scope <br> `alert.instances.external:read` for scope `datasources:*` | Read all alerts and silences in the organization produced by Grafana Alerts and Mimir and Loki alerts and silences.[\*](#alerting-roles) |
| `fixed:alerting.instances:writer` | `fixed_pKOBJE346uyqMLdgWbk1NsQfEl0` | All permissions from `fixed:alerting.instances:reader` and<br> `alert.instances:create`<br>`alert.instances:write` for organization scope <br> `alert.instances.external:write` for scope `datasources:*` | Create, update and expire all silences in the organization produced by Grafana, Mimir, and Loki.[\*](#alerting-roles) |
| `fixed:alerting.notifications:reader` | `fixed_hmBn0lX5h1RZXB9Vaot420EEdA0` | `alert.notifications:read` for organization scope<br>`alert.notifications.external:read` for scope `datasources:*` | Read all Grafana and Alertmanager contact points, templates, and notification policies.[\*](#alerting-roles) |
| `fixed:alerting.notifications:writer` | `fixed_XplK6HPNxf9AP5IGTdB5Iun4tJc` | All permissions from `fixed:alerting.notifications:reader` and<br>`alert.notifications:write`for organization scope<br>`alert.notifications.external:read` for scope `datasources:*` | Create, update, and delete contact points, templates, mute timings and notification policies for Grafana and external Alertmanager.[\*](#alerting-roles) |
| `fixed:alerting.provisioning:writer` | `fixed_y7pFjdEkxpx5ETdcxPvp0AgRuUo` | `alert.provisioning:read` and `alert.provisioning:write` | Create, update and delete Grafana alert rules, notification policies, contact points, templates, etc via provisioning API. [\*](#alerting-roles) |
| `fixed:alerting.provisioning.secrets:reader` | `fixed_9fmzXXZZG-Od0Amy2ofEG8Uk--c` | `alert.provisioning:read` and `alert.provisioning.secrets:read` | Read-only permissions for Provisioning API and let export resources with decrypted secrets [\*](#alerting-roles) |
| `fixed:alerting.provisioning.provenance:writer` | `fixed_eAxlzfkTuobvKEgXHveFMBZrOj8` | `alert.provisioning.provenance:write` | Set provenance status to alert rules, notification policies, contact points, etc. Should be used together with regular writer roles. [\*](#alerting-roles) |
| `fixed:alerting.rules:reader` | `fixed_fRGKL_vAqUsmUWq5EYKnOha9DcA` | `alert.rule:read`, `alert.silences:read` for scope `folders:*` <br> `alert.rules.external:read` for scope `datasources:*` <br> `alert.notifications.time-intervals:read` <br> `alert.notifications.receivers:list` | Read all\* Grafana, Mimir, and Loki alert rules.[\*](#alerting-roles) and read rule-specific silences |
| `fixed:alerting.rules:writer` | `fixed_YJJGwAalUwDZPrXSyFH8GfYBXAc` | All permissions from `fixed:alerting.rules:reader` and <br> `alert.rule:create` <br> `alert.rule:write` <br> `alert.rule:delete` <br> `alert.silences:create` <br> `alert.silences:write` for scope `folders:*` <br> `alert.rules.external:write` for scope `datasources:*` | Create, update, and delete all\* Grafana, Mimir, and Loki alert rules.[\*](#alerting-roles) and manage rule-specific silences |
| `fixed:annotations:reader` | `fixed_hpZnoizrfAJsrceNcNQqWYV-xNU` | `annotations:read` for scopes `annotations:type:*` | Read all annotations and annotation tags. |
| `fixed:annotations:writer` | `fixed_ZVW-Aa9Tzle6J4s2aUFcq1StKWE` | All permissions from `fixed:annotations:reader` <br>`annotations:write` <br>`annotations.create`<br> `annotations:delete` for scope `annotations:type:*` | Read, create, update and delete all annotations and annotation tags. |
| `fixed:annotations.dashboard:writer` | `fixed_8A775xenXeKaJk4Cr7bchP9yXOA` | `annotations:write` <br>`annotations.create`<br> `annotations:delete` for scope `annotations:type:dashboard` | Create, update and delete dashboard annotations and annotation tags. |
| `fixed:authentication.config:writer` | `fixed_0rYhZ2Qnzs8AdB1nX7gexk3fHDw` | `settings:read` for scope `settings:auth.saml:*` <br> `settings:write` for scope `settings:auth.saml:*` | Read and update authentication and SAML settings. |
| `fixed:general.auth.config:writer` | `fixed_QFxIT_FGtBqbIVJIwx1bLgI5z6c` | `settings:read` for scope `settings:auth:oauth_allow_insecure_email_lookup` <br> `settings:write` for scope `settings:auth:oauth_allow_insecure_email_lookup` | Read and update the Grafana instance's general authentication configuration settings. |
| `fixed:dashboards:creator` | `fixed_ZorKUcEPCM01A1fPakEzGBUyU64` | `dashboards:create`<br>`folders:read` | Create dashboards. |
| `fixed:dashboards:reader` | `fixed_Sgr67JTOhjQGFlzYRahOe45TdWM` | `dashboards:read` | Read all dashboards. |
| `fixed:dashboards:writer` | `fixed_OK2YOQGIoI1G031hVzJB6rAJQAs` | All permissions from `fixed:dashboards:reader` and <br>`dashboards:write`<br>`dashboards:delete`<br>`dashboards:create`<br>`dashboards.permissions:read`<br>`dashboards.permissions:write` | Read, create, update, and delete all dashboards. |
| `fixed:dashboards.insights:reader` | `fixed_JlBJ2_gizP8zhgaeGE2rjyZe2Rs` | `dashboards.insights:read` | Read dashboard insights data and see presence indicators. |
| `fixed:dashboards.permissions:reader` | `fixed_f17oxuXW_58LL8mYJsm4T_mCeIw` | `dashboards.permissions:read` | Read all dashboard permissions. |
| `fixed:dashboards.permissions:writer` | `fixed_CcznxhWX_Yqn8uWMXMQ-b5iFW9k` | All permissions from `fixed:dashboards.permissions:reader` and <br>`dashboards.permissions:write` | Read and update all dashboard permissions. |
| `fixed:dashboards.public:writer` | `fixed_f_GHHRBciaqESXfGz2oCcooqHxs` | `dashboards.public:write` | Create, update, delete or pause a shared dashboard. |
| `fixed:datasources:creator` | `fixed_XX8jHREgUt-wo1A-rPXIiFlX6Zw` | `datasources:create` | Create data sources. |
| `fixed:datasources:explorer` | `fixed_qDzW9mzx9yM91T5Bi8dHUM2muTw` | `datasources:explore` | Enable the Explore feature. Data source permissions still apply, you can only query data sources for which you have query permissions. |
| `fixed:datasources:reader` | `fixed_C2x8IxkiBc1KZVjyYH775T9jNMQ` | `datasources:read`<br>`datasources:query` | Read and query data sources. |
| `fixed:datasources:writer` | `fixed_q8HXq8kjjA5IlHHgBJlKlUyaNik` | All permissions from `fixed:datasources:reader` and <br>`datasources:create`<br>`datasources:write`<br>`datasources:delete` | Read, query, create, delete, or update a data source. |
| `fixed:datasources.builtin:reader` | `fixed_q8HXq8kjjA5IlHHgBJlKlUyaNik` | `datasources:read` and `datasources:query` scoped to `datasources:uid:grafana` | An internal role used to grant Viewers access to the builtin example data source in Grafana. |
| `fixed:datasources.caching:reader` | `fixed_D2ddpGxJYlw0mbsTS1ek9fj0kj4` | `datasources.caching:read` | Read data source query caching settings. |
| `fixed:datasources.caching:writer` | `fixed_JtFjHr7jd7hSqUYcktKvRvIOGRE` | `datasources.caching:read`<br>`datasources.caching:write` | Enable, disable, or update query caching settings. |
| `fixed:datasources.id:reader` | `fixed_entg--fHmDqWY2-69N0ocawK0Os` | `datasources.id:read` | Read the ID of a data source based on its name. |
| `fixed:datasources.insights:reader` | `fixed_EBZ3NwlfecNPp2p0XcZRC1nfEYk` | `datasources.insights:read` | Read data source insights data. |
| `fixed:datasources.permissions:reader` | `fixed_ErYA-cTN3yn4h4GxaVPcawRhiOY` | `datasources.permissions:read` | Read data source permissions. |
| `fixed:datasources.permissions:writer` | `fixed_aiQh9YDfLOKjQhYasF9_SFUjQiw` | All permissions from `fixed:datasources.permissions:reader` and <br>`datasources.permissions:write` | Create, read, or delete permissions of a data source. |
| `fixed:folders:creator` | `fixed_gGLRbZGAGB6n9uECqSh_W382RlQ` | `folders:create` | Create folders in the root level. |
| `fixed:folders:reader` | `fixed_yeW-5QPeo-i5PZUIUXMlAA97GnQ` | `folders:read`<br>`dashboards:read` | Read all folders and dashboards. |
| `fixed:folders:writer` | `fixed_wJXLoTzgE7jVuz90dryYoiogL0o` | All permissions from `fixed:dashboards:writer` and <br>`folders:read`<br>`folders:write`<br>`folders:create`<br>`folders:delete`<br>`folders.permissions:read`<br>`folders.permissions:write` | Read, update, and delete all folders and dashboards. Create folders and subfolders. |
| `fixed:folders.general:reader` | `fixed_rSASbkg8DvpG_gTX5s41d7uxRvI` | `folders:read` scoped to `folders:uid:general` | An internal role used to correctly display access to the folder tree for Viewer role. |
| `fixed:folders.permissions:reader` | `fixed_E06l4cx0JFm47EeLBE4nmv3pnSo` | `folders.permissions:read` | Read all folder permissions. |
| `fixed:folders.permissions:writer` | `fixed_3GAgpQ_hWG8o7-lwNb86_VB37eI` | All permissions from `fixed:folders.permissions:reader` and <br>`folders.permissions:write` | Read and update all folder permissions. |
| `fixed:ldap:reader` | `fixed_lMcOPwSkxKY-qCK8NMJc5k6izLE` | `ldap.user:read`<br>`ldap.status:read` | Read the LDAP configuration and LDAP status information. |
| `fixed:ldap:writer` | `fixed_p6AvnU4GCQyIh7-hbwI-bk3GYnU` | All permissions from `fixed:ldap:reader` and <br>`ldap.user:sync`<br>`ldap.config:reload` | Read and update the LDAP configuration, and read LDAP status information. |
| `fixed:library.panels:creator` | `fixed_6eX6ItfegCIY5zLmPqTDW8ZV7KY` | `library.panels:create`<br>`folders:read` | Create library panel at the root level. |
| `fixed:library.panels:general.reader` | `fixed_ct0DghiBWR_2BiQm3EvNPDVmpio` | `library.panels:read` | Read all library panels at the root level. |
| `fixed:library.panels:general.writer` | `fixed_DgprkmqfN_1EhZ2v1_d1fYG8LzI` | All permissions from `fixed:library.panels:general.reader` plus<br>`library.panels:create`<br>`library.panels:delete`<br>`library.panels:write` | Create, read, write or delete all library panels and their permissions at the root level. |
| `fixed:library.panels:reader` | `fixed_tvTr9CnZ6La5vvUO_U_X1LPnhUs` | `library.panels:read` | Read all library panels. |
| `fixed:library.panels:writer` | `fixed_JTljAr21LWLTXCkgfBC4H0lhBC8` | All permissions from `fixed:library.panels:reader` plus<br>`library.panels:create`<br>`library.panels:delete`<br>`library.panels:write` | Create, read, write or delete all library panels and their permissions. |
| `fixed:licensing:reader` | `fixed_OADpuXvNEylO2Kelu3GIuBXEAYE` | `licensing:read`<br>`licensing.reports:read` | Read licensing information and licensing reports. |
| `fixed:licensing:writer` | `fixed_gzbz3rJpQMdaKHt-E4q0PVaKMoE` | All permissions from `fixed:licensing:reader` and <br>`licensing:write`<br>`licensing:delete` | Read licensing information and licensing reports, update and delete the license token. |
| `fixed:migrationassistant:migrator` | `fixed_LLk2p7TRuBztOAksTQb1Klc8YTk` | `migrationassistant:migrate` | Execute on-prem to cloud migrations through the Migration Assistant. |
| `fixed:org.users:reader` | `fixed_oCqNwlVHLOpw7-jAlwp4HzYqwGY` | `org.users:read` | Read users within a single organization. |
| `fixed:org.users:writer` | `fixed_VERj5nayasjgf_Yh0sWqqCkxWlw` | All permissions from `fixed:org.users:reader` and <br>`org.users:add`<br>`org.users:remove`<br>`org.users:write` | Within a single organization, add a user, invite a new user, read information about a user and their role, remove a user from that organization, or change the role of a user. |
| `fixed:organization:maintainer` | `fixed_CMm-uuBaPUBf4r8XG3jIvxo55bg` | All permissions from `fixed:organization:reader` and <br> `orgs:write`<br>`orgs:create`<br>`orgs:delete`<br>`orgs.quotas:write` | Create, read, write, or delete an organization. Read or write its quotas. This role needs to be assigned globally. |
| `fixed:organization:reader` | `fixed_0SZPJlTHdNEe8zO91zv7Zwiwa2w` | `orgs:read`<br>`orgs.quotas:read` | Read an organization and its quotas. |
| `fixed:organization:writer` | `fixed_Y4jGqDd8w1yCrPwlik8z5Iu8-3M` | All permissions from `fixed:organization:reader` and <br> `orgs:write`<br>`orgs.preferences:read`<br>`orgs.preferences:write` | Read an organization, its quotas, or its preferences. Update organization properties, or its preferences. |
| `fixed:plugins:maintainer` | `fixed_yEOKidBcWgbm74x-nTa3lW5lOyY` | `plugins:install` | Install and uninstall plugins. Needs to be assigned globally. |
| `fixed:plugins:writer` | `fixed_MRYpGk7kpNNwt2VoVOXFiPnQziE` | `plugins:write` | Enable and disable plugins and edit plugins' settings. |
| `fixed:plugins.app:reader` | `fixed_AcZRiNYx7NueYkUqzw1o2OGGUAA` | `plugins.app:access` | Access application plugins (still enforcing the organization role). |
| `fixed:provisioning:writer` | `fixed_bgk1FCyR6OEDwhgirZlQgu5LlCA` | `provisioning:reload` | Reload provisioning. |
| `fixed:reports:reader` | `fixed_72_8LU_0ukfm6BdblOw8Z9q-GQ8` | `reports:read`<br>`reports:send`<br>`reports.settings:read` | Read all reports and shared report settings. |
| `fixed:reports:writer` | `fixed_jBW3_7g1EWOjGVBYeVRwtFxhUNw` | All permissions from `fixed:reports:reader` and <br>`reports:create`<br>`reports:write`<br>`reports:delete`<br>`reports.settings:write` | Create, read, update, or delete all reports and shared report settings. |
| `fixed:roles:reader` | `fixed_GkfG-1NSwEGb4hpK3-E3qHyNltc` | `roles:read`<br>`teams.roles:read`<br>`users.roles:read`<br>`users.permissions:read` | Read all access control roles, roles and permissions assigned to users, teams. |
| `fixed:roles:resetter` | `fixed_WgPpC3qJRmVpVTJavFNwfS5RuzQ` | `roles:write` with scope `permissions:type:escalate` | Reset basic roles to their default. |
| `fixed:roles:writer` | `fixed_W5aFaw8isAM27x_eWfElBhZ0iOc` | All permissions from `fixed:roles:reader` and <br>`roles:write`<br>`roles:delete`<br>`teams.roles:add`<br>`teams.roles:remove`<br>`users.roles:add`<br>`users.roles:remove` | Create, read, update, or delete all roles, assign or unassign roles to users, teams. |
| `fixed:serviceaccounts:creator` | `fixed_Ikw60fckA0MyiiZ73BawSfOULy4` | `serviceaccounts:create` | Create Grafana service accounts. |
| `fixed:serviceaccounts:reader` | `fixed_QFjJAZ88iawMLInYOxPA1DB1w6I` | `serviceaccounts:read` | Read Grafana service accounts. |
| `fixed:serviceaccounts:writer` | `fixed_iBvUNUEZBZ7PUW0vdkN5iojc2sk` | `serviceaccounts:read`<br>`serviceaccounts:create`<br>`serviceaccounts:write`<br>`serviceaccounts:delete`<br>`serviceaccounts.permissions:read`<br>`serviceaccounts.permissions:write` | Create, update, read and delete all Grafana service accounts and manage service account permissions. |
| `fixed:settings:reader` | `fixed_0LaUt1x6PP8hsZzEBhqPQZFUd8Q` | `settings:read` | Read Grafana instance settings. |
| `fixed:settings:writer` | `fixed_joIHDgMrGg790hMhUufVzcU4j44` | All permissions from `fixed:settings:reader` and<br>`settings:write` | Read and update Grafana instance settings. |
| `fixed:stats:reader` | `fixed_OnRCXxZVINWpcKvTF5A1gecJ7pA` | `server.stats:read` | Read Grafana instance statistics. |
| `fixed:support.bundles:reader` | `fixed_gcPjI3PTUJwRx-GJZwDhNa7zbos` | `support.bundles:read` | List and download support bundles. |
| `fixed:support.bundles:writer` | `fixed_dTgCv9Wxrp_WHAhwHYIgeboxKpE` | `support.bundles:read`<br>`support.bundles:create`<br>`support.bundles:delete` | Create, delete, list and download support bundles. |
| `fixed:teams:creator` | `fixed_nzVQoNSDSn0fg1MDgO6XnZX2RZI` | `teams:create`<br>`org.users:read` | Create a team and list organization users (required to manage the created team). |
| `fixed:teams:read` | `fixed_Z8pB0GQlrqRt8IZBCJQxPWvJPgQ` | `teams:read` | List all teams. |
| `fixed:teams:writer` | `fixed_xw1T0579h620MOYi4L96GUs7fZY` | `teams:create`<br>`teams:delete`<br>`teams:read`<br>`teams:write`<br>`teams.permissions:read`<br>`teams.permissions:write` | Create, read, update and delete teams and manage team memberships. |
| `fixed:usagestats:reader` | `fixed_eAM0azEvnWFCJAjNkUKnGL_1-bU` | `server.usagestats.report:read` | View usage statistics report. |
| `fixed:users:reader` | `fixed_buZastUG3reWyQpPemcWjGqPAd0` | `users:read`<br>`users.quotas:read`<br>`users.authtoken:read` | Read all users and their information, such as team memberships, authentication tokens, and quotas. |
| `fixed:users:writer` | `fixed_wjzgHHo_Ux25DJuELn_oiAdB_yM` | All permissions from `fixed:users:reader` and <br>`users:write`<br>`users:create`<br>`users:delete`<br>`users:enable`<br>`users:disable`<br>`users.password:write`<br>`users.permissions:write`<br>`users:logout`<br>`users.authtoken:write`<br>`users.quotas:write` | Read and update all attributes and settings for all users in Grafana: update user information, read user information, create or enable or disable a user, make a user a Grafana administrator, sign out a user, update a users authentication token, or update quotas for all users. |
| Fixed role | UUID | Permissions | Description |
| -------------------------------------------- | ----------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `fixed:alerting:reader` | `fixed_O2oP1_uBFozI2i93klAkcvEWR30` | All permissions from `fixed:alerting.rules:reader` <br>`fixed:alerting.instances:reader`<br>`fixed:alerting.notifications:reader` | Read-only permissions for all Grafana, Mimir, Loki and Alertmanager alert rules\*, alerts, contact points, and notification policies.[\*](#alerting-roles) |
| `fixed:alerting:writer` | `fixed_-PAZgSJsDlRD8NUg-PFSeH_BkJY` | All permissions from `fixed:alerting.rules:writer` <br>`fixed:alerting.instances:writer`<br>`fixed:alerting.notifications:writer` | Create, update, and delete Grafana, Mimir, Loki and Alertmanager alert rules\*, silences, contact points, templates, mute timings, and notification policies.[\*](#alerting-roles) |
| `fixed:alerting.instances:reader` | `fixed_ut5fVS-Ulh_ejFoskFhJT_rYg0Y` | `alert.instances:read` for organization scope <br> `alert.instances.external:read` for scope `datasources:*` | Read all alerts and silences in the organization produced by Grafana Alerts and Mimir and Loki alerts and silences.[\*](#alerting-roles) |
| `fixed:alerting.instances:writer` | `fixed_pKOBJE346uyqMLdgWbk1NsQfEl0` | All permissions from `fixed:alerting.instances:reader` and<br> `alert.instances:create`<br>`alert.instances:write` for organization scope <br> `alert.instances.external:write` for scope `datasources:*` | Create, update and expire all silences in the organization produced by Grafana, Mimir, and Loki.[\*](#alerting-roles) |
| `fixed:alerting.notifications:reader` | `fixed_hmBn0lX5h1RZXB9Vaot420EEdA0` | `alert.notifications:read` for organization scope<br>`alert.notifications.external:read` for scope `datasources:*` | Read all Grafana and Alertmanager contact points, templates, and notification policies.[\*](#alerting-roles) |
| `fixed:alerting.notifications:writer` | `fixed_XplK6HPNxf9AP5IGTdB5Iun4tJc` | All permissions from `fixed:alerting.notifications:reader` and<br>`alert.notifications:write`for organization scope<br>`alert.notifications.external:read` for scope `datasources:*` | Create, update, and delete contact points, templates, mute timings and notification policies for Grafana and external Alertmanager.[\*](#alerting-roles) |
| `fixed:alerting.provisioning:writer` | `fixed_y7pFjdEkxpx5ETdcxPvp0AgRuUo` | `alert.provisioning:read` and `alert.provisioning:write` | Create, update and delete Grafana alert rules, notification policies, contact points, templates, etc via provisioning API. [\*](#alerting-roles) |
| `fixed:alerting.provisioning.secrets:reader` | `fixed_9fmzXXZZG-Od0Amy2ofEG8Uk--c` | `alert.provisioning:read` and `alert.provisioning.secrets:read` | Read-only permissions for Provisioning API and let export resources with decrypted secrets [\*](#alerting-roles) |
| `fixed:alerting.provisioning.status:writer` | `fixed_eAxlzfkTuobvKEgXHveFMBZrOj8` | `alert.provisioning.provenance:write` | Set provenance status to alert rules, notification policies, contact points, etc. Should be used together with regular writer roles. [\*](#alerting-roles) |
| `fixed:alerting.rules:reader` | `fixed_fRGKL_vAqUsmUWq5EYKnOha9DcA` | `alert.rule:read`, `alert.silences:read` for scope `folders:*` <br> `alert.rules.external:read` for scope `datasources:*` <br> `alert.notifications.time-intervals:read` <br> `alert.notifications.receivers:list` | Read all\* Grafana, Mimir, and Loki alert rules.[\*](#alerting-roles) and read rule-specific silences |
| `fixed:alerting.rules:writer` | `fixed_YJJGwAalUwDZPrXSyFH8GfYBXAc` | All permissions from `fixed:alerting.rules:reader` and <br> `alert.rule:create` <br> `alert.rule:write` <br> `alert.rule:delete` <br> `alert.silences:create` <br> `alert.silences:write` for scope `folders:*` <br> `alert.rules.external:write` for scope `datasources:*` | Create, update, and delete all\* Grafana, Mimir, and Loki alert rules.[\*](#alerting-roles) and manage rule-specific silences |
| `fixed:annotations:reader` | `fixed_hpZnoizrfAJsrceNcNQqWYV-xNU` | `annotations:read` for scopes `annotations:type:*` | Read all annotations and annotation tags. |
| `fixed:annotations:writer` | `fixed_ZVW-Aa9Tzle6J4s2aUFcq1StKWE` | All permissions from `fixed:annotations:reader` <br>`annotations:write` <br>`annotations.create`<br> `annotations:delete` for scope `annotations:type:*` | Read, create, update and delete all annotations and annotation tags. |
| `fixed:annotations.dashboard:writer` | `fixed_8A775xenXeKaJk4Cr7bchP9yXOA` | `annotations:write` <br>`annotations.create`<br> `annotations:delete` for scope `annotations:type:dashboard` | Create, update and delete dashboard annotations and annotation tags. |
| `fixed:authentication.config:writer` | `fixed_0rYhZ2Qnzs8AdB1nX7gexk3fHDw` | `settings:read` for scope `settings:auth.saml:*` <br> `settings:write` for scope `settings:auth.saml:*` | Read and update authentication and SAML settings. |
| `fixed:general.auth.config:writer` | `fixed_QFxIT_FGtBqbIVJIwx1bLgI5z6c` | `settings:read` for scope `settings:auth:oauth_allow_insecure_email_lookup` <br> `settings:write` for scope `settings:auth:oauth_allow_insecure_email_lookup` | Read and update the Grafana instance's general authentication configuration settings. |
| `fixed:dashboards:creator` | `fixed_ZorKUcEPCM01A1fPakEzGBUyU64` | `dashboards:create`<br>`folders:read` | Create dashboards. |
| `fixed:dashboards:reader` | `fixed_Sgr67JTOhjQGFlzYRahOe45TdWM` | `dashboards:read` | Read all dashboards. |
| `fixed:dashboards:writer` | `fixed_OK2YOQGIoI1G031hVzJB6rAJQAs` | All permissions from `fixed:dashboards:reader` and <br>`dashboards:write`<br>`dashboards:delete`<br>`dashboards:create`<br>`dashboards.permissions:read`<br>`dashboards.permissions:write` | Read, create, update, and delete all dashboards. |
| `fixed:dashboards.insights:reader` | `fixed_JlBJ2_gizP8zhgaeGE2rjyZe2Rs` | `dashboards.insights:read` | Read dashboard insights data and see presence indicators. |
| `fixed:dashboards.permissions:reader` | `fixed_f17oxuXW_58LL8mYJsm4T_mCeIw` | `dashboards.permissions:read` | Read all dashboard permissions. |
| `fixed:dashboards.permissions:writer` | `fixed_CcznxhWX_Yqn8uWMXMQ-b5iFW9k` | All permissions from `fixed:dashboards.permissions:reader` and <br>`dashboards.permissions:write` | Read and update all dashboard permissions. |
| `fixed:dashboards.public:writer` | `fixed_f_GHHRBciaqESXfGz2oCcooqHxs` | `dashboards.public:write` | Create, update, delete or pause a shared dashboard. |
| `fixed:datasources:creator` | `fixed_XX8jHREgUt-wo1A-rPXIiFlX6Zw` | `datasources:create` | Create data sources. |
| `fixed:datasources:explorer` | `fixed_qDzW9mzx9yM91T5Bi8dHUM2muTw` | `datasources:explore` | Enable the Explore feature. Data source permissions still apply, you can only query data sources for which you have query permissions. |
| `fixed:datasources:reader` | `fixed_C2x8IxkiBc1KZVjyYH775T9jNMQ` | `datasources:read`<br>`datasources:query` | Read and query data sources. |
| `fixed:datasources:writer` | `fixed_q8HXq8kjjA5IlHHgBJlKlUyaNik` | All permissions from `fixed:datasources:reader` and <br>`datasources:create`<br>`datasources:write`<br>`datasources:delete` | Read, query, create, delete, or update a data source. |
| `fixed:datasources.builtin:reader` | `fixed_q8HXq8kjjA5IlHHgBJlKlUyaNik` | `datasources:read` and `datasources:query` scoped to `datasources:uid:grafana` | An internal role used to grant Viewers access to the builtin example data source in Grafana. |
| `fixed:datasources.caching:reader` | `fixed_D2ddpGxJYlw0mbsTS1ek9fj0kj4` | `datasources.caching:read` | Read data source query caching settings. |
| `fixed:datasources.caching:writer` | `fixed_JtFjHr7jd7hSqUYcktKvRvIOGRE` | `datasources.caching:read`<br>`datasources.caching:write` | Enable, disable, or update query caching settings. |
| `fixed:datasources.id:reader` | `fixed_entg--fHmDqWY2-69N0ocawK0Os` | `datasources.id:read` | Read the ID of a data source based on its name. |
| `fixed:datasources.insights:reader` | `fixed_EBZ3NwlfecNPp2p0XcZRC1nfEYk` | `datasources.insights:read` | Read data source insights data. |
| `fixed:datasources.permissions:reader` | `fixed_ErYA-cTN3yn4h4GxaVPcawRhiOY` | `datasources.permissions:read` | Read data source permissions. |
| `fixed:datasources.permissions:writer` | `fixed_aiQh9YDfLOKjQhYasF9_SFUjQiw` | All permissions from `fixed:datasources.permissions:reader` and <br>`datasources.permissions:write` | Create, read, or delete permissions of a data source. |
| `fixed:folders:creator` | `fixed_gGLRbZGAGB6n9uECqSh_W382RlQ` | `folders:create` | Create folders in the root level. |
| `fixed:folders:reader` | `fixed_yeW-5QPeo-i5PZUIUXMlAA97GnQ` | `folders:read`<br>`dashboards:read` | Read all folders and dashboards. |
| `fixed:folders:writer` | `fixed_wJXLoTzgE7jVuz90dryYoiogL0o` | All permissions from `fixed:dashboards:writer` and <br>`folders:read`<br>`folders:write`<br>`folders:create`<br>`folders:delete`<br>`folders.permissions:read`<br>`folders.permissions:write` | Read, update, and delete all folders and dashboards. Create folders and subfolders. |
| `fixed:folders.general:reader` | `fixed_rSASbkg8DvpG_gTX5s41d7uxRvI` | `folders:read` scoped to `folders:uid:general` | An internal role used to correctly display access to the folder tree for Viewer role. |
| `fixed:folders.permissions:reader` | `fixed_E06l4cx0JFm47EeLBE4nmv3pnSo` | `folders.permissions:read` | Read all folder permissions. |
| `fixed:folders.permissions:writer` | `fixed_3GAgpQ_hWG8o7-lwNb86_VB37eI` | All permissions from `fixed:folders.permissions:reader` and <br>`folders.permissions:write` | Read and update all folder permissions. |
| `fixed:ldap:reader` | `fixed_lMcOPwSkxKY-qCK8NMJc5k6izLE` | `ldap.user:read`<br>`ldap.status:read` | Read the LDAP configuration and LDAP status information. |
| `fixed:ldap:writer` | `fixed_p6AvnU4GCQyIh7-hbwI-bk3GYnU` | All permissions from `fixed:ldap:reader` and <br>`ldap.user:sync`<br>`ldap.config:reload` | Read and update the LDAP configuration, and read LDAP status information. |
| `fixed:library.panels:creator` | `fixed_6eX6ItfegCIY5zLmPqTDW8ZV7KY` | `library.panels:create`<br>`folders:read` | Create library panel at the root level. |
| `fixed:library.panels:general.reader` | `fixed_ct0DghiBWR_2BiQm3EvNPDVmpio` | `library.panels:read` | Read all library panels at the root level. |
| `fixed:library.panels:general.writer` | `fixed_DgprkmqfN_1EhZ2v1_d1fYG8LzI` | All permissions from `fixed:library.panels:general.reader` plus<br>`library.panels:create`<br>`library.panels:delete`<br>`library.panels:write` | Create, read, write or delete all library panels and their permissions at the root level. |
| `fixed:library.panels:reader` | `fixed_tvTr9CnZ6La5vvUO_U_X1LPnhUs` | `library.panels:read` | Read all library panels. |
| `fixed:library.panels:writer` | `fixed_JTljAr21LWLTXCkgfBC4H0lhBC8` | All permissions from `fixed:library.panels:reader` plus<br>`library.panels:create`<br>`library.panels:delete`<br>`library.panels:write` | Create, read, write or delete all library panels and their permissions. |
| `fixed:licensing:reader` | `fixed_OADpuXvNEylO2Kelu3GIuBXEAYE` | `licensing:read`<br>`licensing.reports:read` | Read licensing information and licensing reports. |
| `fixed:licensing:writer` | `fixed_gzbz3rJpQMdaKHt-E4q0PVaKMoE` | All permissions from `fixed:licensing:reader` and <br>`licensing:write`<br>`licensing:delete` | Read licensing information and licensing reports, update and delete the license token. |
| `fixed:migrationassistant:migrator` | `fixed_LLk2p7TRuBztOAksTQb1Klc8YTk` | `migrationassistant:migrate` | Execute on-prem to cloud migrations through the Migration Assistant. |
| `fixed:org.users:reader` | `fixed_oCqNwlVHLOpw7-jAlwp4HzYqwGY` | `org.users:read` | Read users within a single organization. |
| `fixed:org.users:writer` | `fixed_VERj5nayasjgf_Yh0sWqqCkxWlw` | All permissions from `fixed:org.users:reader` and <br>`org.users:add`<br>`org.users:remove`<br>`org.users:write` | Within a single organization, add a user, invite a new user, read information about a user and their role, remove a user from that organization, or change the role of a user. |
| `fixed:organization:maintainer` | `fixed_CMm-uuBaPUBf4r8XG3jIvxo55bg` | All permissions from `fixed:organization:reader` and <br> `orgs:write`<br>`orgs:create`<br>`orgs:delete`<br>`orgs.quotas:write` | Create, read, write, or delete an organization. Read or write its quotas. This role needs to be assigned globally. |
| `fixed:organization:reader` | `fixed_0SZPJlTHdNEe8zO91zv7Zwiwa2w` | `orgs:read`<br>`orgs.quotas:read` | Read an organization and its quotas. |
| `fixed:organization:writer` | `fixed_Y4jGqDd8w1yCrPwlik8z5Iu8-3M` | All permissions from `fixed:organization:reader` and <br> `orgs:write`<br>`orgs.preferences:read`<br>`orgs.preferences:write` | Read an organization, its quotas, or its preferences. Update organization properties, or its preferences. |
| `fixed:plugins:maintainer` | `fixed_yEOKidBcWgbm74x-nTa3lW5lOyY` | `plugins:install` | Install and uninstall plugins. Needs to be assigned globally. |
| `fixed:plugins:writer` | `fixed_MRYpGk7kpNNwt2VoVOXFiPnQziE` | `plugins:write` | Enable and disable plugins and edit plugins' settings. |
| `fixed:plugins.app:reader` | `fixed_AcZRiNYx7NueYkUqzw1o2OGGUAA` | `plugins.app:access` | Access application plugins (still enforcing the organization role). |
| `fixed:provisioning:writer` | `fixed_bgk1FCyR6OEDwhgirZlQgu5LlCA` | `provisioning:reload` | Reload provisioning. |
| `fixed:reports:reader` | `fixed_72_8LU_0ukfm6BdblOw8Z9q-GQ8` | `reports:read`<br>`reports:send`<br>`reports.settings:read` | Read all reports and shared report settings. |
| `fixed:reports:writer` | `fixed_jBW3_7g1EWOjGVBYeVRwtFxhUNw` | All permissions from `fixed:reports:reader` and <br>`reports:create`<br>`reports:write`<br>`reports:delete`<br>`reports.settings:write` | Create, read, update, or delete all reports and shared report settings. |
| `fixed:roles:reader` | `fixed_GkfG-1NSwEGb4hpK3-E3qHyNltc` | `roles:read`<br>`teams.roles:read`<br>`users.roles:read`<br>`users.permissions:read` | Read all access control roles, roles and permissions assigned to users, teams. |
| `fixed:roles:resetter` | `fixed_WgPpC3qJRmVpVTJavFNwfS5RuzQ` | `roles:write` with scope `permissions:type:escalate` | Reset basic roles to their default. |
| `fixed:roles:writer` | `fixed_W5aFaw8isAM27x_eWfElBhZ0iOc` | All permissions from `fixed:roles:reader` and <br>`roles:write`<br>`roles:delete`<br>`teams.roles:add`<br>`teams.roles:remove`<br>`users.roles:add`<br>`users.roles:remove` | Create, read, update, or delete all roles, assign or unassign roles to users, teams. |
| `fixed:serviceaccounts:creator` | `fixed_Ikw60fckA0MyiiZ73BawSfOULy4` | `serviceaccounts:create` | Create Grafana service accounts. |
| `fixed:serviceaccounts:reader` | `fixed_QFjJAZ88iawMLInYOxPA1DB1w6I` | `serviceaccounts:read` | Read Grafana service accounts. |
| `fixed:serviceaccounts:writer` | `fixed_iBvUNUEZBZ7PUW0vdkN5iojc2sk` | `serviceaccounts:read`<br>`serviceaccounts:create`<br>`serviceaccounts:write`<br>`serviceaccounts:delete`<br>`serviceaccounts.permissions:read`<br>`serviceaccounts.permissions:write` | Create, update, read and delete all Grafana service accounts and manage service account permissions. |
| `fixed:settings:reader` | `fixed_0LaUt1x6PP8hsZzEBhqPQZFUd8Q` | `settings:read` | Read Grafana instance settings. |
| `fixed:settings:writer` | `fixed_joIHDgMrGg790hMhUufVzcU4j44` | All permissions from `fixed:settings:reader` and<br>`settings:write` | Read and update Grafana instance settings. |
| `fixed:stats:reader` | `fixed_OnRCXxZVINWpcKvTF5A1gecJ7pA` | `server.stats:read` | Read Grafana instance statistics. |
| `fixed:support.bundles:reader` | `fixed_gcPjI3PTUJwRx-GJZwDhNa7zbos` | `support.bundles:read` | List and download support bundles. |
| `fixed:support.bundles:writer` | `fixed_dTgCv9Wxrp_WHAhwHYIgeboxKpE` | `support.bundles:read`<br>`support.bundles:create`<br>`support.bundles:delete` | Create, delete, list and download support bundles. |
| `fixed:teams:creator` | `fixed_nzVQoNSDSn0fg1MDgO6XnZX2RZI` | `teams:create`<br>`org.users:read` | Create a team and list organization users (required to manage the created team). |
| `fixed:teams:read` | `fixed_Z8pB0GQlrqRt8IZBCJQxPWvJPgQ` | `teams:read` | List all teams. |
| `fixed:teams:writer` | `fixed_xw1T0579h620MOYi4L96GUs7fZY` | `teams:create`<br>`teams:delete`<br>`teams:read`<br>`teams:write`<br>`teams.permissions:read`<br>`teams.permissions:write` | Create, read, update and delete teams and manage team memberships. |
| `fixed:usagestats:reader` | `fixed_eAM0azEvnWFCJAjNkUKnGL_1-bU` | `server.usagestats.report:read` | View usage statistics report. |
| `fixed:users:reader` | `fixed_buZastUG3reWyQpPemcWjGqPAd0` | `users:read`<br>`users.quotas:read`<br>`users.authtoken:read` | Read all users and their information, such as team memberships, authentication tokens, and quotas. |
| `fixed:users:writer` | `fixed_wjzgHHo_Ux25DJuELn_oiAdB_yM` | All permissions from `fixed:users:reader` and <br>`users:write`<br>`users:create`<br>`users:delete`<br>`users:enable`<br>`users:disable`<br>`users.password:write`<br>`users.permissions:write`<br>`users:logout`<br>`users.authtoken:write`<br>`users.quotas:write` | Read and update all attributes and settings for all users in Grafana: update user information, read user information, create or enable or disable a user, make a user a Grafana administrator, sign out a user, update a users authentication token, or update quotas for all users. |
### Alerting roles
@@ -164,20 +164,10 @@ Access to Grafana alert rules is an intersection of many permissions:
- Permission to read a folder. For example, the fixed role `fixed:folders:reader` includes the action `folders:read` and a folder scope `folders:id:`.
- Permission to query **all** data sources that a given alert rule uses. If a user cannot query a given data source, they cannot see any alert rules that query that data source.
There is only one exclusion. Role `fixed:alerting.provisioning:writer` does not require user to have any additional permissions and provides access to all aspects of the alerting configuration via special provisioning API.
There is only one exclusion at this moment. Role `fixed:alerting.provisioning:writer` does not require user to have any additional permissions and provides access to all aspects of the alerting configuration via special provisioning API.
For more information about the permissions required to access alert rules, refer to [Create a custom role to access alerts in a folder](ref:plan-rbac-rollout-strategy-create-a-custom-role-to-access-alerts-in-a-folder).
#### Alerting basic roles
The following table lists the default RBAC alerting role assignments to the basic roles:
| Basic role | Associated fixed roles | Description |
| ---------- | --------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- |
| Admin | `fixed:alerting:writer`<br>`fixed:alerting.provisioning.secrets:reader`<br>`fixed:alerting.provisioning:writer` | Default [Grafana organization administrator](ref:rbac-basic-roles) assignments. |
| Editor | `fixed:alerting:writer`<br>`fixed:alerting.provisioning.provenance:writer` | Default [Editor](ref:rbac-basic-roles) assignments. |
| Viewer | `fixed:alerting:reader` | Default [Viewer](ref:rbac-basic-roles) assignments. |
### Grafana OnCall roles
If you are using [Grafana OnCall](ref:oncall), you can try out the integration between Grafana OnCall and RBAC.

Some files were not shown because too many files have changed in this diff Show More