mirror of
https://github.com/grafana/grafana.git
synced 2025-12-21 03:54:29 +08:00
Compare commits
221 Commits
leeoniya/l
...
team-user-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
85d7181b7d | ||
|
|
d0fe342cfe | ||
|
|
1ef7c68f53 | ||
|
|
9dd8c85448 | ||
|
|
64c61c6916 | ||
|
|
f50d513252 | ||
|
|
7772c3ab2e | ||
|
|
8288ce6dd6 | ||
|
|
f5df0b05ef | ||
|
|
1f1c75f817 | ||
|
|
af7f110664 | ||
|
|
de45393eb5 | ||
|
|
4581ed89a0 | ||
|
|
050f6572a8 | ||
|
|
ffcd06c629 | ||
|
|
58e0d03f46 | ||
|
|
f116208b88 | ||
|
|
ef61b67e66 | ||
|
|
b70c6a726f | ||
|
|
e6eb40a679 | ||
|
|
fe0486915e | ||
|
|
66766fe729 | ||
|
|
a2c5d6e686 | ||
|
|
3e9662d910 | ||
|
|
9818822e87 | ||
|
|
f7e07d814a | ||
|
|
77aac05b09 | ||
|
|
a59c4e2fcc | ||
|
|
5e2a579802 | ||
|
|
5a111bc087 | ||
|
|
c2b15ca786 | ||
|
|
6d7ce16883 | ||
|
|
bfa7ce9d78 | ||
|
|
4355b3ed0d | ||
|
|
92ef1c4942 | ||
|
|
bcc5d29bf7 | ||
|
|
9376d569cc | ||
|
|
c2489d2768 | ||
|
|
67444cee78 | ||
|
|
bfee2ecc65 | ||
|
|
1535cfc17b | ||
|
|
9ad6507eef | ||
|
|
d8a5d8d882 | ||
|
|
3fffb2d998 | ||
|
|
1162fa5104 | ||
|
|
8c3c3a851f | ||
|
|
1cc21a0705 | ||
|
|
5b34d92dca | ||
|
|
668ef398d6 | ||
|
|
d92cb9f7a6 | ||
|
|
326d374266 | ||
|
|
5717da4b22 | ||
|
|
0ab58642c4 | ||
|
|
09a7a0c94f | ||
|
|
23c192f330 | ||
|
|
6b26391cf2 | ||
|
|
cd40f7e36c | ||
|
|
bfca0d578c | ||
|
|
060af9cede | ||
|
|
4ee2112ea4 | ||
|
|
9ca6ad3b49 | ||
|
|
3f48a6358f | ||
|
|
c1485ecf5f | ||
|
|
1491607e8e | ||
|
|
7c709f0b89 | ||
|
|
42bca68966 | ||
|
|
df44209e53 | ||
|
|
ed17fb22dc | ||
|
|
1bb9de6f75 | ||
|
|
6603abc873 | ||
|
|
f041563df3 | ||
|
|
ae8a8cf16e | ||
|
|
906d32b437 | ||
|
|
44a92d252b | ||
|
|
7fe5772888 | ||
|
|
0d67fac87f | ||
|
|
3e4933ec60 | ||
|
|
a2150b0b79 | ||
|
|
f5f0c1e6f6 | ||
|
|
b550750a9b | ||
|
|
e92a976de2 | ||
|
|
108693eb31 | ||
|
|
97a6ab7b1c | ||
|
|
3bd49f6546 | ||
|
|
73657be5e7 | ||
|
|
3082a762d3 | ||
|
|
b4b410f5be | ||
|
|
6eac95f860 | ||
|
|
5091c946b5 | ||
|
|
6da33546a5 | ||
|
|
ac5e54a225 | ||
|
|
0a9f93436a | ||
|
|
eaa1b62c01 | ||
|
|
7ee61a9277 | ||
|
|
00e4d98ca3 | ||
|
|
55a29bd2d1 | ||
|
|
a5b8038f35 | ||
|
|
3563388d4d | ||
|
|
6c8c4c32b5 | ||
|
|
e60ad6f195 | ||
|
|
3e31f7b713 | ||
|
|
cbd794d0b8 | ||
|
|
a67fad4734 | ||
|
|
a194219365 | ||
|
|
ec9f39d54a | ||
|
|
c9e381b96f | ||
|
|
97c8121785 | ||
|
|
59ff606106 | ||
|
|
4cb290e4cc | ||
|
|
1f14f1447f | ||
|
|
67f811b6d8 | ||
|
|
4bca10195e | ||
|
|
5162988fa1 | ||
|
|
6eabb9b2e4 | ||
|
|
d35524915c | ||
|
|
5ca48bc73d | ||
|
|
06954b7b0a | ||
|
|
1f558b1e06 | ||
|
|
a8dda428ce | ||
|
|
d1d8aa7c14 | ||
|
|
0392bf5724 | ||
|
|
16ddd536ab | ||
|
|
4b1fbcbd04 | ||
|
|
d83c35fd71 | ||
|
|
6c512dabdc | ||
|
|
3e2dccb544 | ||
|
|
735b776edc | ||
|
|
cdc6a6114c | ||
|
|
6d64c373ce | ||
|
|
b9e39cdfcc | ||
|
|
4e050267c7 | ||
|
|
ed19a92a2a | ||
|
|
d54a2b33fe | ||
|
|
4eca53890f | ||
|
|
e463781077 | ||
|
|
09942c08db | ||
|
|
f0d18beaf3 | ||
|
|
48438f49e7 | ||
|
|
6401901e5d | ||
|
|
76ab09a6a2 | ||
|
|
04902b0419 | ||
|
|
a9b52589ff | ||
|
|
d8363bdfcf | ||
|
|
559dab8b1b | ||
|
|
c4cf454cf0 | ||
|
|
96f34f8f56 | ||
|
|
4ae1774e1f | ||
|
|
ee6c8a6e20 | ||
|
|
562e7ba043 | ||
|
|
194f7cb4f0 | ||
|
|
f34f7579a2 | ||
|
|
62eef87208 | ||
|
|
34e85113d2 | ||
|
|
2d4e432239 | ||
|
|
fcc243886c | ||
|
|
43de885aad | ||
|
|
b6bd31a4aa | ||
|
|
dd0a2d4cff | ||
|
|
142340e0ff | ||
|
|
c49caead25 | ||
|
|
ac9259d6a4 | ||
|
|
70e30df6ce | ||
|
|
fb20d7311e | ||
|
|
243f1fc64b | ||
|
|
f094a9d5e5 | ||
|
|
2dc48c0b98 | ||
|
|
704c6a47e3 | ||
|
|
1a2beae38a | ||
|
|
9a542489a7 | ||
|
|
746efb4c56 | ||
|
|
32db7e176d | ||
|
|
8ce9098765 | ||
|
|
a7ace2dcdd | ||
|
|
51c18b57a2 | ||
|
|
cd91f858e6 | ||
|
|
834ff1be3c | ||
|
|
478ae025a3 | ||
|
|
5806196797 | ||
|
|
24e4e0946d | ||
|
|
aa75cc5bbe | ||
|
|
cb43dea319 | ||
|
|
f3843fc67a | ||
|
|
0e9fe9dc40 | ||
|
|
90ddd922ad | ||
|
|
1e1adafeec | ||
|
|
ecc9e9257e | ||
|
|
4fee8b34ad | ||
|
|
02464c19b8 | ||
|
|
62129bb91f | ||
|
|
3d8da61569 | ||
|
|
d7d296df8e | ||
|
|
305ed25896 | ||
|
|
8b6cc211e9 | ||
|
|
1ca95cda4a | ||
|
|
830a3fda97 | ||
|
|
829770e6eb | ||
|
|
0dd0305400 | ||
|
|
9c0d29dd45 | ||
|
|
212c8e8b63 | ||
|
|
b925f0948b | ||
|
|
a5ab428d34 | ||
|
|
334b5e7bfd | ||
|
|
f62002478c | ||
|
|
d566da0bb0 | ||
|
|
8a5364e82e | ||
|
|
54299df127 | ||
|
|
7734371936 | ||
|
|
3a7dbef16d | ||
|
|
70b2e7de65 | ||
|
|
d4246ece54 | ||
|
|
44ca63441b | ||
|
|
5b7bd02961 | ||
|
|
668dca9e96 | ||
|
|
50c04238c1 | ||
|
|
4ded8e9c50 | ||
|
|
40a2533500 | ||
|
|
42070eb269 | ||
|
|
e0afc47183 | ||
|
|
76f36617c3 | ||
|
|
084c0befc7 | ||
|
|
0ca3d77829 |
5
.gitattributes
vendored
5
.gitattributes
vendored
@@ -2,5 +2,10 @@
|
||||
*.gen.ts linguist-generated
|
||||
*_gen.ts linguist-generated
|
||||
*_gen.go linguist-generated
|
||||
*_gen.csv linguist-generated
|
||||
*_gen.json linguist-generated
|
||||
**/openapi_snapshots/*.json linguist-generated
|
||||
apps/**/pkg/apis/*_manifest.go linguist-generated
|
||||
public/openapi3.json linguist-generated
|
||||
public/api-merged.json linguist-generated
|
||||
public/api-enterprise-spec.json linguist-generated
|
||||
|
||||
9
.github/CODEOWNERS
vendored
9
.github/CODEOWNERS
vendored
@@ -41,12 +41,14 @@
|
||||
/docs/sources/ @irenerl24
|
||||
|
||||
/docs/sources/alerting/ @JohnnyK-Grafana
|
||||
/docs/sources/as-code/ @urbiz-grafana
|
||||
/docs/sources/developer-resources/ @urbiz-grafana
|
||||
/docs/sources/datasources/ @lwandz13
|
||||
/docs/sources/upgrade-guide/ @jtvdez
|
||||
/docs/sources/whatsnew/ @jtvdez
|
||||
|
||||
|
||||
/docs/sources/developers/plugins/ @grafana/plugins-platform-frontend @grafana/plugins-platform-backend
|
||||
/docs/sources/developer-resources/plugins/ @grafana/plugins-platform-frontend @grafana/plugins-platform-backend
|
||||
/docs/sources/visualizations/dashboards/ @imatwawana
|
||||
/docs/sources/visualizations/panels-visualizations/ @imatwawana
|
||||
|
||||
@@ -254,7 +256,6 @@
|
||||
/devenv/dev-dashboards/all-panels.json @grafana/dataviz-squad
|
||||
/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/partner-datasources
|
||||
/devenv/dev-dashboards/datasource-influxdb/ @grafana/partner-datasources
|
||||
@@ -550,6 +551,7 @@ i18next.config.ts @grafana/grafana-frontend-platform
|
||||
/packages/grafana-data/src/geo/ @grafana/dataviz-squad
|
||||
/packages/grafana-data/src/monaco/ @grafana/partner-datasources
|
||||
/packages/grafana-data/src/panel/ @grafana/dashboards-squad
|
||||
/packages/grafana-data/src/panel/suggestions/ @grafana/dataviz-squad
|
||||
/packages/grafana-data/src/query/ @grafana/grafana-datasources-core-services
|
||||
/packages/grafana-data/src/rbac/ @grafana/access-squad
|
||||
/packages/grafana-data/src/table/ @grafana/dataviz-squad
|
||||
@@ -558,6 +560,7 @@ i18next.config.ts @grafana/grafana-frontend-platform
|
||||
/packages/grafana-data/src/transformations/ @grafana/datapro
|
||||
/packages/grafana-data/src/types/ @grafana/grafana-frontend-platform
|
||||
/packages/grafana-data/src/types/scopes.ts @grafana/grafana-operator-experience-squad
|
||||
/packages/grafana-data/src/types/suggestions.ts @grafana/dataviz-squad
|
||||
/packages/grafana-data/src/utils/__snapshots__/ @grafanabot
|
||||
/packages/grafana-data/src/utils/anyToNumber.ts @grafana/grafana-frontend-platform
|
||||
/packages/grafana-data/src/utils/arrayUtils* @grafana/grafana-frontend-platform
|
||||
@@ -833,7 +836,6 @@ playwright.storybook.config.ts @grafana/grafana-frontend-platform
|
||||
/public/app/core/constants.ts @grafana/grafana-frontend-platform
|
||||
/public/app/core/context/ @grafana/grafana-frontend-platform
|
||||
/public/app/core/copy/appNotification.ts @grafana/grafana-search-navigate-organise
|
||||
/public/app/core/core.ts @grafana/grafana-frontend-platform
|
||||
/public/app/core/crash/ @grafana/observability-traces-and-profiling
|
||||
/public/app/core/history/ @grafana/observability-traces-and-profiling
|
||||
/public/app/core/hooks/useBusEvent.ts @grafana/grafana-frontend-platform
|
||||
@@ -942,6 +944,7 @@ 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/suggestions/ @grafana/dataviz-squad
|
||||
/public/app/features/playlist/ @grafana/dashboards-squad
|
||||
/public/app/features/plugins/ @grafana/plugins-platform-frontend
|
||||
/public/app/features/profile/ @grafana/grafana-frontend-platform
|
||||
|
||||
6
.github/workflows/pr-test-integration.yml
vendored
6
.github/workflows/pr-test-integration.yml
vendored
@@ -68,7 +68,7 @@ jobs:
|
||||
run: |
|
||||
set -euo pipefail
|
||||
readarray -t PACKAGES <<< "$(./scripts/ci/backend-tests/pkgs-with-tests-named.sh -b TestIntegration | ./scripts/ci/backend-tests/shard.sh -N"$SHARD" -d-)"
|
||||
go test -tags=sqlite -timeout=12m -run '^TestIntegration' "${PACKAGES[@]}"
|
||||
go test -tags=sqlite -timeout=8m -run '^TestIntegration' "${PACKAGES[@]}"
|
||||
|
||||
sqlite_nocgo:
|
||||
needs: detect-changes
|
||||
@@ -109,7 +109,7 @@ jobs:
|
||||
# Build regex pattern like: pkg1$|pkg2$|pkg3$
|
||||
SKIP_PATTERN=$(echo "$SKIP_PACKAGES" | sed '/^$/d' | sed 's|.*|&$|' | paste -sd '|' -)
|
||||
readarray -t PACKAGES <<< "$(./scripts/ci/backend-tests/pkgs-with-tests-named.sh -b TestIntegration | ./scripts/ci/backend-tests/shard.sh -N "$SHARD" -d - | grep -Ev "($SKIP_PATTERN)")"
|
||||
go test -tags=sqlite -timeout=12m -run '^TestIntegration' "${PACKAGES[@]}"
|
||||
go test -tags=sqlite -timeout=8m -run '^TestIntegration' "${PACKAGES[@]}"
|
||||
- name: Run profiled tests
|
||||
id: run-profiled-tests
|
||||
if: matrix.shard == 'profiled'
|
||||
@@ -135,7 +135,7 @@ jobs:
|
||||
pkg_name=$(basename "$full_pkg" | tr '/' '_' | tr '.' '_')
|
||||
echo "📦 Running $full_pkg"
|
||||
set +e
|
||||
go test -tags=sqlite -timeout=12m -run '^TestIntegration' \
|
||||
go test -tags=sqlite -timeout=8m -run '^TestIntegration' \
|
||||
-outputdir=profiles \
|
||||
-cpuprofile="cpu_${pkg_name}.prof" \
|
||||
-memprofile="mem_${pkg_name}.prof" \
|
||||
|
||||
11
.github/workflows/release-build.yml
vendored
11
.github/workflows/release-build.yml
vendored
@@ -320,13 +320,21 @@ jobs:
|
||||
repositories: '["grafana"]'
|
||||
permissions: '{"issues": "write", "pull_requests": "write", "contents": "read"}'
|
||||
- name: Find PR
|
||||
continue-on-error: true
|
||||
id: find-pr
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ steps.generate_token.outputs.token }}
|
||||
GRAFANA_COMMIT: ${{ needs.setup.outputs.grafana-commit }}
|
||||
run: echo "ISSUE_NUMBER=$(gh api "/repos/grafana/grafana/commits/${GRAFANA_COMMIT}/pulls" | jq -r '.[0].number')" >> "$GITHUB_ENV"
|
||||
REPO: ${{ github.repository }}
|
||||
run: |
|
||||
set -eo pipefail
|
||||
gh api "/repos/${REPO}/commits/${GRAFANA_COMMIT}/pulls" | jq -r '.[0].number' | tee issue_number.txt
|
||||
echo "ISSUE_NUMBER=$(cat issue_number.txt)" >> "$GITHUB_ENV"
|
||||
- name: Find Comment
|
||||
uses: peter-evans/find-comment@3eae4d37986fb5a8592848f6a574fdf654e61f9e # v3
|
||||
if: ${{ steps.find-pr.outcome == 'success' }}
|
||||
id: fc
|
||||
continue-on-error: true
|
||||
with:
|
||||
issue-number: ${{ env.ISSUE_NUMBER }}
|
||||
comment-author: 'grafana-delivery-bot[bot]'
|
||||
@@ -334,6 +342,7 @@ jobs:
|
||||
token: ${{ steps.generate_token.outputs.token }}
|
||||
- name: Create or update comment
|
||||
uses: peter-evans/create-or-update-comment@e8674b075228eee787fea43ef493e45ece1004c9 # v4
|
||||
if: ${{ steps.find-pr.outcome == 'success' }} # Run even if comment wasn't found
|
||||
with:
|
||||
token: ${{ steps.generate_token.outputs.token }}
|
||||
comment-id: ${{ steps.fc.outputs.comment-id }}
|
||||
|
||||
@@ -105,6 +105,8 @@ linters:
|
||||
- '**/pkg/tsdb/graphite/**/*'
|
||||
- '**/pkg/tsdb/mysql/*'
|
||||
- '**/pkg/tsdb/mysql/**/*'
|
||||
- '**/pkg/tsdb/opentsdb/*'
|
||||
- '**/pkg/tsdb/opentsdb/**/*'
|
||||
- '**/pkg/tsdb/parca/*'
|
||||
- '**/pkg/tsdb/parca/**/*'
|
||||
- '**/pkg/tsdb/tempo/*'
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -25,6 +25,6 @@ plugins:
|
||||
path: .yarn/plugins/@yarnpkg/plugin-licenses.cjs
|
||||
spec: "https://raw.githubusercontent.com/mhassan1/yarn-plugin-licenses/v0.15.0/bundles/@yarnpkg/plugin-licenses.js"
|
||||
|
||||
yarnPath: .yarn/releases/yarn-4.10.3.cjs
|
||||
yarnPath: .yarn/releases/yarn-4.11.0.cjs
|
||||
|
||||
enableScripts: false
|
||||
|
||||
@@ -152,28 +152,3 @@ Check [`security_config_step.go`](./pkg/app/checks/configchecks/security_config_
|
||||
## Testing
|
||||
|
||||
Create tests for your check and its steps to ensure they work as expected. Test both successful and failure scenarios.
|
||||
|
||||
## Running the Standalone Mode
|
||||
|
||||
To run the standalone mode, you can use the `make run` command. This will start the advisor app in standalone mode, which means it will not be running in a Kubernetes cluster.
|
||||
|
||||
```bash
|
||||
make etcd # Start etcd in a docker container
|
||||
make run # Start the advisor app in standalone mode
|
||||
```
|
||||
|
||||
This will start the advisor app on port 7445. You can then access the advisor app at `http://localhost:7445`.
|
||||
|
||||
To see some sample checks, you can run the following command:
|
||||
|
||||
```bash
|
||||
make create-checks
|
||||
```
|
||||
|
||||
Then you can see list in the URL: `http://localhost:7445/apis/advisor.grafana.app/v0alpha1/namespaces/stacks-1/checks`
|
||||
|
||||
To delete all checks, you can run the following command:
|
||||
|
||||
```bash
|
||||
make delete-checks
|
||||
```
|
||||
|
||||
@@ -8,15 +8,13 @@ require (
|
||||
github.com/google/go-github/v70 v70.0.0
|
||||
github.com/grafana/authlib/types v0.0.0-20250926065801-df98203cff37
|
||||
github.com/grafana/grafana v0.0.0-00010101000000-000000000000
|
||||
github.com/grafana/grafana-app-sdk v0.48.1
|
||||
github.com/grafana/grafana-app-sdk v0.48.2
|
||||
github.com/grafana/grafana-app-sdk/logging v0.48.1
|
||||
github.com/grafana/grafana-plugin-sdk-go v0.281.0
|
||||
github.com/grafana/grafana/pkg/apimachinery v0.0.0
|
||||
github.com/stretchr/testify v1.11.1
|
||||
k8s.io/apimachinery v0.34.1
|
||||
k8s.io/apiserver v0.34.1
|
||||
k8s.io/client-go v0.34.1
|
||||
k8s.io/component-base v0.34.1
|
||||
k8s.io/apimachinery v0.34.2
|
||||
k8s.io/apiserver v0.34.2
|
||||
k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912
|
||||
)
|
||||
|
||||
@@ -45,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.7.0 // indirect
|
||||
dario.cat/mergo v1.0.2 // indirect
|
||||
filippo.io/edwards25519 v1.1.0 // indirect
|
||||
@@ -58,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
|
||||
@@ -89,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 +100,6 @@ require (
|
||||
github.com/emicklei/go-restful/v3 v3.13.0 // 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
|
||||
@@ -148,7 +142,6 @@ 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
|
||||
@@ -168,7 +161,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.2 // indirect
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.1-0.20191002090509-6af20e3a5340 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 // indirect
|
||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||
github.com/hashicorp/go-hclog v1.6.3 // indirect
|
||||
@@ -183,7 +175,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 +247,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 +255,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.1.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0 // indirect
|
||||
@@ -287,22 +273,20 @@ require (
|
||||
go.opentelemetry.io/proto/otlp v1.7.1 // 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.0 // indirect
|
||||
go.yaml.in/yaml/v2 v2.4.3 // indirect
|
||||
go.yaml.in/yaml/v3 v3.0.4 // indirect
|
||||
golang.org/x/crypto v0.43.0 // indirect
|
||||
golang.org/x/crypto v0.44.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20251002181428-27f1f14c8bb9 // indirect
|
||||
golang.org/x/mod v0.29.0 // indirect
|
||||
golang.org/x/net v0.46.0 // indirect
|
||||
golang.org/x/mod v0.30.0 // indirect
|
||||
golang.org/x/net v0.47.0 // indirect
|
||||
golang.org/x/oauth2 v0.32.0 // indirect
|
||||
golang.org/x/sync v0.17.0 // indirect
|
||||
golang.org/x/sys v0.37.0 // indirect
|
||||
golang.org/x/telemetry v0.0.0-20251008203120-078029d740a8 // indirect
|
||||
golang.org/x/term v0.36.0 // indirect
|
||||
golang.org/x/text v0.30.0 // indirect
|
||||
golang.org/x/sync v0.18.0 // indirect
|
||||
golang.org/x/sys v0.38.0 // indirect
|
||||
golang.org/x/telemetry v0.0.0-20251111182119-bc8e575c7b54 // indirect
|
||||
golang.org/x/term v0.37.0 // indirect
|
||||
golang.org/x/text v0.31.0 // indirect
|
||||
golang.org/x/time v0.14.0 // indirect
|
||||
golang.org/x/tools v0.38.0 // indirect
|
||||
golang.org/x/tools v0.39.0 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect
|
||||
gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect
|
||||
gonum.org/v1/gonum v0.16.0 // indirect
|
||||
@@ -311,25 +295,23 @@ require (
|
||||
google.golang.org/grpc v1.76.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.1 // indirect
|
||||
k8s.io/apiextensions-apiserver v0.34.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.1 // 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.39.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.0 // indirect
|
||||
|
||||
@@ -131,7 +131,6 @@ github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAE
|
||||
github.com/ProtonMail/go-crypto v1.1.6 h1:ZcV+Ropw6Qn0AX9brlQLAUXfqLBc7Bl+f/DmNxpLfdw=
|
||||
github.com/ProtonMail/go-crypto v1.1.6/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE=
|
||||
github.com/RoaringBitmap/roaring v1.9.3 h1:t4EbC5qQwnisr5PrP9nt0IRhRTb9gMUgQF4t4S2OByM=
|
||||
github.com/RoaringBitmap/roaring v1.9.3/go.mod h1:6AXUsoIEzDTFFQCe1RbGA6uFONMhvejWj5rqITANK90=
|
||||
github.com/RoaringBitmap/roaring/v2 v2.4.5 h1:uGrrMreGjvAtTBobc0g5IrW1D5ldxDQYe2JW2gggRdg=
|
||||
github.com/RoaringBitmap/roaring/v2 v2.4.5/go.mod h1:FiJcsfkGje/nZBZgCu0ZxCPOKD/hVXDS2dXi7/eUFE0=
|
||||
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
|
||||
@@ -211,8 +210,6 @@ github.com/aws/aws-sdk-go-v2/service/sts v1.38.5 h1:+LVB0xBqEgjQoqr9bGZbRzvg212B
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.38.5/go.mod h1:xoaxeqnnUaZjPjaICgIy5B+MHCSb/ZSOn4MvkFNOUA0=
|
||||
github.com/aws/smithy-go v1.23.1 h1:sLvcH6dfAFwGkHLZ7dGiYF7aK6mg4CgKA/iDKjLDt9M=
|
||||
github.com/aws/smithy-go v1.23.1/go.mod h1:LEj2LM3rBRQJxPZTB4KuzZkaZYnZPnvgIhb4pu07mx0=
|
||||
github.com/axiomhq/hyperloglog v0.0.0-20240507144631-af9851f82b27 h1:60m4tnanN1ctzIu4V3bfCNJ39BiOPSm1gHFlFjTkRE0=
|
||||
github.com/axiomhq/hyperloglog v0.0.0-20240507144631-af9851f82b27/go.mod h1:k08r+Yj1PRAmuayFiRK6MYuR5Ve4IuZtTfxErMIh0+c=
|
||||
github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk=
|
||||
github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg=
|
||||
github.com/barkimedes/go-deepcopy v0.0.0-20220514131651-17c30cfc62df h1:GSoSVRLoBaFpOOds6QyY1L8AX7uoY+Ln3BHc22W40X0=
|
||||
@@ -269,14 +266,6 @@ github.com/blevesearch/zapx/v16 v16.2.2 h1:MifKJVRTEhMTgSlle2bDRTb39BGc9jXFRLPZc
|
||||
github.com/blevesearch/zapx/v16 v16.2.2/go.mod h1:B9Pk4G1CqtErgQV9DyCSA9Lb7WZe4olYfGw7fVDZ4sk=
|
||||
github.com/bluele/gcache v0.0.2 h1:WcbfdXICg7G/DGBh1PFfcirkWOQV+v077yF1pSy3DGw=
|
||||
github.com/bluele/gcache v0.0.2/go.mod h1:m15KV+ECjptwSPxKhOhQoAFQVtUFjTVkc3H8o0t/fp0=
|
||||
github.com/blugelabs/bluge v0.2.2 h1:gat8CqE6P6tOgeX30XGLOVNTC26cpM2RWVcreXWtYcM=
|
||||
github.com/blugelabs/bluge v0.2.2/go.mod h1:am1LU9jS8dZgWkRzkGLQN3757EgMs3upWrU2fdN9foE=
|
||||
github.com/blugelabs/bluge_segment_api v0.2.0 h1:cCX1Y2y8v0LZ7+EEJ6gH7dW6TtVTW4RhG0vp3R+N2Lo=
|
||||
github.com/blugelabs/bluge_segment_api v0.2.0/go.mod h1:95XA+ZXfRj/IXADm7gZ+iTcWOJPg5jQTY1EReIzl3LA=
|
||||
github.com/blugelabs/ice v1.0.0 h1:um7wf9e6jbkTVCrOyQq3tKK43fBMOvLUYxbj3Qtc4eo=
|
||||
github.com/blugelabs/ice v1.0.0/go.mod h1:gNfFPk5zM+yxJROhthxhVQYjpBO9amuxWXJQ2Lo+IbQ=
|
||||
github.com/blugelabs/ice/v2 v2.0.1 h1:mzHbntLjk2v7eDRgoXCgzOsPKN1Tenu9Svo6l9cTLS4=
|
||||
github.com/blugelabs/ice/v2 v2.0.1/go.mod h1:QxAWSPNwZwsIqS25c3lbIPFQrVvT1sphf5x5DfMLH5M=
|
||||
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
|
||||
github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874 h1:N7oVaKyGp8bttX0bfZGmcGkjz7DLQXhAn3DNd3T0ous=
|
||||
github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874/go.mod h1:r5xuitiExdLAJ09PR7vBVENGvp4ZuTBeWTGtxuX3K+c=
|
||||
@@ -290,8 +279,6 @@ github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMU
|
||||
github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
|
||||
github.com/bwmarrin/snowflake v0.3.0 h1:xm67bEhkKh6ij1790JB83OujPR5CzNe8QuQqAgISZN0=
|
||||
github.com/bwmarrin/snowflake v0.3.0/go.mod h1:NdZxfVWX+oR6y2K0o6qAYv6gIOP9rjG0/E9WsDpxqwE=
|
||||
github.com/caio/go-tdigest v3.1.0+incompatible h1:uoVMJ3Q5lXmVLCCqaMGHLBWnbGoN6Lpu7OAUPR60cds=
|
||||
github.com/caio/go-tdigest v3.1.0+incompatible/go.mod h1:sHQM/ubZStBUmF1WbB8FAm8q9GjDajLC5T7ydxE3JHI=
|
||||
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
|
||||
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
|
||||
github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM=
|
||||
@@ -334,7 +321,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=
|
||||
@@ -357,8 +343,6 @@ github.com/dgraph-io/badger/v4 v4.7.0 h1:Q+J8HApYAY7UMpL8d9owqiB+odzEc0zn/aqOD9j
|
||||
github.com/dgraph-io/badger/v4 v4.7.0/go.mod h1:He7TzG3YBy3j4f5baj5B7Zl2XyfNe5bl4Udl0aPemVA=
|
||||
github.com/dgraph-io/ristretto/v2 v2.2.0 h1:bkY3XzJcXoMuELV8F+vS8kzNgicwQFAaGINAEJdWGOM=
|
||||
github.com/dgraph-io/ristretto/v2 v2.2.0/go.mod h1:RZrm63UmcBAaYWC1DotLYBmTvgkrs0+XhBd7Npn7/zI=
|
||||
github.com/dgryski/go-metro v0.0.0-20180109044635-280f6062b5bc h1:8WFBn63wegobsYAX0YjD+8suexZDga5CctH4CCTx2+8=
|
||||
github.com/dgryski/go-metro v0.0.0-20180109044635-280f6062b5bc/go.mod h1:c9O8+fpSOX1DM8cPNSkX/qsBWdkD4yd2dpciOWQjpBw=
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
|
||||
github.com/dhui/dktest v0.3.0/go.mod h1:cyzIUfGsBEbZ6BT7tnXqAShHSXCZhSNmFl70sZ7c1yc=
|
||||
@@ -461,8 +445,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=
|
||||
@@ -665,8 +647,6 @@ 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-20251009192429-9427c24835ae h1:NLPwY3tIP0lg0g9wTRiMcypm6VRXW6W+MOLBsq8JSVA=
|
||||
github.com/grafana/alerting v0.0.0-20251009192429-9427c24835ae/go.mod h1:VGjS5gDwWEADPP6pF/drqLxEImgeuHlEW5u8E5EfIrM=
|
||||
github.com/grafana/authlib v0.0.0-20250930082137-a40e2c2b094f h1:Cbm6OKkOcJ+7CSZsGsEJzktC/SIa5bxVeYKQLuYK86o=
|
||||
@@ -679,8 +659,8 @@ github.com/grafana/dataplane/sdata v0.0.9 h1:AGL1LZnCUG4MnQtnWpBPbQ8ZpptaZs14w6k
|
||||
github.com/grafana/dataplane/sdata v0.0.9/go.mod h1:Jvs5ddpGmn6vcxT7tCTWAZ1mgi4sbcdFt9utQx5uMAU=
|
||||
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.1 h1:bKJadWH18WCpJ+Zk8AezRFXCcZgGredRv+fRS+8zkek=
|
||||
github.com/grafana/grafana-app-sdk v0.48.1/go.mod h1:5LljCz+wvmGfkQ8ZKTOfserhtXNEF0cSFthoWShvN6c=
|
||||
github.com/grafana/grafana-app-sdk v0.48.2 h1:CQQDhwo1fWaXQVKvxxOcK6azbuY3E2TgJHNAZlYYn7U=
|
||||
github.com/grafana/grafana-app-sdk v0.48.2/go.mod h1:LDOvQ7OOyHLcXdSa0InATCa5OMoYAd6E1+rGLrMgHuk=
|
||||
github.com/grafana/grafana-app-sdk/logging v0.48.1 h1:veM0X5LAPyN3KsDLglWjIofndbGuf7MqnrDuDN+F/Ng=
|
||||
github.com/grafana/grafana-app-sdk/logging v0.48.1/go.mod h1:Gh/nBWnspK3oDNWtiM5qUF/fardHzOIEez+SPI3JeHA=
|
||||
github.com/grafana/grafana-aws-sdk v1.3.0 h1:/bfJzP93rCel1GbWoRSq0oUo424MZXt8jAp2BK9w8tM=
|
||||
@@ -810,8 +790,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=
|
||||
@@ -1044,7 +1022,6 @@ github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSg
|
||||
github.com/pressly/goose/v3 v3.25.0 h1:6WeYhMWGRCzpyd89SpODFnCBCKz41KrVbRT58nVjGng=
|
||||
github.com/pressly/goose/v3 v3.25.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=
|
||||
@@ -1062,7 +1039,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=
|
||||
@@ -1077,7 +1053,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=
|
||||
@@ -1104,7 +1079,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=
|
||||
@@ -1127,8 +1101,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=
|
||||
@@ -1142,7 +1114,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=
|
||||
@@ -1168,7 +1139,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=
|
||||
@@ -1185,8 +1155,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=
|
||||
@@ -1204,8 +1172,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=
|
||||
@@ -1230,12 +1196,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=
|
||||
@@ -1342,8 +1302,8 @@ golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm
|
||||
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04=
|
||||
golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0=
|
||||
golang.org/x/crypto v0.44.0 h1:A97SsFvM3AIwEEmTBiaxPPTYpDC47w720rdiiUvgoAU=
|
||||
golang.org/x/crypto v0.44.0/go.mod h1:013i+Nw79BMiQiMsOPcVCB5ZIJbYkerPrGnOa00tvmc=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
@@ -1381,14 +1341,13 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA=
|
||||
golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w=
|
||||
golang.org/x/mod v0.30.0 h1:fDEXFVZ/fmCKProc/yAXXUijritrDzahmwwefnjoPFk=
|
||||
golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
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=
|
||||
@@ -1437,8 +1396,8 @@ golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su
|
||||
golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4=
|
||||
golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210=
|
||||
golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
|
||||
golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
@@ -1475,8 +1434,8 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ
|
||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220513210516-0976fa681c29/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
|
||||
golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||
golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I=
|
||||
golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
@@ -1565,14 +1524,14 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ=
|
||||
golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/telemetry v0.0.0-20251008203120-078029d740a8 h1:LvzTn0GQhWuvKH/kVRS3R3bVAsdQWI7hvfLHGgh9+lU=
|
||||
golang.org/x/telemetry v0.0.0-20251008203120-078029d740a8/go.mod h1:Pi4ztBfryZoJEkyFTI5/Ocsu2jXyDr6iSdgJiYE/uwE=
|
||||
golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
|
||||
golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/telemetry v0.0.0-20251111182119-bc8e575c7b54 h1:E2/AqCUMZGgd73TQkxUMcMla25GB9i/5HOdLr+uH7Vo=
|
||||
golang.org/x/telemetry v0.0.0-20251111182119-bc8e575c7b54/go.mod h1:hKdjCMrbv9skySur+Nek8Hd0uJ0GuxJIoIX2payrIdQ=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.36.0 h1:zMPR+aF8gfksFprF/Nc/rd1wRS1EI6nDBGyWAvDzx2Q=
|
||||
golang.org/x/term v0.36.0/go.mod h1:Qu394IJq6V6dCBRgwqshf3mPF85AqzYEzofzRdZkWss=
|
||||
golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU=
|
||||
golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
@@ -1582,8 +1541,8 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k=
|
||||
golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM=
|
||||
golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=
|
||||
golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
@@ -1647,8 +1606,8 @@ golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ=
|
||||
golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs=
|
||||
golang.org/x/tools v0.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ=
|
||||
golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ=
|
||||
golang.org/x/tools/godoc v0.1.0-deprecated h1:o+aZ1BOj6Hsx/GBdJO/s815sqftjSnrZZwyYTHODvtk=
|
||||
golang.org/x/tools/godoc v0.1.0-deprecated/go.mod h1:qM63CriJ961IHWmnWa9CjZnBndniPt4a3CK0PVB9bIg=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
@@ -1800,7 +1759,6 @@ google.golang.org/genproto/googleapis/api v0.0.0-20250908214217-97024824d090/go.
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20251002232023-7c0ddcbb5797 h1:CirRxTOwnRWVLKzDNrs0CXAaVozJoR4G9xvdRecrdpk=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20251002232023-7c0ddcbb5797/go.mod h1:HSkG/KdJWusxU1F6CNrwNDjBMgisKxGnc5dAZfT0mjQ=
|
||||
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=
|
||||
@@ -1897,22 +1855,22 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh
|
||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
k8s.io/api v0.34.1 h1:jC+153630BMdlFukegoEL8E/yT7aLyQkIVuwhmwDgJM=
|
||||
k8s.io/api v0.34.1/go.mod h1:SB80FxFtXn5/gwzCoN6QCtPD7Vbu5w2n1S0J5gFfTYk=
|
||||
k8s.io/apiextensions-apiserver v0.34.1 h1:NNPBva8FNAPt1iSVwIE0FsdrVriRXMsaWFMqJbII2CI=
|
||||
k8s.io/apiextensions-apiserver v0.34.1/go.mod h1:hP9Rld3zF5Ay2Of3BeEpLAToP+l4s5UlxiHfqRaRcMc=
|
||||
k8s.io/apimachinery v0.34.1 h1:dTlxFls/eikpJxmAC7MVE8oOeP1zryV7iRyIjB0gky4=
|
||||
k8s.io/apimachinery v0.34.1/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw=
|
||||
k8s.io/apiserver v0.34.1 h1:U3JBGdgANK3dfFcyknWde1G6X1F4bg7PXuvlqt8lITA=
|
||||
k8s.io/apiserver v0.34.1/go.mod h1:eOOc9nrVqlBI1AFCvVzsob0OxtPZUCPiUJL45JOTBG0=
|
||||
k8s.io/client-go v0.34.1 h1:ZUPJKgXsnKwVwmKKdPfw4tB58+7/Ik3CrjOEhsiZ7mY=
|
||||
k8s.io/client-go v0.34.1/go.mod h1:kA8v0FP+tk6sZA0yKLRG67LWjqufAoSHA2xVGKw9Of8=
|
||||
k8s.io/component-base v0.34.1 h1:v7xFgG+ONhytZNFpIz5/kecwD+sUhVE6HU7qQUiRM4A=
|
||||
k8s.io/component-base v0.34.1/go.mod h1:mknCpLlTSKHzAQJJnnHVKqjxR7gBeHRv0rPXA7gdtQ0=
|
||||
k8s.io/api v0.34.2 h1:fsSUNZhV+bnL6Aqrp6O7lMTy6o5x2C4XLjnh//8SLYY=
|
||||
k8s.io/api v0.34.2/go.mod h1:MMBPaWlED2a8w4RSeanD76f7opUoypY8TFYkSM+3XHw=
|
||||
k8s.io/apiextensions-apiserver v0.34.2 h1:WStKftnGeoKP4AZRz/BaAAEJvYp4mlZGN0UCv+uvsqo=
|
||||
k8s.io/apiextensions-apiserver v0.34.2/go.mod h1:398CJrsgXF1wytdaanynDpJ67zG4Xq7yj91GrmYN2SE=
|
||||
k8s.io/apimachinery v0.34.2 h1:zQ12Uk3eMHPxrsbUJgNF8bTauTVR2WgqJsTmwTE/NW4=
|
||||
k8s.io/apimachinery v0.34.2/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw=
|
||||
k8s.io/apiserver v0.34.2 h1:2/yu8suwkmES7IzwlehAovo8dDE07cFRC7KMDb1+MAE=
|
||||
k8s.io/apiserver v0.34.2/go.mod h1:gqJQy2yDOB50R3JUReHSFr+cwJnL8G1dzTA0YLEqAPI=
|
||||
k8s.io/client-go v0.34.2 h1:Co6XiknN+uUZqiddlfAjT68184/37PS4QAzYvQvDR8M=
|
||||
k8s.io/client-go v0.34.2/go.mod h1:2VYDl1XXJsdcAxw7BenFslRQX28Dxz91U9MWKjX97fE=
|
||||
k8s.io/component-base v0.34.2 h1:HQRqK9x2sSAsd8+R4xxRirlTjowsg6fWCPwWYeSvogQ=
|
||||
k8s.io/component-base v0.34.2/go.mod h1:9xw2FHJavUHBFpiGkZoKuYZ5pdtLKe97DEByaA+hHbM=
|
||||
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
|
||||
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
|
||||
k8s.io/kms v0.34.1 h1:iCFOvewDPzWM9fMTfyIPO+4MeuZ0tcZbugxLNSHFG4w=
|
||||
k8s.io/kms v0.34.1/go.mod h1:s1CFkLG7w9eaTYvctOxosx88fl4spqmixnNpys0JAtM=
|
||||
k8s.io/kms v0.34.2 h1:91rj4MDZLyIT9KxG8J5/CcMH666Z88CF/xJQeuPfJc8=
|
||||
k8s.io/kms v0.34.2/go.mod h1:s1CFkLG7w9eaTYvctOxosx88fl4spqmixnNpys0JAtM=
|
||||
k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 h1:Y3gxNAuB0OBLImH611+UDZcmKS3g6CthxToOb37KgwE=
|
||||
k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912/go.mod h1:kdmbQkyfwUagLfXIad1y2TdrjPFWp2Q89B3qkRwf/pQ=
|
||||
k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 h1:hwvWFiBzdWw1FhfY1FooPn3kzWuJ8tmbZBHi4zVsl1Y=
|
||||
|
||||
@@ -20,6 +20,10 @@ import (
|
||||
)
|
||||
|
||||
func New(cfg app.Config) (app.App, error) {
|
||||
// Needed until https://github.com/grafana/grafana-app-sdk/pull/1077
|
||||
if cfg.KubeConfig.APIPath == "" {
|
||||
cfg.KubeConfig.APIPath = "apis"
|
||||
}
|
||||
// Read config
|
||||
specificConfig, ok := cfg.SpecificConfig.(checkregistry.AdvisorAppConfig)
|
||||
if !ok {
|
||||
|
||||
@@ -3,6 +3,7 @@ package app
|
||||
import (
|
||||
"context"
|
||||
|
||||
claims "github.com/grafana/authlib/types"
|
||||
"github.com/grafana/grafana/pkg/apimachinery/identity"
|
||||
"k8s.io/apiserver/pkg/authorization/authorizer"
|
||||
)
|
||||
@@ -15,7 +16,22 @@ func GetAuthorizer() authorizer.Authorizer {
|
||||
return authorizer.DecisionNoOpinion, "", nil
|
||||
}
|
||||
|
||||
// require a user
|
||||
// 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
|
||||
|
||||
@@ -4,6 +4,7 @@ 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"
|
||||
@@ -79,4 +80,12 @@ 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
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
package mockchecks
|
||||
|
||||
import (
|
||||
"github.com/grafana/grafana/apps/advisor/pkg/app/checkregistry/mockchecks/mocksvcs"
|
||||
"github.com/grafana/grafana/apps/advisor/pkg/app/checks"
|
||||
"github.com/grafana/grafana/apps/advisor/pkg/app/checks/datasourcecheck"
|
||||
"github.com/grafana/grafana/apps/advisor/pkg/app/checks/plugincheck"
|
||||
"github.com/grafana/grafana/pkg/plugins"
|
||||
"github.com/grafana/grafana/pkg/plugins/repo"
|
||||
"github.com/grafana/grafana/pkg/services/datasources"
|
||||
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginchecker"
|
||||
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginstore"
|
||||
)
|
||||
|
||||
// mockchecks.CheckRegistry is a mock implementation of the checkregistry.CheckService interface
|
||||
// TODO: Add mocked checks here
|
||||
type CheckRegistry struct {
|
||||
datasourceSvc datasources.DataSourceService
|
||||
pluginStore pluginstore.Store
|
||||
pluginClient plugins.Client
|
||||
pluginRepo repo.Service
|
||||
GrafanaVersion string
|
||||
pluginContextProvider datasourcecheck.PluginContextProvider
|
||||
updateChecker pluginchecker.PluginUpdateChecker
|
||||
pluginErrorResolver plugins.ErrorResolver
|
||||
}
|
||||
|
||||
func (m *CheckRegistry) Checks() []checks.Check {
|
||||
return []checks.Check{
|
||||
datasourcecheck.New(
|
||||
m.datasourceSvc,
|
||||
m.pluginStore,
|
||||
m.pluginContextProvider,
|
||||
m.pluginClient,
|
||||
m.pluginRepo,
|
||||
m.GrafanaVersion,
|
||||
),
|
||||
plugincheck.New(
|
||||
m.pluginStore,
|
||||
m.pluginRepo,
|
||||
m.updateChecker,
|
||||
m.pluginErrorResolver,
|
||||
m.GrafanaVersion,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
func New() *CheckRegistry {
|
||||
return &CheckRegistry{
|
||||
datasourceSvc: &mocksvcs.DatasourceSvc{},
|
||||
pluginStore: &mocksvcs.PluginStore{},
|
||||
pluginClient: &mocksvcs.PluginClient{},
|
||||
pluginRepo: &mocksvcs.PluginRepo{},
|
||||
pluginContextProvider: &mocksvcs.PluginContextProvider{},
|
||||
updateChecker: &mocksvcs.UpdateChecker{},
|
||||
pluginErrorResolver: &mocksvcs.PluginErrorResolver{},
|
||||
GrafanaVersion: "1.0.0",
|
||||
}
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
package mocksvcs
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/grafana/grafana/pkg/services/datasources"
|
||||
)
|
||||
|
||||
var dss = map[string]*datasources.DataSource{
|
||||
"prometheus-uid": {
|
||||
ID: 1,
|
||||
UID: "prometheus-uid",
|
||||
Name: "Prometheus",
|
||||
Type: "prometheus",
|
||||
},
|
||||
"mysql-uid": {
|
||||
ID: 2,
|
||||
UID: "mysql-uid",
|
||||
Name: "MySQL",
|
||||
Type: "mysql",
|
||||
},
|
||||
"unknown-uid": {
|
||||
ID: 3,
|
||||
UID: "unknown-uid",
|
||||
Name: "Unknown",
|
||||
Type: "unknown",
|
||||
},
|
||||
}
|
||||
|
||||
type DatasourceSvc struct {
|
||||
datasources.DataSourceService
|
||||
}
|
||||
|
||||
func (m *DatasourceSvc) GetDataSources(ctx context.Context, query *datasources.GetDataSourcesQuery) ([]*datasources.DataSource, error) {
|
||||
sources := make([]*datasources.DataSource, 0, len(dss))
|
||||
for _, ds := range dss {
|
||||
sources = append(sources, ds)
|
||||
}
|
||||
return sources, nil
|
||||
}
|
||||
|
||||
func (m *DatasourceSvc) GetDataSource(ctx context.Context, query *datasources.GetDataSourceQuery) (*datasources.DataSource, error) {
|
||||
return dss[query.UID], nil
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
package mocksvcs
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||
"github.com/grafana/grafana/pkg/plugins"
|
||||
)
|
||||
|
||||
type PluginClient struct {
|
||||
plugins.Client
|
||||
}
|
||||
|
||||
func (m *PluginClient) CheckHealth(ctx context.Context, req *backend.CheckHealthRequest) (*backend.CheckHealthResult, error) {
|
||||
return &backend.CheckHealthResult{
|
||||
Status: backend.HealthStatusOk,
|
||||
Message: "Plugin is healthy",
|
||||
}, nil
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
package mocksvcs
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||
"github.com/grafana/grafana/pkg/apimachinery/identity"
|
||||
"github.com/grafana/grafana/pkg/services/datasources"
|
||||
)
|
||||
|
||||
type PluginContextProvider struct {
|
||||
}
|
||||
|
||||
// ACTUALLY USED by datasourcecheck
|
||||
func (m *PluginContextProvider) GetWithDataSource(ctx context.Context, pluginID string, user identity.Requester, ds *datasources.DataSource) (backend.PluginContext, error) {
|
||||
// Create a plugin context with sample data based on the datasource
|
||||
pluginContext := backend.PluginContext{
|
||||
PluginID: pluginID,
|
||||
PluginVersion: "1.0.0",
|
||||
OrgID: 1,
|
||||
DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{
|
||||
ID: ds.ID,
|
||||
UID: ds.UID,
|
||||
Name: ds.Name,
|
||||
URL: ds.URL,
|
||||
JSONData: []byte(`{
|
||||
"httpMethod": "GET",
|
||||
"timeout": "30s",
|
||||
"keepCookies": []
|
||||
}`),
|
||||
DecryptedSecureJSONData: map[string]string{
|
||||
"password": "sample-password",
|
||||
"apiKey": "sample-api-key",
|
||||
},
|
||||
},
|
||||
GrafanaConfig: backend.NewGrafanaCfg(map[string]string{
|
||||
"app_url": "http://localhost:3000",
|
||||
"default_timezone": "UTC",
|
||||
}),
|
||||
}
|
||||
|
||||
// Add user context if provided
|
||||
if user != nil && !user.IsNil() {
|
||||
pluginContext.User = &backend.User{
|
||||
Login: user.GetLogin(),
|
||||
Name: user.GetName(),
|
||||
Email: user.GetEmail(),
|
||||
Role: string(user.GetOrgRole()),
|
||||
}
|
||||
}
|
||||
|
||||
return pluginContext, nil
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
package mocksvcs
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/grafana/grafana/pkg/plugins"
|
||||
)
|
||||
|
||||
type PluginErrorResolver struct {
|
||||
}
|
||||
|
||||
// Assume no plugin with errors
|
||||
func (m *PluginErrorResolver) PluginErrors(ctx context.Context) []*plugins.Error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *PluginErrorResolver) PluginError(ctx context.Context, pluginID string) *plugins.Error {
|
||||
return nil
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
package mocksvcs
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/grafana/grafana/pkg/plugins/repo"
|
||||
)
|
||||
|
||||
type PluginRepo struct {
|
||||
repo.Service
|
||||
}
|
||||
|
||||
func (m *PluginRepo) GetPluginsInfo(ctx context.Context, options repo.GetPluginsInfoOptions, compatOpts repo.CompatOpts) ([]repo.PluginInfo, error) {
|
||||
return []repo.PluginInfo{
|
||||
{
|
||||
ID: 1,
|
||||
Slug: "grafana-piechart-panel",
|
||||
Version: "1.6.0",
|
||||
},
|
||||
{
|
||||
ID: 2,
|
||||
Slug: "prometheus",
|
||||
Version: "10.0.0",
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
@@ -1,114 +0,0 @@
|
||||
package mocksvcs
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/grafana/grafana/pkg/plugins"
|
||||
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginstore"
|
||||
)
|
||||
|
||||
type PluginStore struct {
|
||||
}
|
||||
|
||||
var ps = map[string]pluginstore.Plugin{
|
||||
"prometheus": {
|
||||
JSONData: plugins.JSONData{
|
||||
ID: "prometheus",
|
||||
Type: plugins.TypeDataSource,
|
||||
Name: "Prometheus",
|
||||
Info: plugins.Info{
|
||||
Author: plugins.InfoLink{
|
||||
Name: "Grafana Labs",
|
||||
},
|
||||
Version: "10.0.0",
|
||||
},
|
||||
Category: "Time series databases",
|
||||
State: plugins.ReleaseStateAlpha,
|
||||
Backend: true,
|
||||
Metrics: true,
|
||||
Logs: true,
|
||||
Alerting: true,
|
||||
Explore: true,
|
||||
},
|
||||
Class: plugins.ClassCore,
|
||||
Signature: plugins.SignatureStatusInternal,
|
||||
SignatureType: plugins.SignatureTypeGrafana,
|
||||
SignatureOrg: "grafana.com",
|
||||
},
|
||||
"test-datasource": {
|
||||
JSONData: plugins.JSONData{
|
||||
ID: "grafana-piechart-panel",
|
||||
Type: plugins.TypePanel,
|
||||
Name: "Pie Chart",
|
||||
Info: plugins.Info{
|
||||
Author: plugins.InfoLink{
|
||||
Name: "Grafana Labs",
|
||||
},
|
||||
Version: "1.6.0",
|
||||
},
|
||||
Category: "Visualization",
|
||||
State: plugins.ReleaseStateAlpha,
|
||||
},
|
||||
Class: plugins.ClassCore,
|
||||
Signature: plugins.SignatureStatusInternal,
|
||||
SignatureType: plugins.SignatureTypeGrafana,
|
||||
SignatureOrg: "grafana.com",
|
||||
},
|
||||
"grafana-piechart-panel": {
|
||||
JSONData: plugins.JSONData{
|
||||
ID: "prometheus",
|
||||
Type: plugins.TypeDataSource,
|
||||
Name: "Prometheus",
|
||||
Info: plugins.Info{
|
||||
Author: plugins.InfoLink{
|
||||
Name: "Grafana Labs",
|
||||
},
|
||||
Version: "10.0.0",
|
||||
},
|
||||
Category: "Time series databases",
|
||||
State: plugins.ReleaseStateAlpha,
|
||||
Backend: true,
|
||||
Metrics: true,
|
||||
Logs: true,
|
||||
Alerting: true,
|
||||
Explore: true,
|
||||
},
|
||||
Class: plugins.ClassCore,
|
||||
Signature: plugins.SignatureStatusInternal,
|
||||
SignatureType: plugins.SignatureTypeGrafana,
|
||||
SignatureOrg: "grafana.com",
|
||||
},
|
||||
"test-app": {
|
||||
JSONData: plugins.JSONData{
|
||||
ID: "test-app",
|
||||
Type: plugins.TypeApp,
|
||||
Name: "Test App",
|
||||
Info: plugins.Info{
|
||||
Author: plugins.InfoLink{
|
||||
Name: "Test Author",
|
||||
},
|
||||
Version: "2.0.0",
|
||||
},
|
||||
Category: "Application",
|
||||
State: plugins.ReleaseStateAlpha,
|
||||
AutoEnabled: true,
|
||||
},
|
||||
Class: plugins.ClassExternal,
|
||||
Signature: plugins.SignatureStatusValid,
|
||||
SignatureType: plugins.SignatureTypeCommercial,
|
||||
SignatureOrg: "test.com",
|
||||
},
|
||||
}
|
||||
|
||||
func (s *PluginStore) Plugin(ctx context.Context, pluginID string) (pluginstore.Plugin, bool) {
|
||||
p, ok := ps[pluginID]
|
||||
return p, ok
|
||||
}
|
||||
|
||||
func (s *PluginStore) Plugins(ctx context.Context, pluginTypes ...plugins.Type) []pluginstore.Plugin {
|
||||
plugins := make([]pluginstore.Plugin, 0, len(ps))
|
||||
for _, p := range ps {
|
||||
plugins = append(plugins, p)
|
||||
}
|
||||
return plugins
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
package mocksvcs
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginstore"
|
||||
)
|
||||
|
||||
type UpdateChecker struct {
|
||||
}
|
||||
|
||||
func (m *UpdateChecker) IsUpdatable(ctx context.Context, plugin pluginstore.Plugin) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (m *UpdateChecker) CanUpdate(pluginId string, currentVersion string, targetVersion string, onlyMinor bool) bool {
|
||||
return true
|
||||
}
|
||||
@@ -86,6 +86,11 @@ func New(cfg app.Config, log logging.Logger) (app.Runnable, error) {
|
||||
|
||||
func (r *Runner) Run(ctx context.Context) error {
|
||||
logger := r.log.WithContext(ctx)
|
||||
if r.stackID == "" && r.orgService == nil {
|
||||
logger.Debug("Check scheduler disabled")
|
||||
return nil
|
||||
}
|
||||
|
||||
// We still need the context to eventually be cancelled to exit this function
|
||||
// but we don't want the requests to fail because of it
|
||||
ctxWithoutCancel := context.WithoutCancel(ctx)
|
||||
|
||||
@@ -64,6 +64,11 @@ func New(cfg app.Config, log logging.Logger) (app.Runnable, error) {
|
||||
|
||||
func (r *Runner) Run(ctx context.Context) error {
|
||||
logger := r.log.WithContext(ctx)
|
||||
// If stackID is empty and OrgService is nil, do nothing (on-demand registration only)
|
||||
if r.stackID == "" && r.orgService == nil {
|
||||
logger.Debug("Auto-registration of checktypes disabled")
|
||||
return nil
|
||||
}
|
||||
|
||||
// Determine namespaces based on StackID or OrgID
|
||||
namespaces, err := checks.GetNamespaces(ctx, r.stackID, r.orgService)
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"log/slog"
|
||||
"os"
|
||||
|
||||
"k8s.io/apiserver/pkg/admission"
|
||||
genericapiserver "k8s.io/apiserver/pkg/server"
|
||||
"k8s.io/client-go/rest"
|
||||
"k8s.io/component-base/cli"
|
||||
|
||||
"github.com/grafana/grafana-app-sdk/app"
|
||||
"github.com/grafana/grafana-app-sdk/k8s/apiserver"
|
||||
"github.com/grafana/grafana-app-sdk/k8s/apiserver/cmd/server"
|
||||
"github.com/grafana/grafana-app-sdk/logging"
|
||||
"github.com/grafana/grafana-app-sdk/simple"
|
||||
"github.com/grafana/grafana/apps/advisor/pkg/apis"
|
||||
advisorapp "github.com/grafana/grafana/apps/advisor/pkg/app"
|
||||
"github.com/grafana/grafana/apps/advisor/pkg/app/checkregistry"
|
||||
"github.com/grafana/grafana/apps/advisor/pkg/app/checkregistry/mockchecks"
|
||||
)
|
||||
|
||||
func main() {
|
||||
logging.DefaultLogger = logging.NewSLogLogger(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
|
||||
Level: slog.LevelDebug,
|
||||
}))
|
||||
provider := simple.NewAppProvider(apis.LocalManifest(), nil, advisorapp.New)
|
||||
config := app.Config{
|
||||
KubeConfig: rest.Config{}, // this will be replaced by the apiserver loopback config
|
||||
ManifestData: *apis.LocalManifest().ManifestData,
|
||||
SpecificConfig: checkregistry.AdvisorAppConfig{
|
||||
CheckRegistry: mockchecks.New(),
|
||||
PluginConfig: map[string]string{},
|
||||
StackID: "1", // Numeric stack ID for standalone mode
|
||||
OrgService: nil, // Not needed when StackID is set
|
||||
},
|
||||
}
|
||||
installer, err := apiserver.NewDefaultAppInstaller(provider, config, &apis.GoTypeAssociator{})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ctx := genericapiserver.SetupSignalContext()
|
||||
opts := apiserver.NewOptions([]apiserver.AppInstaller{installer})
|
||||
opts.RecommendedOptions.Authentication = nil
|
||||
opts.RecommendedOptions.Authorization = nil
|
||||
opts.RecommendedOptions.CoreAPI = nil
|
||||
opts.RecommendedOptions.EgressSelector = nil
|
||||
opts.RecommendedOptions.Admission.Plugins = admission.NewPlugins()
|
||||
opts.RecommendedOptions.Admission.RecommendedPluginOrder = []string{}
|
||||
opts.RecommendedOptions.Admission.EnablePlugins = []string{}
|
||||
opts.RecommendedOptions.Features.EnablePriorityAndFairness = false
|
||||
opts.RecommendedOptions.ExtraAdmissionInitializers = func(_ *genericapiserver.RecommendedConfig) ([]admission.PluginInitializer, error) {
|
||||
return nil, nil
|
||||
}
|
||||
cmd := server.NewCommandStartServer(ctx, opts)
|
||||
code := cli.Run(cmd)
|
||||
os.Exit(code)
|
||||
}
|
||||
@@ -3,9 +3,9 @@ module github.com/grafana/grafana/apps/alerting/alertenrichment
|
||||
go 1.25.3
|
||||
|
||||
require (
|
||||
github.com/grafana/grafana-app-sdk v0.48.1
|
||||
github.com/grafana/grafana-app-sdk v0.48.2
|
||||
github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250901080157-a0280d701b28
|
||||
k8s.io/apimachinery v0.34.1
|
||||
k8s.io/apimachinery v0.34.2
|
||||
k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912
|
||||
)
|
||||
|
||||
@@ -27,8 +27,8 @@ require (
|
||||
github.com/x448/float16 v0.8.4 // indirect
|
||||
go.yaml.in/yaml/v2 v2.4.3 // indirect
|
||||
go.yaml.in/yaml/v3 v3.0.4 // indirect
|
||||
golang.org/x/net v0.46.0 // indirect
|
||||
golang.org/x/text v0.30.0 // indirect
|
||||
golang.org/x/net v0.47.0 // indirect
|
||||
golang.org/x/text v0.31.0 // indirect
|
||||
google.golang.org/protobuf v1.36.10 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
|
||||
@@ -23,8 +23,8 @@ github.com/google/gnostic-models v0.7.0/go.mod h1:whL5G0m6dmc5cPxKc5bdKdEN3UjI7O
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/grafana/grafana-app-sdk v0.48.1 h1:bKJadWH18WCpJ+Zk8AezRFXCcZgGredRv+fRS+8zkek=
|
||||
github.com/grafana/grafana-app-sdk v0.48.1/go.mod h1:5LljCz+wvmGfkQ8ZKTOfserhtXNEF0cSFthoWShvN6c=
|
||||
github.com/grafana/grafana-app-sdk v0.48.2 h1:CQQDhwo1fWaXQVKvxxOcK6azbuY3E2TgJHNAZlYYn7U=
|
||||
github.com/grafana/grafana-app-sdk v0.48.2/go.mod h1:LDOvQ7OOyHLcXdSa0InATCa5OMoYAd6E1+rGLrMgHuk=
|
||||
github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250901080157-a0280d701b28 h1:PgMfX4OPENz/iXmtDDIW9+poZY4UD0hhmXm7flVclDo=
|
||||
github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250901080157-a0280d701b28/go.mod h1:av5N0Naq+8VV9MLF7zAkihy/mVq5UbS2EvRSJukDHlY=
|
||||
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
||||
@@ -73,8 +73,8 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4=
|
||||
golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210=
|
||||
golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
|
||||
golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@@ -83,8 +83,8 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k=
|
||||
golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM=
|
||||
golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=
|
||||
golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
@@ -102,8 +102,8 @@ gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
|
||||
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
k8s.io/apimachinery v0.34.1 h1:dTlxFls/eikpJxmAC7MVE8oOeP1zryV7iRyIjB0gky4=
|
||||
k8s.io/apimachinery v0.34.1/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw=
|
||||
k8s.io/apimachinery v0.34.2 h1:zQ12Uk3eMHPxrsbUJgNF8bTauTVR2WgqJsTmwTE/NW4=
|
||||
k8s.io/apimachinery v0.34.2/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw=
|
||||
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
|
||||
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
|
||||
k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 h1:Y3gxNAuB0OBLImH611+UDZcmKS3g6CthxToOb37KgwE=
|
||||
|
||||
@@ -3,10 +3,10 @@ module github.com/grafana/grafana/apps/alerting/notifications
|
||||
go 1.25.3
|
||||
|
||||
require (
|
||||
github.com/grafana/grafana-app-sdk v0.48.1
|
||||
github.com/grafana/grafana-app-sdk v0.48.2
|
||||
github.com/grafana/grafana-app-sdk/logging v0.48.1
|
||||
k8s.io/apimachinery v0.34.1
|
||||
k8s.io/apiserver v0.34.1
|
||||
k8s.io/apimachinery v0.34.2
|
||||
k8s.io/apiserver v0.34.2
|
||||
k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912
|
||||
)
|
||||
|
||||
@@ -84,12 +84,12 @@ require (
|
||||
go.uber.org/zap v1.27.0 // indirect
|
||||
go.yaml.in/yaml/v2 v2.4.3 // indirect
|
||||
go.yaml.in/yaml/v3 v3.0.4 // indirect
|
||||
golang.org/x/net v0.46.0 // indirect
|
||||
golang.org/x/net v0.47.0 // indirect
|
||||
golang.org/x/oauth2 v0.32.0 // indirect
|
||||
golang.org/x/sync v0.17.0 // indirect
|
||||
golang.org/x/sys v0.37.0 // indirect
|
||||
golang.org/x/term v0.36.0 // indirect
|
||||
golang.org/x/text v0.30.0 // indirect
|
||||
golang.org/x/sync v0.18.0 // indirect
|
||||
golang.org/x/sys v0.38.0 // indirect
|
||||
golang.org/x/term v0.37.0 // indirect
|
||||
golang.org/x/text v0.31.0 // indirect
|
||||
golang.org/x/time v0.14.0 // indirect
|
||||
gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250908214217-97024824d090 // indirect
|
||||
@@ -99,10 +99,10 @@ require (
|
||||
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
k8s.io/api v0.34.1 // indirect
|
||||
k8s.io/apiextensions-apiserver v0.34.1 // indirect
|
||||
k8s.io/client-go v0.34.1 // indirect
|
||||
k8s.io/component-base v0.34.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/utils v0.0.0-20250604170112-4c0f3b243397 // indirect
|
||||
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2 // indirect
|
||||
|
||||
@@ -71,8 +71,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/grafana-app-sdk v0.48.1 h1:bKJadWH18WCpJ+Zk8AezRFXCcZgGredRv+fRS+8zkek=
|
||||
github.com/grafana/grafana-app-sdk v0.48.1/go.mod h1:5LljCz+wvmGfkQ8ZKTOfserhtXNEF0cSFthoWShvN6c=
|
||||
github.com/grafana/grafana-app-sdk v0.48.2 h1:CQQDhwo1fWaXQVKvxxOcK6azbuY3E2TgJHNAZlYYn7U=
|
||||
github.com/grafana/grafana-app-sdk v0.48.2/go.mod h1:LDOvQ7OOyHLcXdSa0InATCa5OMoYAd6E1+rGLrMgHuk=
|
||||
github.com/grafana/grafana-app-sdk/logging v0.48.1 h1:veM0X5LAPyN3KsDLglWjIofndbGuf7MqnrDuDN+F/Ng=
|
||||
github.com/grafana/grafana-app-sdk/logging v0.48.1/go.mod h1:Gh/nBWnspK3oDNWtiM5qUF/fardHzOIEez+SPI3JeHA=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.1.0 h1:QGLs/O40yoNK9vmy4rhUGBVyMf1lISBGtXRpsu/Qu/o=
|
||||
@@ -224,8 +224,8 @@ go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04=
|
||||
golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0=
|
||||
golang.org/x/crypto v0.44.0 h1:A97SsFvM3AIwEEmTBiaxPPTYpDC47w720rdiiUvgoAU=
|
||||
golang.org/x/crypto v0.44.0/go.mod h1:013i+Nw79BMiQiMsOPcVCB5ZIJbYkerPrGnOa00tvmc=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
@@ -236,8 +236,8 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4=
|
||||
golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210=
|
||||
golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
|
||||
golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.32.0 h1:jsCblLleRMDrxMN29H3z/k1KliIvpLgCkE6R8FXXNgY=
|
||||
golang.org/x/oauth2 v0.32.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
|
||||
@@ -246,20 +246,20 @@ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJ
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
|
||||
golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||
golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I=
|
||||
golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ=
|
||||
golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/term v0.36.0 h1:zMPR+aF8gfksFprF/Nc/rd1wRS1EI6nDBGyWAvDzx2Q=
|
||||
golang.org/x/term v0.36.0/go.mod h1:Qu394IJq6V6dCBRgwqshf3mPF85AqzYEzofzRdZkWss=
|
||||
golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
|
||||
golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU=
|
||||
golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k=
|
||||
golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM=
|
||||
golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=
|
||||
golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=
|
||||
golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI=
|
||||
golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4=
|
||||
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
@@ -267,8 +267,8 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ=
|
||||
golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs=
|
||||
golang.org/x/tools v0.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ=
|
||||
golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
@@ -300,18 +300,18 @@ gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYs
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
k8s.io/api v0.34.1 h1:jC+153630BMdlFukegoEL8E/yT7aLyQkIVuwhmwDgJM=
|
||||
k8s.io/api v0.34.1/go.mod h1:SB80FxFtXn5/gwzCoN6QCtPD7Vbu5w2n1S0J5gFfTYk=
|
||||
k8s.io/apiextensions-apiserver v0.34.1 h1:NNPBva8FNAPt1iSVwIE0FsdrVriRXMsaWFMqJbII2CI=
|
||||
k8s.io/apiextensions-apiserver v0.34.1/go.mod h1:hP9Rld3zF5Ay2Of3BeEpLAToP+l4s5UlxiHfqRaRcMc=
|
||||
k8s.io/apimachinery v0.34.1 h1:dTlxFls/eikpJxmAC7MVE8oOeP1zryV7iRyIjB0gky4=
|
||||
k8s.io/apimachinery v0.34.1/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw=
|
||||
k8s.io/apiserver v0.34.1 h1:U3JBGdgANK3dfFcyknWde1G6X1F4bg7PXuvlqt8lITA=
|
||||
k8s.io/apiserver v0.34.1/go.mod h1:eOOc9nrVqlBI1AFCvVzsob0OxtPZUCPiUJL45JOTBG0=
|
||||
k8s.io/client-go v0.34.1 h1:ZUPJKgXsnKwVwmKKdPfw4tB58+7/Ik3CrjOEhsiZ7mY=
|
||||
k8s.io/client-go v0.34.1/go.mod h1:kA8v0FP+tk6sZA0yKLRG67LWjqufAoSHA2xVGKw9Of8=
|
||||
k8s.io/component-base v0.34.1 h1:v7xFgG+ONhytZNFpIz5/kecwD+sUhVE6HU7qQUiRM4A=
|
||||
k8s.io/component-base v0.34.1/go.mod h1:mknCpLlTSKHzAQJJnnHVKqjxR7gBeHRv0rPXA7gdtQ0=
|
||||
k8s.io/api v0.34.2 h1:fsSUNZhV+bnL6Aqrp6O7lMTy6o5x2C4XLjnh//8SLYY=
|
||||
k8s.io/api v0.34.2/go.mod h1:MMBPaWlED2a8w4RSeanD76f7opUoypY8TFYkSM+3XHw=
|
||||
k8s.io/apiextensions-apiserver v0.34.2 h1:WStKftnGeoKP4AZRz/BaAAEJvYp4mlZGN0UCv+uvsqo=
|
||||
k8s.io/apiextensions-apiserver v0.34.2/go.mod h1:398CJrsgXF1wytdaanynDpJ67zG4Xq7yj91GrmYN2SE=
|
||||
k8s.io/apimachinery v0.34.2 h1:zQ12Uk3eMHPxrsbUJgNF8bTauTVR2WgqJsTmwTE/NW4=
|
||||
k8s.io/apimachinery v0.34.2/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw=
|
||||
k8s.io/apiserver v0.34.2 h1:2/yu8suwkmES7IzwlehAovo8dDE07cFRC7KMDb1+MAE=
|
||||
k8s.io/apiserver v0.34.2/go.mod h1:gqJQy2yDOB50R3JUReHSFr+cwJnL8G1dzTA0YLEqAPI=
|
||||
k8s.io/client-go v0.34.2 h1:Co6XiknN+uUZqiddlfAjT68184/37PS4QAzYvQvDR8M=
|
||||
k8s.io/client-go v0.34.2/go.mod h1:2VYDl1XXJsdcAxw7BenFslRQX28Dxz91U9MWKjX97fE=
|
||||
k8s.io/component-base v0.34.2 h1:HQRqK9x2sSAsd8+R4xxRirlTjowsg6fWCPwWYeSvogQ=
|
||||
k8s.io/component-base v0.34.2/go.mod h1:9xw2FHJavUHBFpiGkZoKuYZ5pdtLKe97DEByaA+hHbM=
|
||||
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
|
||||
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
|
||||
k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 h1:Y3gxNAuB0OBLImH611+UDZcmKS3g6CthxToOb37KgwE=
|
||||
|
||||
@@ -8,7 +8,16 @@ spec:
|
||||
preferredVersion: v0alpha1
|
||||
versions:
|
||||
- kinds:
|
||||
- conversion: false
|
||||
- admission:
|
||||
mutation:
|
||||
operations:
|
||||
- CREATE
|
||||
- UPDATE
|
||||
validation:
|
||||
operations:
|
||||
- CREATE
|
||||
- UPDATE
|
||||
conversion: false
|
||||
kind: AlertRule
|
||||
plural: AlertRules
|
||||
schemas:
|
||||
@@ -214,7 +223,16 @@ spec:
|
||||
- spec.panelRef.dashboardUID
|
||||
- spec.panelRef.panelID
|
||||
- spec.notificationSettings.receiver
|
||||
- conversion: false
|
||||
- admission:
|
||||
mutation:
|
||||
operations:
|
||||
- CREATE
|
||||
- UPDATE
|
||||
validation:
|
||||
operations:
|
||||
- CREATE
|
||||
- UPDATE
|
||||
conversion: false
|
||||
kind: RecordingRule
|
||||
plural: RecordingRules
|
||||
schemas:
|
||||
|
||||
@@ -3,9 +3,10 @@ module github.com/grafana/grafana/apps/alerting/rules
|
||||
go 1.25.3
|
||||
|
||||
require (
|
||||
github.com/grafana/grafana-app-sdk v0.48.1
|
||||
github.com/grafana/grafana-app-sdk v0.48.2
|
||||
github.com/grafana/grafana-app-sdk/logging v0.48.1
|
||||
k8s.io/apimachinery v0.34.1
|
||||
github.com/prometheus/common v0.67.1
|
||||
k8s.io/apimachinery v0.34.2
|
||||
k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912
|
||||
)
|
||||
|
||||
@@ -49,7 +50,6 @@ require (
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||
github.com/prometheus/client_golang v1.23.2 // indirect
|
||||
github.com/prometheus/client_model v0.6.2 // indirect
|
||||
github.com/prometheus/common v0.67.1 // indirect
|
||||
github.com/prometheus/procfs v0.16.1 // indirect
|
||||
github.com/puzpuzpuz/xsync/v2 v2.5.1 // indirect
|
||||
github.com/rogpeppe/go-internal v1.14.1 // indirect
|
||||
@@ -67,12 +67,12 @@ require (
|
||||
go.opentelemetry.io/proto/otlp v1.7.1 // indirect
|
||||
go.yaml.in/yaml/v2 v2.4.3 // indirect
|
||||
go.yaml.in/yaml/v3 v3.0.4 // indirect
|
||||
golang.org/x/net v0.46.0 // indirect
|
||||
golang.org/x/net v0.47.0 // indirect
|
||||
golang.org/x/oauth2 v0.32.0 // indirect
|
||||
golang.org/x/sync v0.17.0 // indirect
|
||||
golang.org/x/sys v0.37.0 // indirect
|
||||
golang.org/x/term v0.36.0 // indirect
|
||||
golang.org/x/text v0.30.0 // indirect
|
||||
golang.org/x/sync v0.18.0 // indirect
|
||||
golang.org/x/sys v0.38.0 // indirect
|
||||
golang.org/x/term v0.37.0 // indirect
|
||||
golang.org/x/text v0.31.0 // indirect
|
||||
golang.org/x/time v0.14.0 // indirect
|
||||
gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250908214217-97024824d090 // indirect
|
||||
@@ -81,9 +81,9 @@ require (
|
||||
google.golang.org/protobuf v1.36.10 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
k8s.io/api v0.34.1 // indirect
|
||||
k8s.io/apiextensions-apiserver v0.34.1 // indirect
|
||||
k8s.io/client-go v0.34.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/klog/v2 v2.130.1 // indirect
|
||||
k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 // indirect
|
||||
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect
|
||||
|
||||
@@ -48,8 +48,8 @@ github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 h1:BHT72Gu3keYf3ZEu2J
|
||||
github.com/google/pprof v0.0.0-20250403155104-27863c87afa6/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA=
|
||||
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.1 h1:bKJadWH18WCpJ+Zk8AezRFXCcZgGredRv+fRS+8zkek=
|
||||
github.com/grafana/grafana-app-sdk v0.48.1/go.mod h1:5LljCz+wvmGfkQ8ZKTOfserhtXNEF0cSFthoWShvN6c=
|
||||
github.com/grafana/grafana-app-sdk v0.48.2 h1:CQQDhwo1fWaXQVKvxxOcK6azbuY3E2TgJHNAZlYYn7U=
|
||||
github.com/grafana/grafana-app-sdk v0.48.2/go.mod h1:LDOvQ7OOyHLcXdSa0InATCa5OMoYAd6E1+rGLrMgHuk=
|
||||
github.com/grafana/grafana-app-sdk/logging v0.48.1 h1:veM0X5LAPyN3KsDLglWjIofndbGuf7MqnrDuDN+F/Ng=
|
||||
github.com/grafana/grafana-app-sdk/logging v0.48.1/go.mod h1:Gh/nBWnspK3oDNWtiM5qUF/fardHzOIEez+SPI3JeHA=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 h1:8Tjv8EJ+pM1xP8mK6egEbD1OgnVTyacbefKhmbLhIhU=
|
||||
@@ -163,34 +163,34 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4=
|
||||
golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210=
|
||||
golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
|
||||
golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
|
||||
golang.org/x/oauth2 v0.32.0 h1:jsCblLleRMDrxMN29H3z/k1KliIvpLgCkE6R8FXXNgY=
|
||||
golang.org/x/oauth2 v0.32.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
|
||||
golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||
golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I=
|
||||
golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ=
|
||||
golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/term v0.36.0 h1:zMPR+aF8gfksFprF/Nc/rd1wRS1EI6nDBGyWAvDzx2Q=
|
||||
golang.org/x/term v0.36.0/go.mod h1:Qu394IJq6V6dCBRgwqshf3mPF85AqzYEzofzRdZkWss=
|
||||
golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
|
||||
golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU=
|
||||
golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k=
|
||||
golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM=
|
||||
golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=
|
||||
golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=
|
||||
golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI=
|
||||
golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ=
|
||||
golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs=
|
||||
golang.org/x/tools v0.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ=
|
||||
golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
@@ -216,14 +216,14 @@ gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
|
||||
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
k8s.io/api v0.34.1 h1:jC+153630BMdlFukegoEL8E/yT7aLyQkIVuwhmwDgJM=
|
||||
k8s.io/api v0.34.1/go.mod h1:SB80FxFtXn5/gwzCoN6QCtPD7Vbu5w2n1S0J5gFfTYk=
|
||||
k8s.io/apiextensions-apiserver v0.34.1 h1:NNPBva8FNAPt1iSVwIE0FsdrVriRXMsaWFMqJbII2CI=
|
||||
k8s.io/apiextensions-apiserver v0.34.1/go.mod h1:hP9Rld3zF5Ay2Of3BeEpLAToP+l4s5UlxiHfqRaRcMc=
|
||||
k8s.io/apimachinery v0.34.1 h1:dTlxFls/eikpJxmAC7MVE8oOeP1zryV7iRyIjB0gky4=
|
||||
k8s.io/apimachinery v0.34.1/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw=
|
||||
k8s.io/client-go v0.34.1 h1:ZUPJKgXsnKwVwmKKdPfw4tB58+7/Ik3CrjOEhsiZ7mY=
|
||||
k8s.io/client-go v0.34.1/go.mod h1:kA8v0FP+tk6sZA0yKLRG67LWjqufAoSHA2xVGKw9Of8=
|
||||
k8s.io/api v0.34.2 h1:fsSUNZhV+bnL6Aqrp6O7lMTy6o5x2C4XLjnh//8SLYY=
|
||||
k8s.io/api v0.34.2/go.mod h1:MMBPaWlED2a8w4RSeanD76f7opUoypY8TFYkSM+3XHw=
|
||||
k8s.io/apiextensions-apiserver v0.34.2 h1:WStKftnGeoKP4AZRz/BaAAEJvYp4mlZGN0UCv+uvsqo=
|
||||
k8s.io/apiextensions-apiserver v0.34.2/go.mod h1:398CJrsgXF1wytdaanynDpJ67zG4Xq7yj91GrmYN2SE=
|
||||
k8s.io/apimachinery v0.34.2 h1:zQ12Uk3eMHPxrsbUJgNF8bTauTVR2WgqJsTmwTE/NW4=
|
||||
k8s.io/apimachinery v0.34.2/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw=
|
||||
k8s.io/client-go v0.34.2 h1:Co6XiknN+uUZqiddlfAjT68184/37PS4QAzYvQvDR8M=
|
||||
k8s.io/client-go v0.34.2/go.mod h1:2VYDl1XXJsdcAxw7BenFslRQX28Dxz91U9MWKjX97fE=
|
||||
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
|
||||
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
|
||||
k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 h1:Y3gxNAuB0OBLImH611+UDZcmKS3g6CthxToOb37KgwE=
|
||||
|
||||
@@ -13,6 +13,18 @@ alertRulev0alpha1: alertRuleKind & {
|
||||
schema: {
|
||||
spec: v0alpha1.AlertRuleSpec
|
||||
}
|
||||
validation: {
|
||||
operations: [
|
||||
"CREATE",
|
||||
"UPDATE",
|
||||
]
|
||||
}
|
||||
mutation: {
|
||||
operations: [
|
||||
"CREATE",
|
||||
"UPDATE",
|
||||
]
|
||||
}
|
||||
selectableFields: [
|
||||
"spec.title",
|
||||
"spec.paused",
|
||||
|
||||
@@ -13,6 +13,18 @@ recordingRulev0alpha1: recordingRuleKind & {
|
||||
schema: {
|
||||
spec: v0alpha1.RecordingRuleSpec
|
||||
}
|
||||
validation: {
|
||||
operations: [
|
||||
"CREATE",
|
||||
"UPDATE",
|
||||
]
|
||||
}
|
||||
mutation: {
|
||||
operations: [
|
||||
"CREATE",
|
||||
"UPDATE",
|
||||
]
|
||||
}
|
||||
selectableFields: [
|
||||
"spec.title",
|
||||
"spec.paused",
|
||||
|
||||
@@ -3,6 +3,7 @@ package v0alpha1
|
||||
import (
|
||||
"fmt"
|
||||
"slices"
|
||||
"time"
|
||||
)
|
||||
|
||||
func (o *AlertRule) GetProvenanceStatus() string {
|
||||
@@ -48,4 +49,78 @@ func (s *AlertRuleSpec) ExecErrStateOrDefault() string {
|
||||
return s.ExecErrState
|
||||
}
|
||||
|
||||
// TODO: add duration clamping for the field types AlertRulePromDuration, AlertRulePromDurationWMillis, and the For and KeepFiringFor string pointers
|
||||
func (d *AlertRulePromDuration) ToDuration() (time.Duration, error) {
|
||||
return ToDuration(string(*d))
|
||||
}
|
||||
|
||||
func (d *AlertRulePromDurationWMillis) ToDuration() (time.Duration, error) {
|
||||
return ToDuration(string(*d))
|
||||
}
|
||||
|
||||
func (d *AlertRulePromDuration) Clamp() error {
|
||||
clampedDuration, err := ClampDuration(string(*d))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*d = AlertRulePromDuration(clampedDuration)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *AlertRulePromDurationWMillis) Clamp() error {
|
||||
clampedDuration, err := ClampDuration(string(*d))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*d = AlertRulePromDurationWMillis(clampedDuration)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (spec *AlertRuleSpec) ClampDurations() error {
|
||||
// clamp all duration fields
|
||||
if err := spec.Trigger.Interval.Clamp(); err != nil {
|
||||
return err
|
||||
}
|
||||
if spec.For != nil {
|
||||
clamped, err := ClampDuration(*spec.For)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
spec.For = &clamped
|
||||
}
|
||||
if spec.KeepFiringFor != nil {
|
||||
clamped, err := ClampDuration(*spec.KeepFiringFor)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
spec.KeepFiringFor = &clamped
|
||||
}
|
||||
if spec.NotificationSettings != nil {
|
||||
if spec.NotificationSettings.GroupWait != nil {
|
||||
if err := spec.NotificationSettings.GroupWait.Clamp(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if spec.NotificationSettings.GroupInterval != nil {
|
||||
if err := spec.NotificationSettings.GroupInterval.Clamp(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if spec.NotificationSettings.RepeatInterval != nil {
|
||||
if err := spec.NotificationSettings.RepeatInterval.Clamp(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
for k, expr := range spec.Expressions {
|
||||
if expr.RelativeTimeRange != nil {
|
||||
if err := expr.RelativeTimeRange.From.Clamp(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := expr.RelativeTimeRange.To.Clamp(); err != nil {
|
||||
return err
|
||||
}
|
||||
spec.Expressions[k] = expr
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1,17 +1,50 @@
|
||||
package v0alpha1
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
prom_model "github.com/prometheus/common/model"
|
||||
)
|
||||
|
||||
const (
|
||||
InternalPrefix = "grafana.com/"
|
||||
GroupLabelKey = InternalPrefix + "group"
|
||||
GroupIndexLabelKey = GroupLabelKey + "-index"
|
||||
ProvenanceStatusAnnotationKey = InternalPrefix + "provenance"
|
||||
// Copy of the max title length used in legacy validation path
|
||||
AlertRuleMaxTitleLength = 190
|
||||
// Annotation key used to store the folder UID on resources
|
||||
FolderAnnotationKey = "grafana.app/folder"
|
||||
FolderLabelKey = FolderAnnotationKey
|
||||
)
|
||||
|
||||
// NOTE: This is a copy of the constants from the alertrule package to avoid circular imports.
|
||||
// Keep in sync with pkg/services/ngalert/models/provisioning.go
|
||||
const (
|
||||
ProvenanceStatusNone = ""
|
||||
ProvenanceStatusAPI = "api"
|
||||
ProvenanceStatusNone = ""
|
||||
ProvenanceStatusAPI = "api"
|
||||
ProvenanceStatusFile = "file"
|
||||
ProvenanceStatusConvertedPrometheus = "converted_prometheus"
|
||||
)
|
||||
|
||||
var (
|
||||
AcceptedProvenanceStatuses = []string{ProvenanceStatusNone, ProvenanceStatusAPI}
|
||||
AcceptedProvenanceStatuses = []string{ProvenanceStatusNone, ProvenanceStatusAPI, ProvenanceStatusFile, ProvenanceStatusConvertedPrometheus}
|
||||
)
|
||||
|
||||
func ToDuration(s string) (time.Duration, error) {
|
||||
promDuration, err := prom_model.ParseDuration(s)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("invalid duration format: %w", err)
|
||||
}
|
||||
return time.Duration(promDuration), nil
|
||||
}
|
||||
|
||||
// Convert the string duration to the longest valid Prometheus duration format (e.g., "60s" -> "1m")
|
||||
func ClampDuration(s string) (string, error) {
|
||||
promDuration, err := prom_model.ParseDuration(s)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("invalid duration format: %w", err)
|
||||
}
|
||||
return promDuration.String(), nil
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package v0alpha1
|
||||
import (
|
||||
"fmt"
|
||||
"slices"
|
||||
"time"
|
||||
)
|
||||
|
||||
func (o *RecordingRule) GetProvenanceStatus() string {
|
||||
@@ -27,4 +28,47 @@ func (o *RecordingRule) SetProvenanceStatus(status string) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// TODO: add duration clamping for the field types RecordingRulePromDurationWMillis and RecordingRulePromDuration
|
||||
func (d *RecordingRulePromDuration) ToDuration() (time.Duration, error) {
|
||||
return ToDuration(string(*d))
|
||||
}
|
||||
|
||||
func (d *RecordingRulePromDurationWMillis) ToDuration() (time.Duration, error) {
|
||||
return ToDuration(string(*d))
|
||||
}
|
||||
|
||||
func (d *RecordingRulePromDuration) Clamp() error {
|
||||
clampedDuration, err := ClampDuration(string(*d))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*d = RecordingRulePromDuration(clampedDuration)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *RecordingRulePromDurationWMillis) Clamp() error {
|
||||
clampedDuration, err := ClampDuration(string(*d))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*d = RecordingRulePromDurationWMillis(clampedDuration)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (spec *RecordingRuleSpec) ClampDurations() error {
|
||||
// clamp all duration fields
|
||||
if err := spec.Trigger.Interval.Clamp(); err != nil {
|
||||
return err
|
||||
}
|
||||
for k, expr := range spec.Expressions {
|
||||
if expr.RelativeTimeRange != nil {
|
||||
if err := expr.RelativeTimeRange.From.Clamp(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := expr.RelativeTimeRange.To.Clamp(); err != nil {
|
||||
return err
|
||||
}
|
||||
spec.Expressions[k] = expr
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
32
apps/alerting/rules/pkg/apis/alerting_manifest.go
generated
32
apps/alerting/rules/pkg/apis/alerting_manifest.go
generated
@@ -42,7 +42,21 @@ var appManifestData = app.ManifestData{
|
||||
Plural: "AlertRules",
|
||||
Scope: "Namespaced",
|
||||
Conversion: false,
|
||||
Schema: &versionSchemaAlertRulev0alpha1,
|
||||
Admission: &app.AdmissionCapabilities{
|
||||
Validation: &app.ValidationCapability{
|
||||
Operations: []app.AdmissionOperation{
|
||||
app.AdmissionOperationCreate,
|
||||
app.AdmissionOperationUpdate,
|
||||
},
|
||||
},
|
||||
Mutation: &app.MutationCapability{
|
||||
Operations: []app.AdmissionOperation{
|
||||
app.AdmissionOperationCreate,
|
||||
app.AdmissionOperationUpdate,
|
||||
},
|
||||
},
|
||||
},
|
||||
Schema: &versionSchemaAlertRulev0alpha1,
|
||||
SelectableFields: []string{
|
||||
"spec.title",
|
||||
"spec.paused",
|
||||
@@ -57,7 +71,21 @@ var appManifestData = app.ManifestData{
|
||||
Plural: "RecordingRules",
|
||||
Scope: "Namespaced",
|
||||
Conversion: false,
|
||||
Schema: &versionSchemaRecordingRulev0alpha1,
|
||||
Admission: &app.AdmissionCapabilities{
|
||||
Validation: &app.ValidationCapability{
|
||||
Operations: []app.AdmissionOperation{
|
||||
app.AdmissionOperationCreate,
|
||||
app.AdmissionOperationUpdate,
|
||||
},
|
||||
},
|
||||
Mutation: &app.MutationCapability{
|
||||
Operations: []app.AdmissionOperation{
|
||||
app.AdmissionOperationCreate,
|
||||
app.AdmissionOperationUpdate,
|
||||
},
|
||||
},
|
||||
},
|
||||
Schema: &versionSchemaRecordingRulev0alpha1,
|
||||
SelectableFields: []string{
|
||||
"spec.title",
|
||||
"spec.paused",
|
||||
|
||||
45
apps/alerting/rules/pkg/app/alertrule/mutator.go
Normal file
45
apps/alerting/rules/pkg/app/alertrule/mutator.go
Normal file
@@ -0,0 +1,45 @@
|
||||
package alertrule
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/grafana/grafana-app-sdk/app"
|
||||
"github.com/grafana/grafana-app-sdk/simple"
|
||||
v1 "github.com/grafana/grafana/apps/alerting/rules/pkg/apis/alerting/v0alpha1"
|
||||
"github.com/grafana/grafana/apps/alerting/rules/pkg/app/config"
|
||||
)
|
||||
|
||||
func NewMutator(cfg config.RuntimeConfig) *simple.Mutator {
|
||||
return &simple.Mutator{
|
||||
MutateFunc: func(ctx context.Context, req *app.AdmissionRequest) (*app.MutatingResponse, error) {
|
||||
// Mutate folder label to match folder UID from annotation
|
||||
r, ok := req.Object.(*v1.AlertRule)
|
||||
if !ok || r == nil {
|
||||
// Nothing to do or wrong type; no mutation
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Read folder UID from annotation
|
||||
folderUID := ""
|
||||
if r.Annotations != nil {
|
||||
folderUID = r.Annotations[v1.FolderAnnotationKey]
|
||||
}
|
||||
|
||||
// Ensure labels map exists and set the folder label if folderUID is present
|
||||
if folderUID != "" {
|
||||
if r.Labels == nil {
|
||||
r.Labels = make(map[string]string)
|
||||
}
|
||||
// Maintain folder metadata label for downstream systems (alertmanager grouping etc.)
|
||||
r.Labels[v1.FolderLabelKey] = folderUID
|
||||
}
|
||||
|
||||
// clamp all duration fields
|
||||
if err := r.Spec.ClampDurations(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &app.MutatingResponse{UpdatedObject: r}, nil
|
||||
},
|
||||
}
|
||||
}
|
||||
122
apps/alerting/rules/pkg/app/alertrule/validator.go
Normal file
122
apps/alerting/rules/pkg/app/alertrule/validator.go
Normal file
@@ -0,0 +1,122 @@
|
||||
package alertrule
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"slices"
|
||||
"time"
|
||||
|
||||
"github.com/grafana/grafana-app-sdk/app"
|
||||
"github.com/grafana/grafana-app-sdk/resource"
|
||||
"github.com/grafana/grafana-app-sdk/simple"
|
||||
model "github.com/grafana/grafana/apps/alerting/rules/pkg/apis/alerting/v0alpha1"
|
||||
"github.com/grafana/grafana/apps/alerting/rules/pkg/app/config"
|
||||
"github.com/grafana/grafana/apps/alerting/rules/pkg/app/util"
|
||||
prom_model "github.com/prometheus/common/model"
|
||||
)
|
||||
|
||||
// validateGroupLabels now delegates to util.ValidateGroupLabels for shared logic.
|
||||
func validateGroupLabels(r *model.AlertRule, oldObject resource.Object, action resource.AdmissionAction) error {
|
||||
var oldLabels map[string]string
|
||||
if oldObject != nil {
|
||||
if oldRule, ok := oldObject.(*model.AlertRule); ok {
|
||||
oldLabels = oldRule.Labels
|
||||
} else {
|
||||
return fmt.Errorf("old object is not of type *v0alpha1.AlertRule")
|
||||
}
|
||||
}
|
||||
return util.ValidateGroupLabels(r.Labels, oldLabels, action)
|
||||
}
|
||||
|
||||
func NewValidator(cfg config.RuntimeConfig) *simple.Validator {
|
||||
return &simple.Validator{
|
||||
ValidateFunc: func(ctx context.Context, req *app.AdmissionRequest) error {
|
||||
// Cast to specific type
|
||||
r, ok := req.Object.(*model.AlertRule)
|
||||
if !ok {
|
||||
return fmt.Errorf("object is not of type *v0alpha1.AlertRule")
|
||||
}
|
||||
// 1) Validate provenance status annotation
|
||||
sourceProv := r.GetProvenanceStatus()
|
||||
if !slices.Contains(model.AcceptedProvenanceStatuses, sourceProv) {
|
||||
return fmt.Errorf("invalid provenance status: %s", sourceProv)
|
||||
}
|
||||
|
||||
// 2) Validate group labels rules
|
||||
if err := validateGroupLabels(r, req.OldObject, req.Action); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 3) Validate folder is set and exists
|
||||
// Read folder UID directly from annotations
|
||||
folderUID := ""
|
||||
if r.Annotations != nil {
|
||||
folderUID = r.Annotations[model.FolderAnnotationKey]
|
||||
}
|
||||
if folderUID == "" {
|
||||
return fmt.Errorf("folder is required")
|
||||
}
|
||||
if cfg.FolderValidator != nil {
|
||||
ok, verr := cfg.FolderValidator(ctx, folderUID)
|
||||
if verr != nil {
|
||||
return fmt.Errorf("failed to validate folder: %w", verr)
|
||||
}
|
||||
if !ok {
|
||||
return fmt.Errorf("folder does not exist: %s", folderUID)
|
||||
}
|
||||
}
|
||||
|
||||
// 4) Validate notification settings receiver if provided
|
||||
if r.Spec.NotificationSettings != nil && r.Spec.NotificationSettings.Receiver != "" && cfg.NotificationSettingsValidator != nil {
|
||||
ok, nerr := cfg.NotificationSettingsValidator(ctx, r.Spec.NotificationSettings.Receiver)
|
||||
if nerr != nil {
|
||||
return fmt.Errorf("failed to validate notification settings: %w", nerr)
|
||||
}
|
||||
if !ok {
|
||||
return fmt.Errorf("invalid notification receiver: %s", r.Spec.NotificationSettings.Receiver)
|
||||
}
|
||||
}
|
||||
|
||||
// 5) Enforce max title length
|
||||
if len(r.Spec.Title) > model.AlertRuleMaxTitleLength {
|
||||
return fmt.Errorf("alert rule title is too long. Max length is %d", model.AlertRuleMaxTitleLength)
|
||||
}
|
||||
|
||||
// 6) Validate evaluation interval against base interval
|
||||
if err := util.ValidateInterval(cfg.BaseEvaluationInterval, &r.Spec.Trigger.Interval); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 7) Disallow reserved/spec system label keys
|
||||
if r.Spec.Labels != nil {
|
||||
for key := range r.Spec.Labels {
|
||||
if _, bad := cfg.ReservedLabelKeys[key]; bad {
|
||||
return fmt.Errorf("label key is reserved and cannot be specified: %s", key)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 8) For and KeepFiringFor must be >= 0 if set
|
||||
if r.Spec.For != nil {
|
||||
d, err := prom_model.ParseDuration(*r.Spec.For)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid 'for' duration: %w", err)
|
||||
}
|
||||
if time.Duration(d) < 0 {
|
||||
return fmt.Errorf("'for' cannot be less than 0")
|
||||
}
|
||||
}
|
||||
if r.Spec.KeepFiringFor != nil {
|
||||
d, err := prom_model.ParseDuration(*r.Spec.KeepFiringFor)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid 'keepFiringFor' duration: %w", err)
|
||||
}
|
||||
if time.Duration(d) < 0 {
|
||||
return fmt.Errorf("'keepFiringFor' cannot be less than 0")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -6,16 +6,29 @@ import (
|
||||
"github.com/grafana/grafana-app-sdk/app"
|
||||
"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"
|
||||
|
||||
"github.com/grafana/grafana/apps/alerting/rules/pkg/apis"
|
||||
"github.com/grafana/grafana/apps/alerting/rules/pkg/app/alertrule"
|
||||
"github.com/grafana/grafana/apps/alerting/rules/pkg/app/config"
|
||||
"github.com/grafana/grafana/apps/alerting/rules/pkg/app/recordingrule"
|
||||
)
|
||||
|
||||
func New(cfg app.Config) (app.App, error) {
|
||||
managedKinds := make([]simple.AppManagedKind, 0)
|
||||
runtimeCfg, ok := cfg.SpecificConfig.(config.RuntimeConfig)
|
||||
if !ok {
|
||||
return nil, config.ErrInvalidRuntimeConfig
|
||||
}
|
||||
for _, kinds := range apis.GetKinds() {
|
||||
for _, kind := range kinds {
|
||||
managedKinds = append(managedKinds, simple.AppManagedKind{Kind: kind})
|
||||
managedKind := simple.AppManagedKind{
|
||||
Kind: kind,
|
||||
Validator: buildKindValidator(kind, runtimeCfg),
|
||||
Mutator: buildKindMutator(kind, runtimeCfg),
|
||||
}
|
||||
managedKinds = append(managedKinds, managedKind)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,3 +57,23 @@ func New(cfg app.Config) (app.App, error) {
|
||||
|
||||
return a, nil
|
||||
}
|
||||
|
||||
func buildKindValidator(kind resource.Kind, cfg config.RuntimeConfig) *simple.Validator {
|
||||
switch kind.Kind() {
|
||||
case "AlertRule":
|
||||
return alertrule.NewValidator(cfg)
|
||||
case "RecordingRule":
|
||||
return recordingrule.NewValidator(cfg)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func buildKindMutator(kind resource.Kind, cfg config.RuntimeConfig) *simple.Mutator {
|
||||
switch kind.Kind() {
|
||||
case "AlertRule":
|
||||
return alertrule.NewMutator(cfg)
|
||||
case "RecordingRule":
|
||||
return recordingrule.NewMutator(cfg)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
175
apps/alerting/rules/pkg/app/app_test.go
Normal file
175
apps/alerting/rules/pkg/app/app_test.go
Normal file
@@ -0,0 +1,175 @@
|
||||
package app_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
appsdk "github.com/grafana/grafana-app-sdk/app"
|
||||
"github.com/grafana/grafana-app-sdk/resource"
|
||||
|
||||
v1 "github.com/grafana/grafana/apps/alerting/rules/pkg/apis/alerting/v0alpha1"
|
||||
"github.com/grafana/grafana/apps/alerting/rules/pkg/app/alertrule"
|
||||
"github.com/grafana/grafana/apps/alerting/rules/pkg/app/config"
|
||||
"github.com/grafana/grafana/apps/alerting/rules/pkg/app/recordingrule"
|
||||
)
|
||||
|
||||
func makeDefaultRuntimeConfig() config.RuntimeConfig {
|
||||
return config.RuntimeConfig{
|
||||
FolderValidator: func(ctx context.Context, folderUID string) (bool, error) { return folderUID == "f1", nil },
|
||||
BaseEvaluationInterval: 60 * time.Second, // seconds
|
||||
ReservedLabelKeys: map[string]struct{}{"__reserved__": {}, "grafana_folder": {}},
|
||||
NotificationSettingsValidator: func(ctx context.Context, receiver string) (bool, error) { return receiver == "notif-ok", nil },
|
||||
}
|
||||
}
|
||||
|
||||
func TestAlertRuleValidation_Success(t *testing.T) {
|
||||
r := &v1.AlertRule{}
|
||||
r.SetGroupVersionKind(v1.AlertRuleKind().GroupVersionKind())
|
||||
r.Name = "uid-1"
|
||||
r.Namespace = "ns1"
|
||||
r.Annotations = map[string]string{v1.FolderAnnotationKey: "f1"}
|
||||
r.Labels = map[string]string{}
|
||||
r.Spec = v1.AlertRuleSpec{
|
||||
Title: "ok",
|
||||
Trigger: v1.AlertRuleIntervalTrigger{Interval: v1.AlertRulePromDuration("60s")},
|
||||
Expressions: v1.AlertRuleExpressionMap{"A": v1.AlertRuleExpression{Model: map[string]any{"expr": "1"}, Source: boolPtr(true)}},
|
||||
NoDataState: v1.DefaultNoDataState,
|
||||
ExecErrState: v1.DefaultExecErrState,
|
||||
NotificationSettings: &v1.AlertRuleV0alpha1SpecNotificationSettings{Receiver: "notif-ok"},
|
||||
}
|
||||
|
||||
req := &appsdk.AdmissionRequest{Action: resource.AdmissionActionCreate, Object: r}
|
||||
validator := alertrule.NewValidator(makeDefaultRuntimeConfig())
|
||||
if err := validator.Validate(context.Background(), req); err != nil {
|
||||
t.Fatalf("expected success, got error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAlertRuleValidation_Errors(t *testing.T) {
|
||||
mk := func(mut func(r *v1.AlertRule)) error {
|
||||
r := baseAlertRule()
|
||||
mut(r)
|
||||
return alertrule.NewValidator(makeDefaultRuntimeConfig()).Validate(context.Background(), &appsdk.AdmissionRequest{Action: resource.AdmissionActionCreate, Object: r})
|
||||
}
|
||||
|
||||
if err := mk(func(r *v1.AlertRule) { r.Annotations = nil }); err == nil {
|
||||
t.Errorf("want folder required error")
|
||||
}
|
||||
if err := mk(func(r *v1.AlertRule) { r.Annotations[v1.FolderAnnotationKey] = "bad" }); err == nil {
|
||||
t.Errorf("want folder not exist error")
|
||||
}
|
||||
if err := mk(func(r *v1.AlertRule) { r.Spec.Trigger.Interval = v1.AlertRulePromDuration("30s") }); err == nil {
|
||||
t.Errorf("want base interval multiple error")
|
||||
}
|
||||
if err := mk(func(r *v1.AlertRule) {
|
||||
r.Spec.NotificationSettings = &v1.AlertRuleV0alpha1SpecNotificationSettings{Receiver: "bad"}
|
||||
}); err == nil {
|
||||
t.Errorf("want invalid receiver error")
|
||||
}
|
||||
if err := mk(func(r *v1.AlertRule) { r.Labels[v1.GroupLabelKey] = "grp" }); err == nil {
|
||||
t.Errorf("want group set on create error")
|
||||
}
|
||||
if err := mk(func(r *v1.AlertRule) { r.Spec.For = strPtr("-10s") }); err == nil {
|
||||
t.Errorf("want for>=0 error")
|
||||
}
|
||||
if err := mk(func(r *v1.AlertRule) {
|
||||
if r.Spec.Labels == nil {
|
||||
r.Spec.Labels = map[string]v1.AlertRuleTemplateString{}
|
||||
}
|
||||
r.Spec.Labels["__reserved__"] = v1.AlertRuleTemplateString("x")
|
||||
}); err == nil {
|
||||
t.Errorf("want reserved label key error")
|
||||
}
|
||||
}
|
||||
|
||||
func baseAlertRule() *v1.AlertRule {
|
||||
r := &v1.AlertRule{}
|
||||
r.SetGroupVersionKind(v1.AlertRuleKind().GroupVersionKind())
|
||||
r.Name = "uid-1"
|
||||
r.Namespace = "ns1"
|
||||
r.Annotations = map[string]string{v1.FolderAnnotationKey: "f1"}
|
||||
r.Labels = map[string]string{}
|
||||
r.Spec = v1.AlertRuleSpec{
|
||||
Title: "ok",
|
||||
Trigger: v1.AlertRuleIntervalTrigger{Interval: v1.AlertRulePromDuration("60s")},
|
||||
Expressions: v1.AlertRuleExpressionMap{"A": v1.AlertRuleExpression{Model: map[string]any{"expr": "1"}, Source: boolPtr(true)}},
|
||||
NoDataState: v1.DefaultNoDataState,
|
||||
ExecErrState: v1.DefaultExecErrState,
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func TestRecordingRuleValidation_Success(t *testing.T) {
|
||||
r := &v1.RecordingRule{}
|
||||
r.SetGroupVersionKind(v1.RecordingRuleKind().GroupVersionKind())
|
||||
r.Name = "uid-2"
|
||||
r.Namespace = "ns1"
|
||||
r.Annotations = map[string]string{v1.FolderAnnotationKey: "f1"}
|
||||
r.Labels = map[string]string{}
|
||||
r.Spec = v1.RecordingRuleSpec{
|
||||
Title: "ok",
|
||||
Trigger: v1.RecordingRuleIntervalTrigger{Interval: v1.RecordingRulePromDuration("60s")},
|
||||
Expressions: v1.RecordingRuleExpressionMap{"A": v1.RecordingRuleExpression{Model: map[string]any{"expr": "1"}, Source: boolPtr(true)}},
|
||||
Metric: "test_metric",
|
||||
TargetDatasourceUID: "ds1",
|
||||
}
|
||||
|
||||
req := &appsdk.AdmissionRequest{Action: resource.AdmissionActionCreate, Object: r}
|
||||
validator := recordingrule.NewValidator(makeDefaultRuntimeConfig())
|
||||
if err := validator.Validate(context.Background(), req); err != nil {
|
||||
t.Fatalf("expected success, got error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRecordingRuleValidation_Errors(t *testing.T) {
|
||||
mk := func(mut func(r *v1.RecordingRule)) error {
|
||||
r := baseRecordingRule()
|
||||
mut(r)
|
||||
return recordingrule.NewValidator(makeDefaultRuntimeConfig()).Validate(context.Background(), &appsdk.AdmissionRequest{Action: resource.AdmissionActionCreate, Object: r})
|
||||
}
|
||||
|
||||
if err := mk(func(r *v1.RecordingRule) { r.Annotations = nil }); err == nil {
|
||||
t.Errorf("want folder required error")
|
||||
}
|
||||
if err := mk(func(r *v1.RecordingRule) { r.Annotations[v1.FolderAnnotationKey] = "bad" }); err == nil {
|
||||
t.Errorf("want folder not exist error")
|
||||
}
|
||||
if err := mk(func(r *v1.RecordingRule) { r.Spec.Trigger.Interval = v1.RecordingRulePromDuration("30s") }); err == nil {
|
||||
t.Errorf("want base interval multiple error")
|
||||
}
|
||||
if err := mk(func(r *v1.RecordingRule) { r.Labels[v1.GroupLabelKey] = "grp" }); err == nil {
|
||||
t.Errorf("want group set on create error")
|
||||
}
|
||||
if err := mk(func(r *v1.RecordingRule) { r.Spec.Metric = "" }); err == nil {
|
||||
t.Errorf("want metric required error")
|
||||
}
|
||||
if err := mk(func(r *v1.RecordingRule) {
|
||||
if r.Spec.Labels == nil {
|
||||
r.Spec.Labels = map[string]v1.RecordingRuleTemplateString{}
|
||||
}
|
||||
r.Spec.Labels["__reserved__"] = v1.RecordingRuleTemplateString("x")
|
||||
}); err == nil {
|
||||
t.Errorf("want reserved label key error")
|
||||
}
|
||||
}
|
||||
|
||||
func baseRecordingRule() *v1.RecordingRule {
|
||||
r := &v1.RecordingRule{}
|
||||
r.SetGroupVersionKind(v1.RecordingRuleKind().GroupVersionKind())
|
||||
r.Name = "uid-1"
|
||||
r.Namespace = "ns1"
|
||||
r.Annotations = map[string]string{v1.FolderAnnotationKey: "f1"}
|
||||
r.Labels = map[string]string{}
|
||||
r.Spec = v1.RecordingRuleSpec{
|
||||
Title: "ok",
|
||||
Trigger: v1.RecordingRuleIntervalTrigger{Interval: v1.RecordingRulePromDuration("60s")},
|
||||
Expressions: v1.RecordingRuleExpressionMap{"A": v1.RecordingRuleExpression{Model: map[string]any{"expr": "1"}, Source: boolPtr(true)}},
|
||||
Metric: "test_metric",
|
||||
TargetDatasourceUID: "ds1",
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func boolPtr(b bool) *bool { return &b }
|
||||
func strPtr(s string) *string { return &s }
|
||||
22
apps/alerting/rules/pkg/app/config/runtime.go
Normal file
22
apps/alerting/rules/pkg/app/config/runtime.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrInvalidRuntimeConfig = errors.New("invalid runtime config provided to alerting/rules app")
|
||||
)
|
||||
|
||||
// RuntimeConfig holds configuration values needed at runtime by the alerting/rules app from the running Grafana instance.
|
||||
type RuntimeConfig struct {
|
||||
// function to check folder existence given its uid
|
||||
FolderValidator func(ctx context.Context, folderUID string) (bool, error)
|
||||
// base evaluation interval
|
||||
BaseEvaluationInterval time.Duration
|
||||
// set of strings which are illegal for label keys on rules
|
||||
ReservedLabelKeys map[string]struct{}
|
||||
NotificationSettingsValidator func(ctx context.Context, receiver string) (bool, error)
|
||||
}
|
||||
37
apps/alerting/rules/pkg/app/recordingrule/mutator.go
Normal file
37
apps/alerting/rules/pkg/app/recordingrule/mutator.go
Normal file
@@ -0,0 +1,37 @@
|
||||
package recordingrule
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/grafana/grafana-app-sdk/app"
|
||||
"github.com/grafana/grafana-app-sdk/simple"
|
||||
v1 "github.com/grafana/grafana/apps/alerting/rules/pkg/apis/alerting/v0alpha1"
|
||||
"github.com/grafana/grafana/apps/alerting/rules/pkg/app/config"
|
||||
)
|
||||
|
||||
func NewMutator(cfg config.RuntimeConfig) *simple.Mutator {
|
||||
return &simple.Mutator{
|
||||
MutateFunc: func(ctx context.Context, req *app.AdmissionRequest) (*app.MutatingResponse, error) {
|
||||
r, ok := req.Object.(*v1.RecordingRule)
|
||||
if !ok || r == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
folderUID := ""
|
||||
if r.Annotations != nil {
|
||||
folderUID = r.Annotations[v1.FolderAnnotationKey]
|
||||
}
|
||||
|
||||
if folderUID != "" {
|
||||
if r.Labels == nil {
|
||||
r.Labels = make(map[string]string)
|
||||
}
|
||||
r.Labels[v1.FolderLabelKey] = folderUID
|
||||
}
|
||||
if err := r.Spec.ClampDurations(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &app.MutatingResponse{UpdatedObject: r}, nil
|
||||
},
|
||||
}
|
||||
}
|
||||
95
apps/alerting/rules/pkg/app/recordingrule/validator.go
Normal file
95
apps/alerting/rules/pkg/app/recordingrule/validator.go
Normal file
@@ -0,0 +1,95 @@
|
||||
package recordingrule
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"slices"
|
||||
|
||||
"github.com/grafana/grafana-app-sdk/app"
|
||||
"github.com/grafana/grafana-app-sdk/resource"
|
||||
"github.com/grafana/grafana-app-sdk/simple"
|
||||
model "github.com/grafana/grafana/apps/alerting/rules/pkg/apis/alerting/v0alpha1"
|
||||
"github.com/grafana/grafana/apps/alerting/rules/pkg/app/config"
|
||||
"github.com/grafana/grafana/apps/alerting/rules/pkg/app/util"
|
||||
prom_model "github.com/prometheus/common/model"
|
||||
)
|
||||
|
||||
// validateGroupLabels now delegates to util.ValidateGroupLabels for shared logic.
|
||||
func validateGroupLabels(r *model.RecordingRule, oldObject resource.Object, action resource.AdmissionAction) error {
|
||||
var oldLabels map[string]string
|
||||
if oldObject != nil {
|
||||
if oldRule, ok := oldObject.(*model.RecordingRule); ok {
|
||||
oldLabels = oldRule.Labels
|
||||
} else {
|
||||
return fmt.Errorf("old object is not of type *v0alpha1.RecordingRule")
|
||||
}
|
||||
}
|
||||
return util.ValidateGroupLabels(r.Labels, oldLabels, action)
|
||||
}
|
||||
|
||||
func NewValidator(cfg config.RuntimeConfig) *simple.Validator {
|
||||
return &simple.Validator{
|
||||
ValidateFunc: func(ctx context.Context, req *app.AdmissionRequest) error {
|
||||
// Cast to specific type
|
||||
r, ok := req.Object.(*model.RecordingRule)
|
||||
if !ok {
|
||||
return fmt.Errorf("object is not of type *v0alpha1.RecordingRule")
|
||||
}
|
||||
|
||||
sourceProv := r.GetProvenanceStatus()
|
||||
if !slices.Contains(model.AcceptedProvenanceStatuses, sourceProv) {
|
||||
return fmt.Errorf("invalid provenance status: %s", sourceProv)
|
||||
}
|
||||
|
||||
if err := validateGroupLabels(r, req.OldObject, req.Action); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
folderUID := ""
|
||||
if r.Annotations != nil {
|
||||
folderUID = r.Annotations[model.FolderAnnotationKey]
|
||||
}
|
||||
if folderUID == "" {
|
||||
return fmt.Errorf("folder is required")
|
||||
}
|
||||
if cfg.FolderValidator != nil {
|
||||
ok, verr := cfg.FolderValidator(ctx, folderUID)
|
||||
if verr != nil {
|
||||
return fmt.Errorf("failed to validate folder: %w", verr)
|
||||
}
|
||||
if !ok {
|
||||
return fmt.Errorf("folder does not exist: %s", folderUID)
|
||||
}
|
||||
}
|
||||
|
||||
if len(r.Spec.Title) > model.AlertRuleMaxTitleLength {
|
||||
return fmt.Errorf("recording rule title is too long. Max length is %d", model.AlertRuleMaxTitleLength)
|
||||
}
|
||||
|
||||
if err := util.ValidateInterval(cfg.BaseEvaluationInterval, &r.Spec.Trigger.Interval); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if r.Spec.Labels != nil {
|
||||
for key := range r.Spec.Labels {
|
||||
if _, bad := cfg.ReservedLabelKeys[key]; bad {
|
||||
return fmt.Errorf("label key is reserved and cannot be specified: %s", key)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if r.Spec.Metric == "" {
|
||||
return fmt.Errorf("metric must be specified")
|
||||
}
|
||||
metric := prom_model.LabelValue(r.Spec.Metric)
|
||||
if !metric.IsValid() {
|
||||
return fmt.Errorf("metric contains invalid characters")
|
||||
}
|
||||
if !prom_model.IsValidMetricName(metric) { // nolint:staticcheck
|
||||
return fmt.Errorf("invalid metric name")
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
}
|
||||
59
apps/alerting/rules/pkg/app/util/group_validation.go
Normal file
59
apps/alerting/rules/pkg/app/util/group_validation.go
Normal file
@@ -0,0 +1,59 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/grafana/grafana-app-sdk/resource"
|
||||
model "github.com/grafana/grafana/apps/alerting/rules/pkg/apis/alerting/v0alpha1"
|
||||
)
|
||||
|
||||
// ValidateGroupLabels enforces the cross-field rules for group-related labels.
|
||||
//
|
||||
// Rules enforced:
|
||||
// - On create, group-related labels must not be set.
|
||||
// - If one of group or group-index is set, the other must also be set.
|
||||
// - group-index must be an integer.
|
||||
// - On update, group/group-index can only be present if they were present on the old object.
|
||||
//
|
||||
// Pass current labels and, when available, the previous object's labels. The previous labels
|
||||
// may be nil when there is no old object (e.g., create operations).
|
||||
func ValidateGroupLabels(labels map[string]string, oldLabels map[string]string, action resource.AdmissionAction) error {
|
||||
groupStr, groupExists := labels[model.GroupLabelKey]
|
||||
groupIndexStr, groupIndexStrExists := labels[model.GroupIndexLabelKey]
|
||||
|
||||
if groupExists || groupIndexStrExists {
|
||||
if action == resource.AdmissionActionCreate {
|
||||
return fmt.Errorf("cannot set group when creating a new rule")
|
||||
}
|
||||
if groupExists && !groupIndexStrExists {
|
||||
return fmt.Errorf("%s must be set when %s is set", model.GroupIndexLabelKey, model.GroupLabelKey)
|
||||
}
|
||||
if groupIndexStrExists && !groupExists {
|
||||
return fmt.Errorf("%s must be set when %s is set", model.GroupLabelKey, model.GroupIndexLabelKey)
|
||||
}
|
||||
// Disallow empty values when labels are present
|
||||
if groupExists && groupStr == "" {
|
||||
return fmt.Errorf("%s cannot be empty", model.GroupLabelKey)
|
||||
}
|
||||
if groupIndexStrExists && groupIndexStr == "" {
|
||||
return fmt.Errorf("%s cannot be empty", model.GroupIndexLabelKey)
|
||||
}
|
||||
if _, err := strconv.Atoi(groupIndexStr); err != nil {
|
||||
return fmt.Errorf("invalid %s: %w", model.GroupIndexLabelKey, err)
|
||||
}
|
||||
|
||||
// On updates, ensure that group and group-index are only set if the old object had them set
|
||||
if oldLabels != nil {
|
||||
_, oldGroupExists := oldLabels[model.GroupLabelKey]
|
||||
_, oldGroupIndexExists := oldLabels[model.GroupIndexLabelKey]
|
||||
if groupExists && !oldGroupExists {
|
||||
return fmt.Errorf("cannot set group when updating un-grouped rule")
|
||||
}
|
||||
if groupIndexStrExists && !oldGroupIndexExists {
|
||||
return fmt.Errorf("cannot set group-index when updating un-grouped rule")
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
109
apps/alerting/rules/pkg/app/util/group_validation_test.go
Normal file
109
apps/alerting/rules/pkg/app/util/group_validation_test.go
Normal file
@@ -0,0 +1,109 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/grafana/grafana-app-sdk/resource"
|
||||
model "github.com/grafana/grafana/apps/alerting/rules/pkg/apis/alerting/v0alpha1"
|
||||
)
|
||||
|
||||
func TestValidateGroupLabels(t *testing.T) {
|
||||
group := model.GroupLabelKey
|
||||
groupIdx := model.GroupIndexLabelKey
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
labels map[string]string
|
||||
oldLabels map[string]string
|
||||
action resource.AdmissionAction
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "update empty group value",
|
||||
labels: map[string]string{group: "", groupIdx: "1"},
|
||||
action: resource.AdmissionActionUpdate,
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "update empty group-index value",
|
||||
labels: map[string]string{group: "g1", groupIdx: ""},
|
||||
action: resource.AdmissionActionUpdate,
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "create empty group value disallowed",
|
||||
labels: map[string]string{group: ""},
|
||||
action: resource.AdmissionActionCreate,
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "create no labels allowed",
|
||||
labels: nil,
|
||||
action: resource.AdmissionActionCreate,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "create with group disallowed",
|
||||
labels: map[string]string{group: "g1"},
|
||||
action: resource.AdmissionActionCreate,
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "create with group-index disallowed",
|
||||
labels: map[string]string{groupIdx: "1"},
|
||||
action: resource.AdmissionActionCreate,
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "update missing paired index",
|
||||
labels: map[string]string{group: "g1"},
|
||||
action: resource.AdmissionActionUpdate,
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "update missing paired group",
|
||||
labels: map[string]string{groupIdx: "1"},
|
||||
action: resource.AdmissionActionUpdate,
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "update invalid index format",
|
||||
labels: map[string]string{group: "g1", groupIdx: "x"},
|
||||
oldLabels: map[string]string{group: "g1", groupIdx: "0"},
|
||||
action: resource.AdmissionActionUpdate,
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "update cannot add group when previously ungrouped",
|
||||
labels: map[string]string{group: "g1", groupIdx: "0"},
|
||||
oldLabels: map[string]string{},
|
||||
action: resource.AdmissionActionUpdate,
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "update allowed when previously grouped",
|
||||
labels: map[string]string{group: "g1", groupIdx: "2"},
|
||||
oldLabels: map[string]string{group: "g1", groupIdx: "1"},
|
||||
action: resource.AdmissionActionUpdate,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "update no labels remains allowed",
|
||||
labels: nil,
|
||||
action: resource.AdmissionActionUpdate,
|
||||
wantErr: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
err := ValidateGroupLabels(tc.labels, tc.oldLabels, tc.action)
|
||||
if tc.wantErr && err == nil {
|
||||
t.Fatalf("expected error, got nil")
|
||||
}
|
||||
if !tc.wantErr && err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
27
apps/alerting/rules/pkg/app/util/validator.go
Normal file
27
apps/alerting/rules/pkg/app/util/validator.go
Normal file
@@ -0,0 +1,27 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
type DurationLike interface {
|
||||
ToDuration() (time.Duration, error)
|
||||
}
|
||||
|
||||
func ValidateInterval(baseInterval time.Duration, d DurationLike) error {
|
||||
interval, err := d.ToDuration()
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid trigger interval: %w", err)
|
||||
}
|
||||
// Ensure interval is positive and an integer multiple of BaseEvaluationInterval (if provided)
|
||||
if interval <= 0 {
|
||||
return fmt.Errorf("trigger interval must be greater than 0")
|
||||
}
|
||||
if baseInterval > 0 {
|
||||
if (interval % baseInterval) != 0 {
|
||||
return fmt.Errorf("trigger interval must be a multiple of base evaluation interval (%s)", baseInterval.String())
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -3,9 +3,9 @@ module github.com/grafana/grafana/apps/annotation
|
||||
go 1.24.0
|
||||
|
||||
require (
|
||||
github.com/grafana/grafana-app-sdk v0.48.1
|
||||
github.com/grafana/grafana-app-sdk v0.48.2
|
||||
github.com/grafana/grafana-app-sdk/logging v0.48.1
|
||||
k8s.io/apimachinery v0.34.1
|
||||
k8s.io/apimachinery v0.34.2
|
||||
k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912
|
||||
)
|
||||
|
||||
@@ -67,12 +67,12 @@ require (
|
||||
go.opentelemetry.io/proto/otlp v1.7.1 // indirect
|
||||
go.yaml.in/yaml/v2 v2.4.3 // indirect
|
||||
go.yaml.in/yaml/v3 v3.0.4 // indirect
|
||||
golang.org/x/net v0.46.0 // indirect
|
||||
golang.org/x/net v0.47.0 // indirect
|
||||
golang.org/x/oauth2 v0.32.0 // indirect
|
||||
golang.org/x/sync v0.17.0 // indirect
|
||||
golang.org/x/sys v0.37.0 // indirect
|
||||
golang.org/x/term v0.36.0 // indirect
|
||||
golang.org/x/text v0.30.0 // indirect
|
||||
golang.org/x/sync v0.18.0 // indirect
|
||||
golang.org/x/sys v0.38.0 // indirect
|
||||
golang.org/x/term v0.37.0 // indirect
|
||||
golang.org/x/text v0.31.0 // indirect
|
||||
golang.org/x/time v0.14.0 // indirect
|
||||
gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250908214217-97024824d090 // indirect
|
||||
@@ -81,9 +81,9 @@ require (
|
||||
google.golang.org/protobuf v1.36.10 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
k8s.io/api v0.34.1 // indirect
|
||||
k8s.io/apiextensions-apiserver v0.34.1 // indirect
|
||||
k8s.io/client-go v0.34.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/klog/v2 v2.130.1 // indirect
|
||||
k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 // indirect
|
||||
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect
|
||||
|
||||
@@ -48,8 +48,8 @@ github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 h1:BHT72Gu3keYf3ZEu2J
|
||||
github.com/google/pprof v0.0.0-20250403155104-27863c87afa6/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA=
|
||||
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.1 h1:bKJadWH18WCpJ+Zk8AezRFXCcZgGredRv+fRS+8zkek=
|
||||
github.com/grafana/grafana-app-sdk v0.48.1/go.mod h1:5LljCz+wvmGfkQ8ZKTOfserhtXNEF0cSFthoWShvN6c=
|
||||
github.com/grafana/grafana-app-sdk v0.48.2 h1:CQQDhwo1fWaXQVKvxxOcK6azbuY3E2TgJHNAZlYYn7U=
|
||||
github.com/grafana/grafana-app-sdk v0.48.2/go.mod h1:LDOvQ7OOyHLcXdSa0InATCa5OMoYAd6E1+rGLrMgHuk=
|
||||
github.com/grafana/grafana-app-sdk/logging v0.48.1 h1:veM0X5LAPyN3KsDLglWjIofndbGuf7MqnrDuDN+F/Ng=
|
||||
github.com/grafana/grafana-app-sdk/logging v0.48.1/go.mod h1:Gh/nBWnspK3oDNWtiM5qUF/fardHzOIEez+SPI3JeHA=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 h1:8Tjv8EJ+pM1xP8mK6egEbD1OgnVTyacbefKhmbLhIhU=
|
||||
@@ -163,34 +163,34 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4=
|
||||
golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210=
|
||||
golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
|
||||
golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
|
||||
golang.org/x/oauth2 v0.32.0 h1:jsCblLleRMDrxMN29H3z/k1KliIvpLgCkE6R8FXXNgY=
|
||||
golang.org/x/oauth2 v0.32.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
|
||||
golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||
golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I=
|
||||
golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ=
|
||||
golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/term v0.36.0 h1:zMPR+aF8gfksFprF/Nc/rd1wRS1EI6nDBGyWAvDzx2Q=
|
||||
golang.org/x/term v0.36.0/go.mod h1:Qu394IJq6V6dCBRgwqshf3mPF85AqzYEzofzRdZkWss=
|
||||
golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
|
||||
golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU=
|
||||
golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k=
|
||||
golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM=
|
||||
golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=
|
||||
golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=
|
||||
golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI=
|
||||
golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ=
|
||||
golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs=
|
||||
golang.org/x/tools v0.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ=
|
||||
golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
@@ -216,14 +216,14 @@ gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
|
||||
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
k8s.io/api v0.34.1 h1:jC+153630BMdlFukegoEL8E/yT7aLyQkIVuwhmwDgJM=
|
||||
k8s.io/api v0.34.1/go.mod h1:SB80FxFtXn5/gwzCoN6QCtPD7Vbu5w2n1S0J5gFfTYk=
|
||||
k8s.io/apiextensions-apiserver v0.34.1 h1:NNPBva8FNAPt1iSVwIE0FsdrVriRXMsaWFMqJbII2CI=
|
||||
k8s.io/apiextensions-apiserver v0.34.1/go.mod h1:hP9Rld3zF5Ay2Of3BeEpLAToP+l4s5UlxiHfqRaRcMc=
|
||||
k8s.io/apimachinery v0.34.1 h1:dTlxFls/eikpJxmAC7MVE8oOeP1zryV7iRyIjB0gky4=
|
||||
k8s.io/apimachinery v0.34.1/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw=
|
||||
k8s.io/client-go v0.34.1 h1:ZUPJKgXsnKwVwmKKdPfw4tB58+7/Ik3CrjOEhsiZ7mY=
|
||||
k8s.io/client-go v0.34.1/go.mod h1:kA8v0FP+tk6sZA0yKLRG67LWjqufAoSHA2xVGKw9Of8=
|
||||
k8s.io/api v0.34.2 h1:fsSUNZhV+bnL6Aqrp6O7lMTy6o5x2C4XLjnh//8SLYY=
|
||||
k8s.io/api v0.34.2/go.mod h1:MMBPaWlED2a8w4RSeanD76f7opUoypY8TFYkSM+3XHw=
|
||||
k8s.io/apiextensions-apiserver v0.34.2 h1:WStKftnGeoKP4AZRz/BaAAEJvYp4mlZGN0UCv+uvsqo=
|
||||
k8s.io/apiextensions-apiserver v0.34.2/go.mod h1:398CJrsgXF1wytdaanynDpJ67zG4Xq7yj91GrmYN2SE=
|
||||
k8s.io/apimachinery v0.34.2 h1:zQ12Uk3eMHPxrsbUJgNF8bTauTVR2WgqJsTmwTE/NW4=
|
||||
k8s.io/apimachinery v0.34.2/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw=
|
||||
k8s.io/client-go v0.34.2 h1:Co6XiknN+uUZqiddlfAjT68184/37PS4QAzYvQvDR8M=
|
||||
k8s.io/client-go v0.34.2/go.mod h1:2VYDl1XXJsdcAxw7BenFslRQX28Dxz91U9MWKjX97fE=
|
||||
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
|
||||
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
|
||||
k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 h1:Y3gxNAuB0OBLImH611+UDZcmKS3g6CthxToOb37KgwE=
|
||||
|
||||
@@ -3,9 +3,9 @@ module github.com/grafana/grafana/apps/correlations
|
||||
go 1.25.3
|
||||
|
||||
require (
|
||||
github.com/grafana/grafana-app-sdk v0.48.1
|
||||
github.com/grafana/grafana-app-sdk v0.48.2
|
||||
github.com/grafana/grafana-app-sdk/logging v0.48.1
|
||||
k8s.io/apimachinery v0.34.1
|
||||
k8s.io/apimachinery v0.34.2
|
||||
k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912
|
||||
)
|
||||
|
||||
@@ -67,12 +67,12 @@ require (
|
||||
go.opentelemetry.io/proto/otlp v1.7.1 // indirect
|
||||
go.yaml.in/yaml/v2 v2.4.3 // indirect
|
||||
go.yaml.in/yaml/v3 v3.0.4 // indirect
|
||||
golang.org/x/net v0.46.0 // indirect
|
||||
golang.org/x/net v0.47.0 // indirect
|
||||
golang.org/x/oauth2 v0.32.0 // indirect
|
||||
golang.org/x/sync v0.17.0 // indirect
|
||||
golang.org/x/sys v0.37.0 // indirect
|
||||
golang.org/x/term v0.36.0 // indirect
|
||||
golang.org/x/text v0.30.0 // indirect
|
||||
golang.org/x/sync v0.18.0 // indirect
|
||||
golang.org/x/sys v0.38.0 // indirect
|
||||
golang.org/x/term v0.37.0 // indirect
|
||||
golang.org/x/text v0.31.0 // indirect
|
||||
golang.org/x/time v0.14.0 // indirect
|
||||
gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250908214217-97024824d090 // indirect
|
||||
@@ -81,9 +81,9 @@ require (
|
||||
google.golang.org/protobuf v1.36.10 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
k8s.io/api v0.34.1 // indirect
|
||||
k8s.io/apiextensions-apiserver v0.34.1 // indirect
|
||||
k8s.io/client-go v0.34.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/klog/v2 v2.130.1 // indirect
|
||||
k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 // indirect
|
||||
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect
|
||||
|
||||
@@ -48,8 +48,8 @@ github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 h1:BHT72Gu3keYf3ZEu2J
|
||||
github.com/google/pprof v0.0.0-20250403155104-27863c87afa6/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA=
|
||||
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.1 h1:bKJadWH18WCpJ+Zk8AezRFXCcZgGredRv+fRS+8zkek=
|
||||
github.com/grafana/grafana-app-sdk v0.48.1/go.mod h1:5LljCz+wvmGfkQ8ZKTOfserhtXNEF0cSFthoWShvN6c=
|
||||
github.com/grafana/grafana-app-sdk v0.48.2 h1:CQQDhwo1fWaXQVKvxxOcK6azbuY3E2TgJHNAZlYYn7U=
|
||||
github.com/grafana/grafana-app-sdk v0.48.2/go.mod h1:LDOvQ7OOyHLcXdSa0InATCa5OMoYAd6E1+rGLrMgHuk=
|
||||
github.com/grafana/grafana-app-sdk/logging v0.48.1 h1:veM0X5LAPyN3KsDLglWjIofndbGuf7MqnrDuDN+F/Ng=
|
||||
github.com/grafana/grafana-app-sdk/logging v0.48.1/go.mod h1:Gh/nBWnspK3oDNWtiM5qUF/fardHzOIEez+SPI3JeHA=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 h1:8Tjv8EJ+pM1xP8mK6egEbD1OgnVTyacbefKhmbLhIhU=
|
||||
@@ -163,34 +163,34 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4=
|
||||
golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210=
|
||||
golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
|
||||
golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
|
||||
golang.org/x/oauth2 v0.32.0 h1:jsCblLleRMDrxMN29H3z/k1KliIvpLgCkE6R8FXXNgY=
|
||||
golang.org/x/oauth2 v0.32.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
|
||||
golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||
golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I=
|
||||
golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ=
|
||||
golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/term v0.36.0 h1:zMPR+aF8gfksFprF/Nc/rd1wRS1EI6nDBGyWAvDzx2Q=
|
||||
golang.org/x/term v0.36.0/go.mod h1:Qu394IJq6V6dCBRgwqshf3mPF85AqzYEzofzRdZkWss=
|
||||
golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
|
||||
golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU=
|
||||
golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k=
|
||||
golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM=
|
||||
golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=
|
||||
golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=
|
||||
golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI=
|
||||
golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ=
|
||||
golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs=
|
||||
golang.org/x/tools v0.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ=
|
||||
golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
@@ -216,14 +216,14 @@ gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
|
||||
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
k8s.io/api v0.34.1 h1:jC+153630BMdlFukegoEL8E/yT7aLyQkIVuwhmwDgJM=
|
||||
k8s.io/api v0.34.1/go.mod h1:SB80FxFtXn5/gwzCoN6QCtPD7Vbu5w2n1S0J5gFfTYk=
|
||||
k8s.io/apiextensions-apiserver v0.34.1 h1:NNPBva8FNAPt1iSVwIE0FsdrVriRXMsaWFMqJbII2CI=
|
||||
k8s.io/apiextensions-apiserver v0.34.1/go.mod h1:hP9Rld3zF5Ay2Of3BeEpLAToP+l4s5UlxiHfqRaRcMc=
|
||||
k8s.io/apimachinery v0.34.1 h1:dTlxFls/eikpJxmAC7MVE8oOeP1zryV7iRyIjB0gky4=
|
||||
k8s.io/apimachinery v0.34.1/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw=
|
||||
k8s.io/client-go v0.34.1 h1:ZUPJKgXsnKwVwmKKdPfw4tB58+7/Ik3CrjOEhsiZ7mY=
|
||||
k8s.io/client-go v0.34.1/go.mod h1:kA8v0FP+tk6sZA0yKLRG67LWjqufAoSHA2xVGKw9Of8=
|
||||
k8s.io/api v0.34.2 h1:fsSUNZhV+bnL6Aqrp6O7lMTy6o5x2C4XLjnh//8SLYY=
|
||||
k8s.io/api v0.34.2/go.mod h1:MMBPaWlED2a8w4RSeanD76f7opUoypY8TFYkSM+3XHw=
|
||||
k8s.io/apiextensions-apiserver v0.34.2 h1:WStKftnGeoKP4AZRz/BaAAEJvYp4mlZGN0UCv+uvsqo=
|
||||
k8s.io/apiextensions-apiserver v0.34.2/go.mod h1:398CJrsgXF1wytdaanynDpJ67zG4Xq7yj91GrmYN2SE=
|
||||
k8s.io/apimachinery v0.34.2 h1:zQ12Uk3eMHPxrsbUJgNF8bTauTVR2WgqJsTmwTE/NW4=
|
||||
k8s.io/apimachinery v0.34.2/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw=
|
||||
k8s.io/client-go v0.34.2 h1:Co6XiknN+uUZqiddlfAjT68184/37PS4QAzYvQvDR8M=
|
||||
k8s.io/client-go v0.34.2/go.mod h1:2VYDl1XXJsdcAxw7BenFslRQX28Dxz91U9MWKjX97fE=
|
||||
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
|
||||
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
|
||||
k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 h1:Y3gxNAuB0OBLImH611+UDZcmKS3g6CthxToOb37KgwE=
|
||||
|
||||
@@ -5,15 +5,14 @@ go 1.25.3
|
||||
require (
|
||||
cuelang.org/go v0.11.1
|
||||
github.com/grafana/authlib/types v0.0.0-20250926065801-df98203cff37
|
||||
github.com/grafana/grafana-app-sdk v0.48.1
|
||||
github.com/grafana/grafana-app-sdk v0.48.2
|
||||
github.com/grafana/grafana-app-sdk/logging v0.48.1
|
||||
github.com/grafana/grafana-plugin-sdk-go v0.281.0
|
||||
github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250514132646-acbc7b54ed9e
|
||||
github.com/prometheus/client_golang v1.23.2
|
||||
github.com/stretchr/testify v1.11.1
|
||||
golang.org/x/net v0.46.0
|
||||
k8s.io/apimachinery v0.34.1
|
||||
k8s.io/apiserver v0.34.1
|
||||
k8s.io/apimachinery v0.34.2
|
||||
k8s.io/apiserver v0.34.2
|
||||
k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912
|
||||
k8s.io/utils v0.0.0-20250604170112-4c0f3b243397
|
||||
)
|
||||
@@ -107,17 +106,18 @@ require (
|
||||
go.opentelemetry.io/proto/otlp v1.7.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.43.0 // indirect
|
||||
golang.org/x/crypto v0.44.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20251002181428-27f1f14c8bb9 // indirect
|
||||
golang.org/x/mod v0.29.0 // indirect
|
||||
golang.org/x/mod v0.30.0 // indirect
|
||||
golang.org/x/net v0.47.0 // indirect
|
||||
golang.org/x/oauth2 v0.32.0 // indirect
|
||||
golang.org/x/sync v0.17.0 // indirect
|
||||
golang.org/x/sys v0.37.0 // indirect
|
||||
golang.org/x/telemetry v0.0.0-20251008203120-078029d740a8 // indirect
|
||||
golang.org/x/term v0.36.0 // indirect
|
||||
golang.org/x/text v0.30.0 // indirect
|
||||
golang.org/x/sync v0.18.0 // indirect
|
||||
golang.org/x/sys v0.38.0 // indirect
|
||||
golang.org/x/telemetry v0.0.0-20251111182119-bc8e575c7b54 // indirect
|
||||
golang.org/x/term v0.37.0 // indirect
|
||||
golang.org/x/text v0.31.0 // indirect
|
||||
golang.org/x/time v0.14.0 // indirect
|
||||
golang.org/x/tools v0.38.0 // indirect
|
||||
golang.org/x/tools v0.39.0 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250908214217-97024824d090 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20251002232023-7c0ddcbb5797 // indirect
|
||||
@@ -125,8 +125,8 @@ require (
|
||||
google.golang.org/protobuf v1.36.10 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
k8s.io/client-go v0.34.1 // indirect
|
||||
k8s.io/component-base v0.34.1 // 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
|
||||
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect
|
||||
sigs.k8s.io/randfill v1.0.0 // indirect
|
||||
|
||||
@@ -85,8 +85,8 @@ github.com/grafana/authlib/types v0.0.0-20250926065801-df98203cff37 h1:qEwZ+7MbP
|
||||
github.com/grafana/authlib/types v0.0.0-20250926065801-df98203cff37/go.mod h1:qeWYbnWzaYGl88JlL9+DsP1GT2Cudm58rLtx13fKZdw=
|
||||
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.1 h1:bKJadWH18WCpJ+Zk8AezRFXCcZgGredRv+fRS+8zkek=
|
||||
github.com/grafana/grafana-app-sdk v0.48.1/go.mod h1:5LljCz+wvmGfkQ8ZKTOfserhtXNEF0cSFthoWShvN6c=
|
||||
github.com/grafana/grafana-app-sdk v0.48.2 h1:CQQDhwo1fWaXQVKvxxOcK6azbuY3E2TgJHNAZlYYn7U=
|
||||
github.com/grafana/grafana-app-sdk v0.48.2/go.mod h1:LDOvQ7OOyHLcXdSa0InATCa5OMoYAd6E1+rGLrMgHuk=
|
||||
github.com/grafana/grafana-app-sdk/logging v0.48.1 h1:veM0X5LAPyN3KsDLglWjIofndbGuf7MqnrDuDN+F/Ng=
|
||||
github.com/grafana/grafana-app-sdk/logging v0.48.1/go.mod h1:Gh/nBWnspK3oDNWtiM5qUF/fardHzOIEez+SPI3JeHA=
|
||||
github.com/grafana/grafana-plugin-sdk-go v0.281.0 h1:V8dGyatzcOLQeivFhBV2JWMwTSZH/clDnpfKG9p3dTA=
|
||||
@@ -280,27 +280,27 @@ go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04=
|
||||
golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0=
|
||||
golang.org/x/crypto v0.44.0 h1:A97SsFvM3AIwEEmTBiaxPPTYpDC47w720rdiiUvgoAU=
|
||||
golang.org/x/crypto v0.44.0/go.mod h1:013i+Nw79BMiQiMsOPcVCB5ZIJbYkerPrGnOa00tvmc=
|
||||
golang.org/x/exp v0.0.0-20251002181428-27f1f14c8bb9 h1:TQwNpfvNkxAVlItJf6Cr5JTsVZoC/Sj7K3OZv2Pc14A=
|
||||
golang.org/x/exp v0.0.0-20251002181428-27f1f14c8bb9/go.mod h1:TwQYMMnGpvZyc+JpB/UAuTNIsVJifOlSkrZkhcvpVUk=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA=
|
||||
golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w=
|
||||
golang.org/x/mod v0.30.0 h1:fDEXFVZ/fmCKProc/yAXXUijritrDzahmwwefnjoPFk=
|
||||
golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4=
|
||||
golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210=
|
||||
golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
|
||||
golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
|
||||
golang.org/x/oauth2 v0.32.0 h1:jsCblLleRMDrxMN29H3z/k1KliIvpLgCkE6R8FXXNgY=
|
||||
golang.org/x/oauth2 v0.32.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
|
||||
golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||
golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I=
|
||||
golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@@ -311,24 +311,24 @@ golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ=
|
||||
golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/telemetry v0.0.0-20251008203120-078029d740a8 h1:LvzTn0GQhWuvKH/kVRS3R3bVAsdQWI7hvfLHGgh9+lU=
|
||||
golang.org/x/telemetry v0.0.0-20251008203120-078029d740a8/go.mod h1:Pi4ztBfryZoJEkyFTI5/Ocsu2jXyDr6iSdgJiYE/uwE=
|
||||
golang.org/x/term v0.36.0 h1:zMPR+aF8gfksFprF/Nc/rd1wRS1EI6nDBGyWAvDzx2Q=
|
||||
golang.org/x/term v0.36.0/go.mod h1:Qu394IJq6V6dCBRgwqshf3mPF85AqzYEzofzRdZkWss=
|
||||
golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
|
||||
golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/telemetry v0.0.0-20251111182119-bc8e575c7b54 h1:E2/AqCUMZGgd73TQkxUMcMla25GB9i/5HOdLr+uH7Vo=
|
||||
golang.org/x/telemetry v0.0.0-20251111182119-bc8e575c7b54/go.mod h1:hKdjCMrbv9skySur+Nek8Hd0uJ0GuxJIoIX2payrIdQ=
|
||||
golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU=
|
||||
golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k=
|
||||
golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM=
|
||||
golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=
|
||||
golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=
|
||||
golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI=
|
||||
golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ=
|
||||
golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs=
|
||||
golang.org/x/tools v0.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ=
|
||||
golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
@@ -355,16 +355,16 @@ gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
k8s.io/api v0.34.1 h1:jC+153630BMdlFukegoEL8E/yT7aLyQkIVuwhmwDgJM=
|
||||
k8s.io/api v0.34.1/go.mod h1:SB80FxFtXn5/gwzCoN6QCtPD7Vbu5w2n1S0J5gFfTYk=
|
||||
k8s.io/apimachinery v0.34.1 h1:dTlxFls/eikpJxmAC7MVE8oOeP1zryV7iRyIjB0gky4=
|
||||
k8s.io/apimachinery v0.34.1/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw=
|
||||
k8s.io/apiserver v0.34.1 h1:U3JBGdgANK3dfFcyknWde1G6X1F4bg7PXuvlqt8lITA=
|
||||
k8s.io/apiserver v0.34.1/go.mod h1:eOOc9nrVqlBI1AFCvVzsob0OxtPZUCPiUJL45JOTBG0=
|
||||
k8s.io/client-go v0.34.1 h1:ZUPJKgXsnKwVwmKKdPfw4tB58+7/Ik3CrjOEhsiZ7mY=
|
||||
k8s.io/client-go v0.34.1/go.mod h1:kA8v0FP+tk6sZA0yKLRG67LWjqufAoSHA2xVGKw9Of8=
|
||||
k8s.io/component-base v0.34.1 h1:v7xFgG+ONhytZNFpIz5/kecwD+sUhVE6HU7qQUiRM4A=
|
||||
k8s.io/component-base v0.34.1/go.mod h1:mknCpLlTSKHzAQJJnnHVKqjxR7gBeHRv0rPXA7gdtQ0=
|
||||
k8s.io/api v0.34.2 h1:fsSUNZhV+bnL6Aqrp6O7lMTy6o5x2C4XLjnh//8SLYY=
|
||||
k8s.io/api v0.34.2/go.mod h1:MMBPaWlED2a8w4RSeanD76f7opUoypY8TFYkSM+3XHw=
|
||||
k8s.io/apimachinery v0.34.2 h1:zQ12Uk3eMHPxrsbUJgNF8bTauTVR2WgqJsTmwTE/NW4=
|
||||
k8s.io/apimachinery v0.34.2/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw=
|
||||
k8s.io/apiserver v0.34.2 h1:2/yu8suwkmES7IzwlehAovo8dDE07cFRC7KMDb1+MAE=
|
||||
k8s.io/apiserver v0.34.2/go.mod h1:gqJQy2yDOB50R3JUReHSFr+cwJnL8G1dzTA0YLEqAPI=
|
||||
k8s.io/client-go v0.34.2 h1:Co6XiknN+uUZqiddlfAjT68184/37PS4QAzYvQvDR8M=
|
||||
k8s.io/client-go v0.34.2/go.mod h1:2VYDl1XXJsdcAxw7BenFslRQX28Dxz91U9MWKjX97fE=
|
||||
k8s.io/component-base v0.34.2 h1:HQRqK9x2sSAsd8+R4xxRirlTjowsg6fWCPwWYeSvogQ=
|
||||
k8s.io/component-base v0.34.2/go.mod h1:9xw2FHJavUHBFpiGkZoKuYZ5pdtLKe97DEByaA+hHbM=
|
||||
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
|
||||
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
|
||||
k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 h1:Y3gxNAuB0OBLImH611+UDZcmKS3g6CthxToOb37KgwE=
|
||||
|
||||
@@ -154,6 +154,8 @@ FieldConfigSource: {
|
||||
defaults: FieldConfig
|
||||
// Overrides are the options applied to specific fields overriding the defaults.
|
||||
overrides: [...{
|
||||
// Describes config override rules created when interacting with Grafana.
|
||||
"__systemRef"?: string
|
||||
matcher: MatcherConfig
|
||||
properties: [...DynamicConfigValue]
|
||||
}]
|
||||
@@ -247,7 +249,8 @@ MatcherConfig: {
|
||||
}
|
||||
|
||||
Threshold: {
|
||||
value: number
|
||||
// Value null means -Infinity
|
||||
value: number | null
|
||||
color: string
|
||||
}
|
||||
|
||||
|
||||
@@ -156,6 +156,8 @@ FieldConfigSource: {
|
||||
defaults: FieldConfig
|
||||
// Overrides are the options applied to specific fields overriding the defaults.
|
||||
overrides: [...{
|
||||
// Describes config override rules created when interacting with Grafana.
|
||||
"__systemRef"?: string
|
||||
matcher: MatcherConfig
|
||||
properties: [...DynamicConfigValue]
|
||||
}]
|
||||
@@ -249,7 +251,8 @@ MatcherConfig: {
|
||||
}
|
||||
|
||||
Threshold: {
|
||||
value: number
|
||||
// Value null means -Infinity
|
||||
value: number | null
|
||||
color: string
|
||||
}
|
||||
|
||||
@@ -475,7 +478,7 @@ DataQueryKind: {
|
||||
|
||||
PanelQuerySpec: {
|
||||
query: DataQueryKind
|
||||
refId: string
|
||||
refId: string | *"A"
|
||||
hidden: bool
|
||||
}
|
||||
|
||||
@@ -876,7 +879,7 @@ IntervalVariableSpec: {
|
||||
auto: bool | *false
|
||||
auto_min: string | *""
|
||||
auto_count: int | *0
|
||||
refresh: VariableRefresh
|
||||
refresh: "onTimeRangeChanged"
|
||||
label?: string
|
||||
hide: VariableHide
|
||||
skipUrlSync: bool | *false
|
||||
|
||||
@@ -158,6 +158,8 @@ FieldConfigSource: {
|
||||
defaults: FieldConfig
|
||||
// Overrides are the options applied to specific fields overriding the defaults.
|
||||
overrides: [...{
|
||||
// Describes config override rules created when interacting with Grafana.
|
||||
"__systemRef"?: string
|
||||
matcher: MatcherConfig
|
||||
properties: [...DynamicConfigValue]
|
||||
}]
|
||||
@@ -251,7 +253,8 @@ MatcherConfig: {
|
||||
}
|
||||
|
||||
Threshold: {
|
||||
value: number
|
||||
// Value null means -Infinity
|
||||
value: number | null
|
||||
color: string
|
||||
}
|
||||
|
||||
|
||||
@@ -551,8 +551,9 @@ const (
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type DashboardThreshold struct {
|
||||
Value float64 `json:"value"`
|
||||
Color string `json:"color"`
|
||||
// Value null means -Infinity
|
||||
Value *float64 `json:"value"`
|
||||
Color string `json:"color"`
|
||||
}
|
||||
|
||||
// NewDashboardThreshold creates a new DashboardThreshold object.
|
||||
@@ -1865,6 +1866,8 @@ func NewDashboardSpec() *DashboardSpec {
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type DashboardV2alpha1FieldConfigSourceOverrides struct {
|
||||
// Describes config override rules created when interacting with Grafana.
|
||||
SystemRef *string `json:"__systemRef,omitempty"`
|
||||
Matcher DashboardMatcherConfig `json:"matcher"`
|
||||
Properties []DashboardDynamicConfigValue `json:"properties"`
|
||||
}
|
||||
|
||||
@@ -4430,9 +4430,9 @@ func schema_pkg_apis_dashboard_v2alpha1_DashboardThreshold(ref common.ReferenceC
|
||||
Properties: map[string]spec.Schema{
|
||||
"value": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Default: 0,
|
||||
Type: []string{"number"},
|
||||
Format: "double",
|
||||
Description: "Value null means -Infinity",
|
||||
Type: []string{"number"},
|
||||
Format: "double",
|
||||
},
|
||||
},
|
||||
"color": {
|
||||
@@ -4677,6 +4677,13 @@ func schema_pkg_apis_dashboard_v2alpha1_DashboardV2alpha1FieldConfigSourceOverri
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Type: []string{"object"},
|
||||
Properties: map[string]spec.Schema{
|
||||
"__systemRef": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "Describes config override rules created when interacting with Grafana.",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
"matcher": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Default: map[string]interface{}{},
|
||||
|
||||
@@ -67,6 +67,7 @@ API rule violation: names_match,github.com/grafana/grafana/apps/dashboard/pkg/ap
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1,DashboardStringOrArrayOfString,String
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1,DashboardStringOrFloat64,Float64
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1,DashboardStringOrFloat64,String
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1,DashboardV2alpha1FieldConfigSourceOverrides,SystemRef
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1,DashboardValueMapOrRangeMapOrRegexMapOrSpecialValueMap,RangeMap
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1,DashboardValueMapOrRangeMapOrRegexMapOrSpecialValueMap,RegexMap
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1,DashboardValueMapOrRangeMapOrRegexMapOrSpecialValueMap,SpecialValueMap
|
||||
|
||||
@@ -160,6 +160,8 @@ FieldConfigSource: {
|
||||
defaults: FieldConfig
|
||||
// Overrides are the options applied to specific fields overriding the defaults.
|
||||
overrides: [...{
|
||||
// Describes config override rules created when interacting with Grafana.
|
||||
"__systemRef"?: string
|
||||
matcher: MatcherConfig
|
||||
properties: [...DynamicConfigValue]
|
||||
}]
|
||||
@@ -253,7 +255,8 @@ MatcherConfig: {
|
||||
}
|
||||
|
||||
Threshold: {
|
||||
value: number
|
||||
// Value null means -Infinity
|
||||
value: number | null
|
||||
color: string
|
||||
}
|
||||
|
||||
@@ -479,7 +482,7 @@ DataQueryKind: {
|
||||
|
||||
PanelQuerySpec: {
|
||||
query: DataQueryKind
|
||||
refId: string
|
||||
refId: string | *"A"
|
||||
hidden: bool
|
||||
}
|
||||
|
||||
@@ -880,7 +883,7 @@ IntervalVariableSpec: {
|
||||
auto: bool | *false
|
||||
auto_min: string | *""
|
||||
auto_count: int | *0
|
||||
refresh: VariableRefresh
|
||||
refresh: "onTimeRangeChanged"
|
||||
label?: string
|
||||
hide: VariableHide
|
||||
skipUrlSync: bool | *false
|
||||
|
||||
@@ -209,6 +209,7 @@ type DashboardPanelQuerySpec struct {
|
||||
func NewDashboardPanelQuerySpec() *DashboardPanelQuerySpec {
|
||||
return &DashboardPanelQuerySpec{
|
||||
Query: *NewDashboardDataQueryKind(),
|
||||
RefId: "A",
|
||||
}
|
||||
}
|
||||
|
||||
@@ -554,8 +555,9 @@ const (
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type DashboardThreshold struct {
|
||||
Value float64 `json:"value"`
|
||||
Color string `json:"color"`
|
||||
// Value null means -Infinity
|
||||
Value *float64 `json:"value"`
|
||||
Color string `json:"color"`
|
||||
}
|
||||
|
||||
// NewDashboardThreshold creates a new DashboardThreshold object.
|
||||
@@ -1615,7 +1617,7 @@ type DashboardIntervalVariableSpec struct {
|
||||
Auto bool `json:"auto"`
|
||||
AutoMin string `json:"auto_min"`
|
||||
AutoCount int64 `json:"auto_count"`
|
||||
Refresh DashboardVariableRefresh `json:"refresh"`
|
||||
Refresh string `json:"refresh"`
|
||||
Label *string `json:"label,omitempty"`
|
||||
Hide DashboardVariableHide `json:"hide"`
|
||||
SkipUrlSync bool `json:"skipUrlSync"`
|
||||
@@ -1639,7 +1641,7 @@ func NewDashboardIntervalVariableSpec() *DashboardIntervalVariableSpec {
|
||||
Auto: false,
|
||||
AutoMin: "",
|
||||
AutoCount: 0,
|
||||
Refresh: DashboardVariableRefreshNever,
|
||||
Refresh: "onTimeRangeChanged",
|
||||
Hide: DashboardVariableHideDontHide,
|
||||
SkipUrlSync: false,
|
||||
}
|
||||
@@ -1926,6 +1928,8 @@ func NewDashboardV2beta1DataQueryKindDatasource() *DashboardV2beta1DataQueryKind
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type DashboardV2beta1FieldConfigSourceOverrides struct {
|
||||
// Describes config override rules created when interacting with Grafana.
|
||||
SystemRef *string `json:"__systemRef,omitempty"`
|
||||
Matcher DashboardMatcherConfig `json:"matcher"`
|
||||
Properties []DashboardDynamicConfigValue `json:"properties"`
|
||||
}
|
||||
|
||||
@@ -4549,9 +4549,9 @@ func schema_pkg_apis_dashboard_v2beta1_DashboardThreshold(ref common.ReferenceCa
|
||||
Properties: map[string]spec.Schema{
|
||||
"value": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Default: 0,
|
||||
Type: []string{"number"},
|
||||
Format: "double",
|
||||
Description: "Value null means -Infinity",
|
||||
Type: []string{"number"},
|
||||
Format: "double",
|
||||
},
|
||||
},
|
||||
"color": {
|
||||
@@ -4832,6 +4832,13 @@ func schema_pkg_apis_dashboard_v2beta1_DashboardV2beta1FieldConfigSourceOverride
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Type: []string{"object"},
|
||||
Properties: map[string]spec.Schema{
|
||||
"__systemRef": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "Describes config override rules created when interacting with Grafana.",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
"matcher": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Default: map[string]interface{}{},
|
||||
|
||||
@@ -68,6 +68,7 @@ API rule violation: names_match,github.com/grafana/grafana/apps/dashboard/pkg/ap
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2beta1,DashboardStringOrArrayOfString,String
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2beta1,DashboardStringOrFloat64,Float64
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2beta1,DashboardStringOrFloat64,String
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2beta1,DashboardV2beta1FieldConfigSourceOverrides,SystemRef
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2beta1,DashboardValueMapOrRangeMapOrRegexMapOrSpecialValueMap,RangeMap
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2beta1,DashboardValueMapOrRangeMapOrRegexMapOrSpecialValueMap,RegexMap
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2beta1,DashboardValueMapOrRangeMapOrRegexMapOrSpecialValueMap,SpecialValueMap
|
||||
|
||||
@@ -198,7 +198,7 @@ grafana_dashboard_migration_conversion_failure_total{
|
||||
|
||||
### Error Types
|
||||
|
||||
The `error_type` label classifies failures into three categories:
|
||||
The `error_type` label classifies failures into four categories:
|
||||
|
||||
#### 1. `conversion_error`
|
||||
- General conversion failures not related to schema migration
|
||||
@@ -215,6 +215,12 @@ The `error_type` label classifies failures into three categories:
|
||||
- These are logged as warnings rather than errors
|
||||
- Indicates dashboards that cannot be migrated automatically
|
||||
|
||||
#### 4. `conversion_data_loss_error`
|
||||
- Data loss detected during conversion
|
||||
- Automatically checks that panels, queries, annotations, and links are preserved
|
||||
- Triggered when target has fewer items than source
|
||||
- Includes detailed loss metrics in logs (see [Data Loss Detection](#data-loss-detection))
|
||||
|
||||
### Logging
|
||||
|
||||
#### Log structure
|
||||
@@ -236,6 +242,13 @@ All migration logs use structured logging with consistent field names:
|
||||
- `erroredConversionFunc` - Name of the conversion function that failed
|
||||
- `error` - The actual error message
|
||||
|
||||
**Data Loss Fields (conversion_data_loss_error only):**
|
||||
- `panelsLost` - Number of panels lost
|
||||
- `queriesLost` - Number of queries lost
|
||||
- `annotationsLost` - Number of annotations lost
|
||||
- `linksLost` - Number of links lost
|
||||
- `variablesLost` - Number of template variables lost
|
||||
|
||||
#### Log levels
|
||||
|
||||
##### Success (DEBUG level)
|
||||
@@ -285,6 +298,55 @@ All migration logs use structured logging with consistent field names:
|
||||
}
|
||||
```
|
||||
|
||||
##### Data Loss Error (ERROR level)
|
||||
```json
|
||||
{
|
||||
"level": "error",
|
||||
"msg": "Dashboard conversion failed",
|
||||
"sourceVersionAPI": "dashboard.grafana.app/v1beta1",
|
||||
"targetVersionAPI": "dashboard.grafana.app/v2alpha1",
|
||||
"erroredConversionFunc": "V1beta1_to_V2alpha1",
|
||||
"dashboardUID": "abc123",
|
||||
"sourceSchemaVersion": 42,
|
||||
"targetSchemaVersion": 42,
|
||||
"panelsLost": 0,
|
||||
"queriesLost": 2,
|
||||
"annotationsLost": 0,
|
||||
"linksLost": 0,
|
||||
"variablesLost": 0,
|
||||
"errorType": "conversion_data_loss_error",
|
||||
"error": "data loss detected: query count decreased from 7 to 5"
|
||||
}
|
||||
```
|
||||
|
||||
### Data Loss Detection
|
||||
|
||||
**Automatic Runtime Checks:**
|
||||
|
||||
Every conversion automatically detects data loss by comparing:
|
||||
- **Panel count** - Visualization panels (regular + library panels)
|
||||
- **Query count** - Data source queries (excludes invalid row panel queries)
|
||||
- **Annotation count** - Dashboard-level annotations
|
||||
- **Link count** - Navigation links
|
||||
- **Variable count** - Template variables (from `templating.list` in v0/v1, `variables` in v2)
|
||||
|
||||
**Detection Logic:**
|
||||
- ✅ **Allows additions**: Default annotations, enriched data
|
||||
- ❌ **Detects losses**: Any decrease in counts triggers `conversion_data_loss_error`
|
||||
|
||||
**Testing:**
|
||||
|
||||
Run comprehensive data loss tests on all conversion test files:
|
||||
|
||||
```bash
|
||||
# Test all conversions for data loss
|
||||
go test ./apps/dashboard/pkg/migration/conversion/... -run TestDataLossDetectionOnAllInputFiles -v
|
||||
|
||||
# Test shows detailed panel/query analysis when loss is detected
|
||||
```
|
||||
|
||||
**Implementation:** See `conversion/conversion_data_loss_detection.go` and `conversion/README.md` for details.
|
||||
|
||||
### Implementation Details
|
||||
|
||||
#### Automatic instrumentation
|
||||
@@ -293,6 +355,7 @@ All dashboard conversions are automatically instrumented via the `withConversion
|
||||
|
||||
```go
|
||||
// All conversion functions are wrapped automatically
|
||||
// Includes metrics, logging, and data loss detection
|
||||
s.AddConversionFunc((*dashv0.Dashboard)(nil), (*dashv1.Dashboard)(nil),
|
||||
withConversionMetrics(dashv0.APIVERSION, dashv1.APIVERSION, func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convert_V0_to_V1(a.(*dashv0.Dashboard), b.(*dashv1.Dashboard), scope)
|
||||
@@ -319,6 +382,15 @@ type ConversionError struct {
|
||||
currentAPIVersion string
|
||||
targetAPIVersion string
|
||||
}
|
||||
|
||||
// Data loss errors are detected when dashboard components (panels, queries, annotations, links, variables)
|
||||
// are lost during conversion
|
||||
type ConversionDataLossError struct {
|
||||
functionName string // Function where data loss was detected (e.g., "V1_to_V2alpha1")
|
||||
message string // Detailed error message with loss statistics
|
||||
sourceAPIVersion string // Source API version (e.g., "dashboard.grafana.app/v1beta1")
|
||||
targetAPIVersion string // Target API version (e.g., "dashboard.grafana.app/v2alpha1")
|
||||
}
|
||||
```
|
||||
|
||||
### Registration
|
||||
|
||||
@@ -8,25 +8,31 @@ import (
|
||||
dashv1 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v1beta1"
|
||||
dashv2alpha1 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1"
|
||||
dashv2beta1 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2beta1"
|
||||
"github.com/grafana/grafana/apps/dashboard/pkg/migration/schemaversion"
|
||||
)
|
||||
|
||||
func RegisterConversions(s *runtime.Scheme) error {
|
||||
func RegisterConversions(s *runtime.Scheme, dsIndexProvider schemaversion.DataSourceIndexProvider) error {
|
||||
// Wrap the provider once with 10s caching for all conversions.
|
||||
// This prevents repeated DB queries across multiple conversion calls while allowing
|
||||
// the cache to refresh periodically, making it suitable for long-lived singleton usage.
|
||||
dsIndexProvider = schemaversion.WrapIndexProviderWithCache(dsIndexProvider)
|
||||
|
||||
// v0 conversions
|
||||
if err := s.AddConversionFunc((*dashv0.Dashboard)(nil), (*dashv1.Dashboard)(nil),
|
||||
withConversionMetrics(dashv0.APIVERSION, dashv1.APIVERSION, func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convert_V0_to_V1(a.(*dashv0.Dashboard), b.(*dashv1.Dashboard), scope)
|
||||
return Convert_V0_to_V1beta1(a.(*dashv0.Dashboard), b.(*dashv1.Dashboard), scope)
|
||||
})); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.AddConversionFunc((*dashv0.Dashboard)(nil), (*dashv2alpha1.Dashboard)(nil),
|
||||
withConversionMetrics(dashv0.APIVERSION, dashv2alpha1.APIVERSION, func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convert_V0_to_V2alpha1(a.(*dashv0.Dashboard), b.(*dashv2alpha1.Dashboard), scope)
|
||||
return Convert_V0_to_V2alpha1(a.(*dashv0.Dashboard), b.(*dashv2alpha1.Dashboard), scope, dsIndexProvider)
|
||||
})); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.AddConversionFunc((*dashv0.Dashboard)(nil), (*dashv2beta1.Dashboard)(nil),
|
||||
withConversionMetrics(dashv0.APIVERSION, dashv2beta1.APIVERSION, func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convert_V0_to_V2beta1(a.(*dashv0.Dashboard), b.(*dashv2beta1.Dashboard), scope)
|
||||
return Convert_V0_to_V2beta1(a.(*dashv0.Dashboard), b.(*dashv2beta1.Dashboard), scope, dsIndexProvider)
|
||||
})); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -34,19 +40,19 @@ func RegisterConversions(s *runtime.Scheme) error {
|
||||
// v1 conversions
|
||||
if err := s.AddConversionFunc((*dashv1.Dashboard)(nil), (*dashv0.Dashboard)(nil),
|
||||
withConversionMetrics(dashv1.APIVERSION, dashv0.APIVERSION, func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convert_V1_to_V0(a.(*dashv1.Dashboard), b.(*dashv0.Dashboard), scope)
|
||||
return Convert_V1beta1_to_V0(a.(*dashv1.Dashboard), b.(*dashv0.Dashboard), scope)
|
||||
})); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.AddConversionFunc((*dashv1.Dashboard)(nil), (*dashv2alpha1.Dashboard)(nil),
|
||||
withConversionMetrics(dashv1.APIVERSION, dashv2alpha1.APIVERSION, func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convert_V1_to_V2alpha1(a.(*dashv1.Dashboard), b.(*dashv2alpha1.Dashboard), scope)
|
||||
return Convert_V1beta1_to_V2alpha1(a.(*dashv1.Dashboard), b.(*dashv2alpha1.Dashboard), scope, dsIndexProvider)
|
||||
})); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.AddConversionFunc((*dashv1.Dashboard)(nil), (*dashv2beta1.Dashboard)(nil),
|
||||
withConversionMetrics(dashv1.APIVERSION, dashv2beta1.APIVERSION, func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convert_V1_to_V2beta1(a.(*dashv1.Dashboard), b.(*dashv2beta1.Dashboard), scope)
|
||||
return Convert_V1beta1_to_V2beta1(a.(*dashv1.Dashboard), b.(*dashv2beta1.Dashboard), scope, dsIndexProvider)
|
||||
})); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -60,7 +66,7 @@ func RegisterConversions(s *runtime.Scheme) error {
|
||||
}
|
||||
if err := s.AddConversionFunc((*dashv2alpha1.Dashboard)(nil), (*dashv1.Dashboard)(nil),
|
||||
withConversionMetrics(dashv2alpha1.APIVERSION, dashv1.APIVERSION, func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convert_V2alpha1_to_V1(a.(*dashv2alpha1.Dashboard), b.(*dashv1.Dashboard), scope)
|
||||
return Convert_V2alpha1_to_V1beta1(a.(*dashv2alpha1.Dashboard), b.(*dashv1.Dashboard), scope)
|
||||
})); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -80,7 +86,7 @@ func RegisterConversions(s *runtime.Scheme) error {
|
||||
}
|
||||
if err := s.AddConversionFunc((*dashv2beta1.Dashboard)(nil), (*dashv1.Dashboard)(nil),
|
||||
withConversionMetrics(dashv2beta1.APIVERSION, dashv1.APIVERSION, func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convert_V2beta1_to_V1(a.(*dashv2beta1.Dashboard), b.(*dashv1.Dashboard), scope)
|
||||
return Convert_V2beta1_to_V1beta1(a.(*dashv2beta1.Dashboard), b.(*dashv1.Dashboard), scope)
|
||||
})); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -0,0 +1,518 @@
|
||||
package conversion
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"k8s.io/apimachinery/pkg/conversion"
|
||||
|
||||
dashv0 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v0alpha1"
|
||||
dashv1 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v1beta1"
|
||||
dashv2alpha1 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1"
|
||||
dashv2beta1 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2beta1"
|
||||
)
|
||||
|
||||
// Conversion Data Loss Detection Strategy for Dashboard Conversions
|
||||
//
|
||||
// This module implements comprehensive data loss detection to identify when data is lost during
|
||||
// dashboard conversions between different API versions (v0alpha1, v1beta1, v2alpha1, v2beta1).
|
||||
//
|
||||
// # What We Detect
|
||||
//
|
||||
// The data loss detection system checks that critical dashboard components are preserved:
|
||||
//
|
||||
// 1. **Panel Count**: Total number of visualization panels (including library panels)
|
||||
// - Counts regular panels and library panel references
|
||||
// - Excludes row panels (which are layout containers, not visualizations)
|
||||
// - Includes panels nested inside collapsed rows
|
||||
//
|
||||
// 2. **Query Count**: Total number of data source queries across all panels
|
||||
// - Each panel can have multiple queries (targets)
|
||||
// - Queries define what data is fetched and displayed
|
||||
// - Loss of queries means loss of data visualization
|
||||
//
|
||||
// 3. **Annotation Count**: Number of annotation configurations
|
||||
// - Annotations mark events and time ranges on visualizations
|
||||
// - Each annotation can query a datasource for events
|
||||
//
|
||||
// 4. **Dashboard Link Count**: Number of navigation links to other dashboards or URLs
|
||||
// - Links enable dashboard navigation workflows
|
||||
// - Important for dashboard ecosystems
|
||||
|
||||
// ConversionDataLossError represents data loss detected during dashboard conversion
|
||||
type ConversionDataLossError struct {
|
||||
functionName string
|
||||
message string
|
||||
sourceAPIVersion string
|
||||
targetAPIVersion string
|
||||
}
|
||||
|
||||
// NewConversionDataLossError creates a new ConversionDataLossError
|
||||
func NewConversionDataLossError(functionName, message, sourceAPIVersion, targetAPIVersion string) *ConversionDataLossError {
|
||||
return &ConversionDataLossError{
|
||||
functionName: functionName,
|
||||
message: message,
|
||||
sourceAPIVersion: sourceAPIVersion,
|
||||
targetAPIVersion: targetAPIVersion,
|
||||
}
|
||||
}
|
||||
|
||||
// Error implements the error interface
|
||||
func (e *ConversionDataLossError) Error() string {
|
||||
return fmt.Sprintf("data loss detected in %s (%s → %s): %s", e.functionName, e.sourceAPIVersion, e.targetAPIVersion, e.message)
|
||||
}
|
||||
|
||||
// GetFunctionName returns the function name where data loss was detected
|
||||
func (e *ConversionDataLossError) GetFunctionName() string {
|
||||
return e.functionName
|
||||
}
|
||||
|
||||
// GetSourceAPIVersion returns the source API version
|
||||
func (e *ConversionDataLossError) GetSourceAPIVersion() string {
|
||||
return e.sourceAPIVersion
|
||||
}
|
||||
|
||||
// GetTargetAPIVersion returns the target API version
|
||||
func (e *ConversionDataLossError) GetTargetAPIVersion() string {
|
||||
return e.targetAPIVersion
|
||||
}
|
||||
|
||||
// dashboardStats contains statistics about a dashboard for data loss detection
|
||||
type dashboardStats struct {
|
||||
panelCount int
|
||||
queryCount int
|
||||
annotationCount int
|
||||
linkCount int
|
||||
variableCount int
|
||||
}
|
||||
|
||||
// countPanelsV0V1 counts panels in v0alpha1 or v1beta1 dashboard spec (unstructured JSON)
|
||||
func countPanelsV0V1(spec map[string]interface{}) int {
|
||||
if spec == nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
panels, ok := spec["panels"].([]interface{})
|
||||
if !ok {
|
||||
return 0
|
||||
}
|
||||
|
||||
count := 0
|
||||
for _, p := range panels {
|
||||
panelMap, ok := p.(map[string]interface{})
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
// Count regular panels (excluding row panels)
|
||||
panelType, _ := panelMap["type"].(string)
|
||||
if panelType != "row" {
|
||||
count++
|
||||
}
|
||||
|
||||
// Count collapsed panels inside row panels
|
||||
if panelType == "row" {
|
||||
if collapsedPanels, ok := panelMap["panels"].([]interface{}); ok {
|
||||
count += len(collapsedPanels)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return count
|
||||
}
|
||||
|
||||
// countQueriesV0V1 counts data queries in v0alpha1 or v1beta1 dashboard spec
|
||||
// Note: Row panels are layout containers and should not have queries.
|
||||
// We ignore any queries on row panels themselves, but count queries in their collapsed panels.
|
||||
func countQueriesV0V1(spec map[string]interface{}) int {
|
||||
if spec == nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
panels, ok := spec["panels"].([]interface{})
|
||||
if !ok {
|
||||
return 0
|
||||
}
|
||||
|
||||
count := 0
|
||||
for _, p := range panels {
|
||||
panelMap, ok := p.(map[string]interface{})
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
panelType, _ := panelMap["type"].(string)
|
||||
|
||||
// Count queries in regular panels (NOT row panels)
|
||||
if panelType != "row" {
|
||||
if targets, ok := panelMap["targets"].([]interface{}); ok {
|
||||
count += len(targets)
|
||||
}
|
||||
}
|
||||
|
||||
// Count queries in collapsed panels inside row panels
|
||||
if panelType == "row" {
|
||||
if collapsedPanels, ok := panelMap["panels"].([]interface{}); ok {
|
||||
for _, cp := range collapsedPanels {
|
||||
if cpMap, ok := cp.(map[string]interface{}); ok {
|
||||
if targets, ok := cpMap["targets"].([]interface{}); ok {
|
||||
count += len(targets)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return count
|
||||
}
|
||||
|
||||
// countAnnotationsV0V1 counts annotations in v0alpha1 or v1beta1 dashboard spec
|
||||
func countAnnotationsV0V1(spec map[string]interface{}) int {
|
||||
if spec == nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
annotations, ok := spec["annotations"].(map[string]interface{})
|
||||
if !ok {
|
||||
return 0
|
||||
}
|
||||
|
||||
annotationList, ok := annotations["list"].([]interface{})
|
||||
if !ok {
|
||||
return 0
|
||||
}
|
||||
|
||||
return len(annotationList)
|
||||
}
|
||||
|
||||
// countLinksV0V1 counts dashboard links in v0alpha1 or v1beta1 dashboard spec
|
||||
func countLinksV0V1(spec map[string]interface{}) int {
|
||||
if spec == nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
links, ok := spec["links"].([]interface{})
|
||||
if !ok {
|
||||
return 0
|
||||
}
|
||||
|
||||
return len(links)
|
||||
}
|
||||
|
||||
// countVariablesV0V1 counts template variables in v0alpha1 or v1beta1 dashboard spec
|
||||
func countVariablesV0V1(spec map[string]interface{}) int {
|
||||
if spec == nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
templating, ok := spec["templating"].(map[string]interface{})
|
||||
if !ok {
|
||||
return 0
|
||||
}
|
||||
|
||||
variableList, ok := templating["list"].([]interface{})
|
||||
if !ok {
|
||||
return 0
|
||||
}
|
||||
|
||||
return len(variableList)
|
||||
}
|
||||
|
||||
// collectStatsV0V1 collects statistics from v0alpha1 or v1beta1 dashboard
|
||||
func collectStatsV0V1(spec map[string]interface{}) dashboardStats {
|
||||
return dashboardStats{
|
||||
panelCount: countPanelsV0V1(spec),
|
||||
queryCount: countQueriesV0V1(spec),
|
||||
annotationCount: countAnnotationsV0V1(spec),
|
||||
linkCount: countLinksV0V1(spec),
|
||||
variableCount: countVariablesV0V1(spec),
|
||||
}
|
||||
}
|
||||
|
||||
// countPanelsV2 counts panels in v2alpha1 or v2beta1 dashboard spec (structured)
|
||||
func countPanelsV2(elements map[string]dashv2alpha1.DashboardElement) int {
|
||||
count := 0
|
||||
for _, element := range elements {
|
||||
// Check if element is a Panel (not a LibraryPanel)
|
||||
if element.PanelKind != nil {
|
||||
count++
|
||||
} else if element.LibraryPanelKind != nil {
|
||||
count++
|
||||
}
|
||||
}
|
||||
return count
|
||||
}
|
||||
|
||||
// countQueriesV2 counts data queries in v2alpha1 or v2beta1 dashboard spec
|
||||
func countQueriesV2(elements map[string]dashv2alpha1.DashboardElement) int {
|
||||
count := 0
|
||||
for _, element := range elements {
|
||||
if element.PanelKind != nil {
|
||||
count += len(element.PanelKind.Spec.Data.Spec.Queries)
|
||||
}
|
||||
}
|
||||
return count
|
||||
}
|
||||
|
||||
// countAnnotationsV2 counts annotations in v2alpha1 or v2beta1 dashboard spec
|
||||
func countAnnotationsV2(annotations []dashv2alpha1.DashboardAnnotationQueryKind) int {
|
||||
return len(annotations)
|
||||
}
|
||||
|
||||
// countLinksV2 counts dashboard links in v2alpha1 or v2beta1 dashboard spec
|
||||
func countLinksV2(links []dashv2alpha1.DashboardDashboardLink) int {
|
||||
return len(links)
|
||||
}
|
||||
|
||||
// countVariablesV2 counts template variables in v2alpha1 or v2beta1 dashboard spec
|
||||
func countVariablesV2(variables []dashv2alpha1.DashboardVariableKind) int {
|
||||
return len(variables)
|
||||
}
|
||||
|
||||
// collectStatsV2alpha1 collects statistics from v2alpha1 dashboard
|
||||
func collectStatsV2alpha1(spec dashv2alpha1.DashboardSpec) dashboardStats {
|
||||
return dashboardStats{
|
||||
panelCount: countPanelsV2(spec.Elements),
|
||||
queryCount: countQueriesV2(spec.Elements),
|
||||
annotationCount: countAnnotationsV2(spec.Annotations),
|
||||
linkCount: countLinksV2(spec.Links),
|
||||
variableCount: countVariablesV2(spec.Variables),
|
||||
}
|
||||
}
|
||||
|
||||
// countPanelsV2beta1 counts panels in v2beta1 dashboard spec
|
||||
func countPanelsV2beta1(elements map[string]dashv2beta1.DashboardElement) int {
|
||||
count := 0
|
||||
for _, element := range elements {
|
||||
// Check if element is a Panel (not a LibraryPanel)
|
||||
if element.PanelKind != nil {
|
||||
count++
|
||||
} else if element.LibraryPanelKind != nil {
|
||||
count++
|
||||
}
|
||||
}
|
||||
return count
|
||||
}
|
||||
|
||||
// countQueriesV2beta1 counts data queries in v2beta1 dashboard spec
|
||||
func countQueriesV2beta1(elements map[string]dashv2beta1.DashboardElement) int {
|
||||
count := 0
|
||||
for _, element := range elements {
|
||||
if element.PanelKind != nil {
|
||||
count += len(element.PanelKind.Spec.Data.Spec.Queries)
|
||||
}
|
||||
}
|
||||
return count
|
||||
}
|
||||
|
||||
// countAnnotationsV2beta1 counts annotations in v2beta1 dashboard spec
|
||||
func countAnnotationsV2beta1(annotations []dashv2beta1.DashboardAnnotationQueryKind) int {
|
||||
return len(annotations)
|
||||
}
|
||||
|
||||
// countLinksV2beta1 counts dashboard links in v2beta1 dashboard spec
|
||||
func countLinksV2beta1(links []dashv2beta1.DashboardDashboardLink) int {
|
||||
return len(links)
|
||||
}
|
||||
|
||||
// countVariablesV2beta1 counts template variables in v2beta1 dashboard spec
|
||||
func countVariablesV2beta1(variables []dashv2beta1.DashboardVariableKind) int {
|
||||
return len(variables)
|
||||
}
|
||||
|
||||
// collectStatsV2beta1 collects statistics from v2beta1 dashboard
|
||||
func collectStatsV2beta1(spec dashv2beta1.DashboardSpec) dashboardStats {
|
||||
return dashboardStats{
|
||||
panelCount: countPanelsV2beta1(spec.Elements),
|
||||
queryCount: countQueriesV2beta1(spec.Elements),
|
||||
annotationCount: countAnnotationsV2beta1(spec.Annotations),
|
||||
linkCount: countLinksV2beta1(spec.Links),
|
||||
variableCount: countVariablesV2beta1(spec.Variables),
|
||||
}
|
||||
}
|
||||
|
||||
// detectConversionDataLoss detects if critical dashboard data was lost during conversion
|
||||
// Note: We only check for DATA LOSS (target < source), not additions (target > source).
|
||||
// Conversions may add default values (like built-in annotations) which is expected behavior.
|
||||
func detectConversionDataLoss(sourceStats, targetStats dashboardStats, sourceFuncName, targetFuncName string) error {
|
||||
var errors []string
|
||||
|
||||
// Panel count: detect loss only (target < source)
|
||||
if targetStats.panelCount < sourceStats.panelCount {
|
||||
errors = append(errors, fmt.Sprintf(
|
||||
"panel count decreased: source=%d, target=%d (loss of %d panels)",
|
||||
sourceStats.panelCount,
|
||||
targetStats.panelCount,
|
||||
sourceStats.panelCount-targetStats.panelCount,
|
||||
))
|
||||
}
|
||||
|
||||
// Query count: detect loss only (target < source)
|
||||
if targetStats.queryCount < sourceStats.queryCount {
|
||||
errors = append(errors, fmt.Sprintf(
|
||||
"query count decreased: source=%d, target=%d (loss of %d queries)",
|
||||
sourceStats.queryCount,
|
||||
targetStats.queryCount,
|
||||
sourceStats.queryCount-targetStats.queryCount,
|
||||
))
|
||||
}
|
||||
|
||||
// Annotation count: detect loss only (target < source)
|
||||
// Note: Conversions may add default annotations, so additions are allowed
|
||||
if targetStats.annotationCount < sourceStats.annotationCount {
|
||||
errors = append(errors, fmt.Sprintf(
|
||||
"annotation count decreased: source=%d, target=%d (loss of %d annotations)",
|
||||
sourceStats.annotationCount,
|
||||
targetStats.annotationCount,
|
||||
sourceStats.annotationCount-targetStats.annotationCount,
|
||||
))
|
||||
}
|
||||
|
||||
// Dashboard link count: detect loss only (target < source)
|
||||
if targetStats.linkCount < sourceStats.linkCount {
|
||||
errors = append(errors, fmt.Sprintf(
|
||||
"dashboard link count decreased: source=%d, target=%d (loss of %d links)",
|
||||
sourceStats.linkCount,
|
||||
targetStats.linkCount,
|
||||
sourceStats.linkCount-targetStats.linkCount,
|
||||
))
|
||||
}
|
||||
|
||||
// Variable count: detect loss only (target < source)
|
||||
if targetStats.variableCount < sourceStats.variableCount {
|
||||
errors = append(errors, fmt.Sprintf(
|
||||
"variable count decreased: source=%d, target=%d (loss of %d variables)",
|
||||
sourceStats.variableCount,
|
||||
targetStats.variableCount,
|
||||
sourceStats.variableCount-targetStats.variableCount,
|
||||
))
|
||||
}
|
||||
|
||||
if len(errors) > 0 {
|
||||
errorMsg := fmt.Sprintf("%v", errors)
|
||||
// Note: sourceAPIVersion and targetAPIVersion are passed from checkConversionDataLoss
|
||||
// For now, use empty strings - they will be set by the caller
|
||||
return NewConversionDataLossError(fmt.Sprintf("%s_to_%s", sourceFuncName, targetFuncName), errorMsg, "", "")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// checkConversionDataLoss is the data loss check function that can be passed to withConversionMetrics
|
||||
// It collects statistics from source and target dashboards and detects if data was lost
|
||||
// Returns a ConversionDataLossError if data loss is detected, nil otherwise
|
||||
func checkConversionDataLoss(sourceVersionAPI, targetVersionAPI string, a, b interface{}) error {
|
||||
// Collect source statistics
|
||||
sourceStats := collectDashboardStats(a)
|
||||
|
||||
// Collect target statistics
|
||||
targetStats := collectDashboardStats(b)
|
||||
|
||||
// Detect if data was lost
|
||||
err := detectConversionDataLoss(sourceStats, targetStats, convertAPIVersionToFuncName(sourceVersionAPI), convertAPIVersionToFuncName(targetVersionAPI))
|
||||
|
||||
// If data loss was detected, update the error with API versions
|
||||
if err != nil {
|
||||
var dataLossErr *ConversionDataLossError
|
||||
if errors.As(err, &dataLossErr) {
|
||||
dataLossErr.sourceAPIVersion = sourceVersionAPI
|
||||
dataLossErr.targetAPIVersion = targetVersionAPI
|
||||
}
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// collectDashboardStats collects statistics from a dashboard object (any version)
|
||||
func collectDashboardStats(dashboard interface{}) dashboardStats {
|
||||
switch d := dashboard.(type) {
|
||||
case *dashv0.Dashboard:
|
||||
if d.Spec.Object != nil {
|
||||
return collectStatsV0V1(d.Spec.Object)
|
||||
}
|
||||
case *dashv1.Dashboard:
|
||||
if d.Spec.Object != nil {
|
||||
return collectStatsV0V1(d.Spec.Object)
|
||||
}
|
||||
case *dashv2alpha1.Dashboard:
|
||||
return collectStatsV2alpha1(d.Spec)
|
||||
case *dashv2beta1.Dashboard:
|
||||
return collectStatsV2beta1(d.Spec)
|
||||
}
|
||||
return dashboardStats{}
|
||||
}
|
||||
|
||||
// withConversionDataLossDetection wraps a conversion function to detect data loss
|
||||
func withConversionDataLossDetection(sourceFuncName, targetFuncName string, conversionFunc func(a, b interface{}, scope conversion.Scope) error) func(a, b interface{}, scope conversion.Scope) error {
|
||||
return func(a, b interface{}, scope conversion.Scope) error {
|
||||
// Collect source statistics
|
||||
var sourceStats dashboardStats
|
||||
switch source := a.(type) {
|
||||
case *dashv0.Dashboard:
|
||||
if source.Spec.Object != nil {
|
||||
sourceStats = collectStatsV0V1(source.Spec.Object)
|
||||
}
|
||||
case *dashv1.Dashboard:
|
||||
if source.Spec.Object != nil {
|
||||
sourceStats = collectStatsV0V1(source.Spec.Object)
|
||||
}
|
||||
case *dashv2alpha1.Dashboard:
|
||||
sourceStats = collectStatsV2alpha1(source.Spec)
|
||||
case *dashv2beta1.Dashboard:
|
||||
sourceStats = collectStatsV2beta1(source.Spec)
|
||||
}
|
||||
|
||||
// Execute the conversion
|
||||
err := conversionFunc(a, b, scope)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Collect target statistics
|
||||
var targetStats dashboardStats
|
||||
switch target := b.(type) {
|
||||
case *dashv0.Dashboard:
|
||||
if target.Spec.Object != nil {
|
||||
targetStats = collectStatsV0V1(target.Spec.Object)
|
||||
}
|
||||
case *dashv1.Dashboard:
|
||||
if target.Spec.Object != nil {
|
||||
targetStats = collectStatsV0V1(target.Spec.Object)
|
||||
}
|
||||
case *dashv2alpha1.Dashboard:
|
||||
targetStats = collectStatsV2alpha1(target.Spec)
|
||||
case *dashv2beta1.Dashboard:
|
||||
targetStats = collectStatsV2beta1(target.Spec)
|
||||
}
|
||||
|
||||
// Detect if data was lost
|
||||
if dataLossErr := detectConversionDataLoss(sourceStats, targetStats, sourceFuncName, targetFuncName); dataLossErr != nil {
|
||||
logger.Error("Dashboard conversion data loss detected",
|
||||
"sourceFunc", sourceFuncName,
|
||||
"targetFunc", targetFuncName,
|
||||
"sourcePanels", sourceStats.panelCount,
|
||||
"targetPanels", targetStats.panelCount,
|
||||
"sourceQueries", sourceStats.queryCount,
|
||||
"targetQueries", targetStats.queryCount,
|
||||
"sourceAnnotations", sourceStats.annotationCount,
|
||||
"targetAnnotations", targetStats.annotationCount,
|
||||
"sourceLinks", sourceStats.linkCount,
|
||||
"targetLinks", targetStats.linkCount,
|
||||
"error", dataLossErr,
|
||||
)
|
||||
return dataLossErr
|
||||
}
|
||||
|
||||
logger.Debug("Dashboard conversion completed without data loss",
|
||||
"sourceFunc", sourceFuncName,
|
||||
"targetFunc", targetFuncName,
|
||||
"panels", targetStats.panelCount,
|
||||
"queries", targetStats.queryCount,
|
||||
"annotations", targetStats.annotationCount,
|
||||
"links", targetStats.linkCount,
|
||||
)
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -3,6 +3,7 @@ package conversion
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"os"
|
||||
@@ -31,7 +32,8 @@ import (
|
||||
|
||||
func TestConversionMatrixExist(t *testing.T) {
|
||||
// Initialize the migrator with a test data source provider
|
||||
migration.Initialize(migrationtestutil.NewDataSourceProvider(migrationtestutil.StandardTestConfig))
|
||||
dsProvider := migrationtestutil.NewDataSourceProvider(migrationtestutil.StandardTestConfig)
|
||||
migration.Initialize(dsProvider)
|
||||
|
||||
versions := []metav1.Object{
|
||||
&dashv0.Dashboard{Spec: common.Unstructured{Object: map[string]any{"title": "dashboardV0"}}},
|
||||
@@ -41,7 +43,7 @@ func TestConversionMatrixExist(t *testing.T) {
|
||||
}
|
||||
|
||||
scheme := runtime.NewScheme()
|
||||
err := RegisterConversions(scheme)
|
||||
err := RegisterConversions(scheme, dsProvider)
|
||||
require.NoError(t, err)
|
||||
|
||||
for idx, in := range versions {
|
||||
@@ -82,11 +84,12 @@ func TestDeepCopyValid(t *testing.T) {
|
||||
|
||||
func TestDashboardConversionToAllVersions(t *testing.T) {
|
||||
// Initialize the migrator with a test data source provider
|
||||
migration.Initialize(migrationtestutil.NewDataSourceProvider(migrationtestutil.StandardTestConfig))
|
||||
dsProvider := migrationtestutil.NewDataSourceProvider(migrationtestutil.StandardTestConfig)
|
||||
migration.Initialize(dsProvider)
|
||||
|
||||
// Set up conversion scheme
|
||||
scheme := runtime.NewScheme()
|
||||
err := RegisterConversions(scheme)
|
||||
err := RegisterConversions(scheme, dsProvider)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Read all files from input directory
|
||||
@@ -120,6 +123,17 @@ func TestDashboardConversionToAllVersions(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, dashv0.GROUP, gv.Group)
|
||||
|
||||
// Validate that the input file starts with the apiVersion declared in the object
|
||||
expectedPrefix := fmt.Sprintf("%s.", gv.Version)
|
||||
if !strings.HasPrefix(file.Name(), expectedPrefix) {
|
||||
t.Fatalf(
|
||||
"Input file %s does not match its declared apiVersion %s. "+
|
||||
"Expected filename to start with \"%s\". "+
|
||||
"Example: if apiVersion is \"dashboard.grafana.app/v1beta1\", "+
|
||||
"filename should start with \"v1beta1.<descriptive-name>.json\"",
|
||||
file.Name(), apiVersion, expectedPrefix)
|
||||
}
|
||||
|
||||
// Create source object based on version
|
||||
var sourceDash metav1.Object
|
||||
switch gv.Version {
|
||||
@@ -199,6 +213,135 @@ func TestDashboardConversionToAllVersions(t *testing.T) {
|
||||
|
||||
// Convert to target version
|
||||
err = scheme.Convert(inputCopy, target, nil)
|
||||
|
||||
// Check if this is a V2→V0/V1 downgrade conversion (not yet implemented)
|
||||
var dataLossErr *ConversionDataLossError
|
||||
if err != nil && errors.As(err, &dataLossErr) {
|
||||
// Check if this is a V2 downgrade
|
||||
if strings.HasPrefix(gv.Version, "v2") &&
|
||||
(strings.Contains(filename, "v0alpha1") || strings.Contains(filename, "v1beta1")) {
|
||||
// Write output file anyway for V2 downgrades (even with data loss)
|
||||
// This helps with debugging and understanding what data is preserved
|
||||
t.Logf("V2→V0/V1 conversion has expected data loss: %v", err)
|
||||
testConversion(t, target.(metav1.Object), filename, outDir)
|
||||
t.Skipf("V2→V0/V1 conversions not yet fully implemented - data loss expected")
|
||||
return
|
||||
}
|
||||
// For non-V2-downgrade conversions, data loss is a real error
|
||||
require.NoError(t, err, "Conversion failed for %s", filename)
|
||||
}
|
||||
|
||||
// Test the changes in the conversion result
|
||||
testConversion(t, target.(metav1.Object), filename, outDir)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestMigratedDashboardsConversion tests conversion of already-migrated dashboards
|
||||
// from the migration package's latest_version output directory
|
||||
func TestMigratedDashboardsConversion(t *testing.T) {
|
||||
// Initialize the migrator with a test data source provider
|
||||
dsProvider := migrationtestutil.NewDataSourceProvider(migrationtestutil.StandardTestConfig)
|
||||
migration.Initialize(dsProvider)
|
||||
|
||||
// Set up conversion scheme
|
||||
scheme := runtime.NewScheme()
|
||||
err := RegisterConversions(scheme, dsProvider)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Read all files from migration package's latest_version directory
|
||||
inputDir := filepath.Join("..", "testdata", "output", "latest_version")
|
||||
files, err := os.ReadDir(inputDir)
|
||||
require.NoError(t, err, "Failed to read latest_version directory")
|
||||
|
||||
for _, file := range files {
|
||||
if file.IsDir() {
|
||||
continue
|
||||
}
|
||||
|
||||
t.Run(fmt.Sprintf("Convert_%s", file.Name()), func(t *testing.T) {
|
||||
// Read input dashboard file
|
||||
inputFile := filepath.Join(inputDir, file.Name())
|
||||
// ignore gosec G304 as this function is only used in the test process
|
||||
//nolint:gosec
|
||||
inputData, err := os.ReadFile(inputFile)
|
||||
require.NoError(t, err, "Failed to read input file")
|
||||
|
||||
// Parse the raw dashboard JSON
|
||||
var rawDash map[string]interface{}
|
||||
err = json.Unmarshal(inputData, &rawDash)
|
||||
require.NoError(t, err, "Failed to unmarshal dashboard JSON")
|
||||
|
||||
// These files are from the old migration system and are raw dashboard JSON
|
||||
// We need to wrap them in the proper v1beta1 API structure
|
||||
sourceDash := &dashv1.Dashboard{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "Dashboard",
|
||||
APIVersion: dashv1.APIVERSION,
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: strings.TrimSuffix(file.Name(), ".json"),
|
||||
},
|
||||
Spec: common.Unstructured{Object: rawDash},
|
||||
}
|
||||
|
||||
// Ensure output directory exists
|
||||
outDir := filepath.Join("testdata", "migrated_dashboards_output")
|
||||
// ignore gosec G301 as this function is only used in the test process
|
||||
//nolint:gosec
|
||||
err = os.MkdirAll(outDir, 0755)
|
||||
require.NoError(t, err, "Failed to create output directory")
|
||||
|
||||
// Get target versions from the dashboard manifest
|
||||
manifest := apis.LocalManifest()
|
||||
targetVersions := make(map[string]runtime.Object)
|
||||
|
||||
// Get original filename without extension
|
||||
originalName := strings.TrimSuffix(file.Name(), ".json")
|
||||
|
||||
// Get all Dashboard versions from the manifest
|
||||
for _, kind := range manifest.ManifestData.Kinds() {
|
||||
if kind.Kind == "Dashboard" {
|
||||
for _, version := range kind.Versions {
|
||||
// Skip v1beta1 since that's our source version
|
||||
if version.VersionName == "v1beta1" {
|
||||
continue
|
||||
}
|
||||
|
||||
// Prefix with v1beta1-mig- to indicate these came from v1beta1 dashboards
|
||||
// that went through the migration pipeline
|
||||
filename := fmt.Sprintf("v1beta1-mig-%s.%s.json", originalName, version.VersionName)
|
||||
typeMeta := metav1.TypeMeta{
|
||||
APIVersion: fmt.Sprintf("%s/%s", dashv0.APIGroup, version.VersionName),
|
||||
Kind: kind.Kind, // Dashboard
|
||||
}
|
||||
|
||||
// Create target object based on version
|
||||
switch version.VersionName {
|
||||
case "v0alpha1":
|
||||
targetVersions[filename] = &dashv0.Dashboard{TypeMeta: typeMeta}
|
||||
case "v2alpha1":
|
||||
targetVersions[filename] = &dashv2alpha1.Dashboard{TypeMeta: typeMeta}
|
||||
case "v2beta1":
|
||||
targetVersions[filename] = &dashv2beta1.Dashboard{TypeMeta: typeMeta}
|
||||
default:
|
||||
t.Logf("Unknown version %s, skipping", version.VersionName)
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Convert to each target version
|
||||
for filename, target := range targetVersions {
|
||||
t.Run(fmt.Sprintf("Convert_to_%s", filename), func(t *testing.T) {
|
||||
// Create a copy of the input dashboard for conversion
|
||||
inputCopy := sourceDash.DeepCopyObject()
|
||||
|
||||
// Convert to target version
|
||||
err := scheme.Convert(inputCopy, target, nil)
|
||||
require.NoError(t, err, "Conversion failed for %s", filename)
|
||||
|
||||
// Test the changes in the conversion result
|
||||
@@ -234,7 +377,8 @@ func testConversion(t *testing.T, convertedDash metav1.Object, filename, outputD
|
||||
// TestConversionMetrics tests that conversion-level metrics are recorded correctly
|
||||
func TestConversionMetrics(t *testing.T) {
|
||||
// Initialize migration with test providers
|
||||
migration.Initialize(migrationtestutil.NewDataSourceProvider(migrationtestutil.StandardTestConfig))
|
||||
dsProvider := migrationtestutil.NewDataSourceProvider(migrationtestutil.StandardTestConfig)
|
||||
migration.Initialize(dsProvider)
|
||||
|
||||
// Create a test registry for metrics
|
||||
registry := prometheus.NewRegistry()
|
||||
@@ -242,7 +386,7 @@ func TestConversionMetrics(t *testing.T) {
|
||||
|
||||
// Set up conversion scheme
|
||||
scheme := runtime.NewScheme()
|
||||
err := RegisterConversions(scheme)
|
||||
err := RegisterConversions(scheme, dsProvider)
|
||||
require.NoError(t, err)
|
||||
|
||||
tests := []struct {
|
||||
@@ -264,6 +408,7 @@ func TestConversionMetrics(t *testing.T) {
|
||||
Spec: common.Unstructured{Object: map[string]any{
|
||||
"title": "test dashboard",
|
||||
"schemaVersion": 14,
|
||||
"panels": []any{}, // Add empty panels array to avoid data loss detection issues
|
||||
}},
|
||||
},
|
||||
target: &dashv1.Dashboard{},
|
||||
@@ -281,6 +426,7 @@ func TestConversionMetrics(t *testing.T) {
|
||||
Spec: common.Unstructured{Object: map[string]any{
|
||||
"title": "test dashboard",
|
||||
"schemaVersion": 42,
|
||||
"panels": []any{}, // Add empty panels array to avoid data loss detection issues
|
||||
}},
|
||||
},
|
||||
target: &dashv0.Dashboard{},
|
||||
@@ -295,7 +441,12 @@ func TestConversionMetrics(t *testing.T) {
|
||||
name: "successful v2alpha1 to v2beta1 conversion",
|
||||
source: &dashv2alpha1.Dashboard{
|
||||
ObjectMeta: metav1.ObjectMeta{UID: "test-uid-3"},
|
||||
Spec: dashv2alpha1.DashboardSpec{Title: "test dashboard"},
|
||||
Spec: dashv2alpha1.DashboardSpec{
|
||||
Title: "test dashboard",
|
||||
Elements: map[string]dashv2alpha1.DashboardElement{}, // Add empty elements
|
||||
Annotations: []dashv2alpha1.DashboardAnnotationQueryKind{},
|
||||
Links: []dashv2alpha1.DashboardDashboardLink{},
|
||||
},
|
||||
},
|
||||
target: &dashv2beta1.Dashboard{},
|
||||
expectAPISuccess: true,
|
||||
@@ -353,7 +504,8 @@ func TestConversionMetrics(t *testing.T) {
|
||||
|
||||
// TestConversionMetricsWrapper tests the withConversionMetrics wrapper function
|
||||
func TestConversionMetricsWrapper(t *testing.T) {
|
||||
migration.Initialize(migrationtestutil.NewDataSourceProvider(migrationtestutil.StandardTestConfig))
|
||||
dsProvider := migrationtestutil.NewDataSourceProvider(migrationtestutil.StandardTestConfig)
|
||||
migration.Initialize(dsProvider)
|
||||
|
||||
// Create a test registry for metrics
|
||||
registry := prometheus.NewRegistry()
|
||||
@@ -377,11 +529,18 @@ func TestConversionMetricsWrapper(t *testing.T) {
|
||||
Spec: common.Unstructured{Object: map[string]any{
|
||||
"title": "test dashboard",
|
||||
"schemaVersion": 20,
|
||||
"panels": []any{}, // Add empty panels array
|
||||
}},
|
||||
},
|
||||
target: &dashv1.Dashboard{},
|
||||
conversionFunction: func(a, b interface{}, scope conversion.Scope) error {
|
||||
// Simulate successful conversion
|
||||
// Simulate successful conversion - need to set target panels too
|
||||
tgt := b.(*dashv1.Dashboard)
|
||||
tgt.Spec = common.Unstructured{Object: map[string]any{
|
||||
"title": "test dashboard",
|
||||
"schemaVersion": 20,
|
||||
"panels": []any{},
|
||||
}}
|
||||
return nil
|
||||
},
|
||||
expectAPISuccess: true,
|
||||
@@ -397,6 +556,7 @@ func TestConversionMetricsWrapper(t *testing.T) {
|
||||
Spec: common.Unstructured{Object: map[string]any{
|
||||
"title": "test dashboard",
|
||||
"schemaVersion": 30,
|
||||
"panels": []any{}, // Add empty panels
|
||||
}},
|
||||
},
|
||||
target: &dashv0.Dashboard{},
|
||||
@@ -404,8 +564,8 @@ func TestConversionMetricsWrapper(t *testing.T) {
|
||||
// Simulate conversion failure
|
||||
return fmt.Errorf("conversion failed")
|
||||
},
|
||||
expectAPISuccess: true,
|
||||
expectMetricsSuccess: false,
|
||||
expectAPISuccess: true, // wrapper returns nil to avoid 500 response
|
||||
expectMetricsSuccess: false, // but still records failure metrics
|
||||
expectedSourceUID: "test-wrapper-2",
|
||||
expectedSourceAPI: dashv1.APIVERSION,
|
||||
expectedTargetAPI: dashv0.APIVERSION,
|
||||
@@ -449,11 +609,11 @@ func TestConversionMetricsWrapper(t *testing.T) {
|
||||
}
|
||||
|
||||
if tt.expectAPISuccess && tt.expectMetricsSuccess {
|
||||
require.Equal(t, float64(1), successTotal, "success metric should be incremented")
|
||||
require.GreaterOrEqual(t, successTotal, float64(1), "success metric should be incremented")
|
||||
require.Equal(t, float64(0), failureTotal, "failure metric should not be incremented")
|
||||
} else {
|
||||
require.Equal(t, float64(0), successTotal, "success metric should not be incremented")
|
||||
require.Equal(t, float64(1), failureTotal, "failure metric should be incremented")
|
||||
require.GreaterOrEqual(t, failureTotal, float64(1), "failure metric should be incremented")
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -512,7 +672,8 @@ func TestSchemaVersionExtraction(t *testing.T) {
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
// Test the schema version extraction logic by creating a wrapper and checking the metrics labels
|
||||
migration.Initialize(migrationtestutil.NewDataSourceProvider(migrationtestutil.StandardTestConfig))
|
||||
dsProvider := migrationtestutil.NewDataSourceProvider(migrationtestutil.StandardTestConfig)
|
||||
migration.Initialize(dsProvider)
|
||||
|
||||
// Create a test registry for metrics
|
||||
registry := prometheus.NewRegistry()
|
||||
@@ -555,7 +716,8 @@ func TestSchemaVersionExtraction(t *testing.T) {
|
||||
|
||||
// TestConversionLogging tests that conversion-level logging works correctly
|
||||
func TestConversionLogging(t *testing.T) {
|
||||
migration.Initialize(migrationtestutil.NewDataSourceProvider(migrationtestutil.StandardTestConfig))
|
||||
dsProvider := migrationtestutil.NewDataSourceProvider(migrationtestutil.StandardTestConfig)
|
||||
migration.Initialize(dsProvider)
|
||||
|
||||
// Create a test registry for metrics
|
||||
registry := prometheus.NewRegistry()
|
||||
@@ -563,7 +725,7 @@ func TestConversionLogging(t *testing.T) {
|
||||
|
||||
// Set up conversion scheme
|
||||
scheme := runtime.NewScheme()
|
||||
err := RegisterConversions(scheme)
|
||||
err := RegisterConversions(scheme, dsProvider)
|
||||
require.NoError(t, err)
|
||||
|
||||
tests := []struct {
|
||||
@@ -645,7 +807,8 @@ func TestConversionLogging(t *testing.T) {
|
||||
|
||||
// TestConversionLogLevels tests that appropriate log levels are used
|
||||
func TestConversionLogLevels(t *testing.T) {
|
||||
migration.Initialize(migrationtestutil.NewDataSourceProvider(migrationtestutil.StandardTestConfig))
|
||||
dsProvider := migrationtestutil.NewDataSourceProvider(migrationtestutil.StandardTestConfig)
|
||||
migration.Initialize(dsProvider)
|
||||
|
||||
t.Run("log levels and structured fields verification", func(t *testing.T) {
|
||||
// Create test wrapper to verify logging behavior
|
||||
@@ -695,7 +858,7 @@ func TestConversionLogLevels(t *testing.T) {
|
||||
target2 := &dashv0.Dashboard{}
|
||||
|
||||
err = failureWrapper(source2, target2, nil)
|
||||
require.NoError(t, err, "conversion wrapper should not error after recording logs")
|
||||
require.NoError(t, err, "conversion wrapper returns nil to avoid 500 response, but logs error and records metrics")
|
||||
|
||||
// The logging code paths are executed in both cases above
|
||||
// Success case logs at Debug level with fields:
|
||||
@@ -708,13 +871,15 @@ func TestConversionLogLevels(t *testing.T) {
|
||||
t.Log("✓ Failure logging uses Error level")
|
||||
t.Log("✓ All structured fields included in log messages")
|
||||
t.Log("✓ Dashboard UID extraction works for different dashboard types")
|
||||
t.Log("✓ Wrapper returns nil to avoid 500 response even on errors")
|
||||
t.Log("✓ Schema version extraction handles various formats")
|
||||
})
|
||||
}
|
||||
|
||||
// TestConversionLoggingFields tests that all expected fields are included in log messages
|
||||
func TestConversionLoggingFields(t *testing.T) {
|
||||
migration.Initialize(migrationtestutil.NewDataSourceProvider(migrationtestutil.StandardTestConfig))
|
||||
dsProvider := migrationtestutil.NewDataSourceProvider(migrationtestutil.StandardTestConfig)
|
||||
migration.Initialize(dsProvider)
|
||||
|
||||
t.Run("verify all log fields are present", func(t *testing.T) {
|
||||
// Test that the conversion wrapper includes all expected structured fields
|
||||
|
||||
@@ -3,6 +3,7 @@ package conversion
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"strings"
|
||||
|
||||
"k8s.io/apimachinery/pkg/conversion"
|
||||
@@ -39,6 +40,11 @@ func getErroredConversionFunc(err error) string {
|
||||
return migrationErr.GetFunctionName()
|
||||
}
|
||||
|
||||
var dataLossErr *ConversionDataLossError
|
||||
if errors.As(err, &dataLossErr) {
|
||||
return dataLossErr.GetFunctionName()
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
@@ -65,6 +71,7 @@ func convertAPIVersionToFuncName(apiVersion string) string {
|
||||
}
|
||||
|
||||
// withConversionMetrics wraps a conversion function with metrics and logging for the overall conversion process
|
||||
// It optionally runs a data loss check function after successful conversion
|
||||
func withConversionMetrics(sourceVersionAPI, targetVersionAPI string, conversionFunc func(a, b interface{}, scope conversion.Scope) error) func(a, b interface{}, scope conversion.Scope) error {
|
||||
return func(a, b interface{}, scope conversion.Scope) error {
|
||||
// Extract dashboard UID and schema version from source
|
||||
@@ -113,16 +120,24 @@ func withConversionMetrics(sourceVersionAPI, targetVersionAPI string, conversion
|
||||
// Execute the actual conversion
|
||||
err := conversionFunc(a, b, scope)
|
||||
|
||||
// If conversion succeeded, run data loss check
|
||||
if err == nil {
|
||||
err = checkConversionDataLoss(sourceVersionAPI, targetVersionAPI, a, b)
|
||||
}
|
||||
|
||||
// Report conversion-level metrics and logs
|
||||
if err != nil {
|
||||
// Classify error type for metrics
|
||||
errorType := "conversion_error"
|
||||
var migrationErr *schemaversion.MigrationError
|
||||
var minVersionErr *schemaversion.MinimumVersionError
|
||||
var dataLossErr *ConversionDataLossError
|
||||
if errors.As(err, &migrationErr) {
|
||||
errorType = "schema_version_migration_error"
|
||||
} else if errors.As(err, &minVersionErr) {
|
||||
errorType = "schema_minimum_version_error"
|
||||
} else if errors.As(err, &dataLossErr) {
|
||||
errorType = "conversion_data_loss_error"
|
||||
}
|
||||
|
||||
// Record failure metrics
|
||||
@@ -161,6 +176,20 @@ func withConversionMetrics(sourceVersionAPI, targetVersionAPI string, conversion
|
||||
)
|
||||
}
|
||||
|
||||
// Add data loss specific fields if this is a data loss error
|
||||
if errorType == "conversion_data_loss_error" {
|
||||
sourceStats := collectDashboardStats(a)
|
||||
targetStats := collectDashboardStats(b)
|
||||
// We consider losing data when the target is less than the source
|
||||
logFields = append(logFields,
|
||||
"panelsLost", math.Max(0, float64(sourceStats.panelCount-targetStats.panelCount)),
|
||||
"queriesLost", math.Max(0, float64(sourceStats.queryCount-targetStats.queryCount)),
|
||||
"annotationsLost", math.Max(0, float64(sourceStats.annotationCount-targetStats.annotationCount)),
|
||||
"linksLost", math.Max(0, float64(sourceStats.linkCount-targetStats.linkCount)),
|
||||
"variablesLost", math.Max(0, float64(sourceStats.variableCount-targetStats.variableCount)),
|
||||
)
|
||||
}
|
||||
|
||||
// Add remaining fields
|
||||
logFields = append(logFields,
|
||||
"errorType", errorType,
|
||||
|
||||
217
apps/dashboard/pkg/migration/conversion/testdata/input/v1beta1.annotation-conversions.json
vendored
Normal file
217
apps/dashboard/pkg/migration/conversion/testdata/input/v1beta1.annotation-conversions.json
vendored
Normal file
@@ -0,0 +1,217 @@
|
||||
{
|
||||
"kind": "Dashboard",
|
||||
"apiVersion": "dashboard.grafana.app/v1beta1",
|
||||
"metadata": {
|
||||
"name": "annotation-conversions-test",
|
||||
"labels": {
|
||||
"test": "annotation-conversions"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"title": "Annotation Conversions Test Dashboard",
|
||||
"description": "Testing annotation transformations",
|
||||
"tags": ["test", "annotations"],
|
||||
"annotations": {
|
||||
"list": [
|
||||
{
|
||||
"builtIn": 1,
|
||||
"datasource": {
|
||||
"type": "grafana",
|
||||
"uid": "-- Grafana --"
|
||||
},
|
||||
"enable": true,
|
||||
"hide": false,
|
||||
"iconColor": "rgba(0, 211, 255, 1)",
|
||||
"name": "Annotations & Alerts",
|
||||
"target": {
|
||||
"limit": 100,
|
||||
"matchAny": false,
|
||||
"tags": [],
|
||||
"type": "dashboard"
|
||||
},
|
||||
"type": "dashboard"
|
||||
},
|
||||
{
|
||||
"name": "Prometheus Annotations",
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "existing-ref-uid"
|
||||
},
|
||||
"enable": true,
|
||||
"hide": false,
|
||||
"iconColor": "red",
|
||||
"target": {
|
||||
"expr": "ALERTS{alertstate=\"firing\"}",
|
||||
"refId": "Anno",
|
||||
"interval": "1m",
|
||||
"step": 60
|
||||
},
|
||||
"builtIn": 0,
|
||||
"type": "prometheus"
|
||||
},
|
||||
{
|
||||
"name": "TestData Annotations",
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"enable": true,
|
||||
"hide": false,
|
||||
"iconColor": "blue",
|
||||
"target": {
|
||||
"lines": 10,
|
||||
"refId": "Anno",
|
||||
"scenarioId": "annotations"
|
||||
},
|
||||
"builtIn": false,
|
||||
"type": "testdata"
|
||||
},
|
||||
{
|
||||
"name": "Elasticsearch Annotations",
|
||||
"datasource": {
|
||||
"type": "elasticsearch",
|
||||
"uid": "existing-target-uid"
|
||||
},
|
||||
"enable": true,
|
||||
"hide": false,
|
||||
"iconColor": "yellow",
|
||||
"target": {
|
||||
"query": "tags:deployment",
|
||||
"timeField": "@timestamp",
|
||||
"refId": "Anno"
|
||||
},
|
||||
"textField": "message",
|
||||
"tagsField": "tags",
|
||||
"timeField": "@timestamp",
|
||||
"timeEndField": "end_time",
|
||||
"builtIn": 0,
|
||||
"type": "elasticsearch"
|
||||
},
|
||||
{
|
||||
"name": "SQL Annotations",
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "non-default-test-ds-uid"
|
||||
},
|
||||
"enable": true,
|
||||
"hide": false,
|
||||
"iconColor": "green",
|
||||
"target": {
|
||||
"format": "table",
|
||||
"rawSql": "SELECT time, title, text, tags FROM annotations WHERE $__timeFilter(time)",
|
||||
"refId": "Anno"
|
||||
},
|
||||
"textColumn": "text",
|
||||
"titleColumn": "title",
|
||||
"tagsColumn": "tags",
|
||||
"timeColumn": "time",
|
||||
"builtIn": 0,
|
||||
"type": "sql"
|
||||
},
|
||||
{
|
||||
"name": "No Datasource Annotation",
|
||||
"enable": true,
|
||||
"hide": false,
|
||||
"iconColor": "purple",
|
||||
"target": {
|
||||
"expr": "static_annotation_query",
|
||||
"refId": "Anno"
|
||||
},
|
||||
"builtIn": 0,
|
||||
"type": "manual"
|
||||
},
|
||||
{
|
||||
"name": "Hidden Annotation",
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "existing-ref-uid"
|
||||
},
|
||||
"enable": false,
|
||||
"hide": true,
|
||||
"iconColor": "gray",
|
||||
"target": {
|
||||
"expr": "disabled_query",
|
||||
"refId": "Anno"
|
||||
},
|
||||
"builtIn": 0,
|
||||
"type": "prometheus"
|
||||
},
|
||||
{
|
||||
"name": "Complex Filter Annotation",
|
||||
"datasource": {
|
||||
"type": "influxdb",
|
||||
"uid": "influx-uid"
|
||||
},
|
||||
"enable": true,
|
||||
"hide": false,
|
||||
"iconColor": "#FF5722",
|
||||
"target": {
|
||||
"query": "from(bucket: \"events\") |> range(start: $__timeFrom, stop: $__timeTo) |> filter(fn: (r) => r._measurement == \"deployments\")",
|
||||
"refId": "Anno"
|
||||
},
|
||||
"filter": {
|
||||
"ids": [1, 2, 3],
|
||||
"exclude": true
|
||||
},
|
||||
"mappings": {
|
||||
"title": "service",
|
||||
"text": "description",
|
||||
"time": "timestamp",
|
||||
"tags": "labels"
|
||||
},
|
||||
"builtIn": 0,
|
||||
"type": "influxdb"
|
||||
},
|
||||
{
|
||||
"name": "CloudWatch Annotations",
|
||||
"datasource": {
|
||||
"type": "cloudwatch",
|
||||
"uid": "cloudwatch-uid"
|
||||
},
|
||||
"enable": true,
|
||||
"hide": false,
|
||||
"iconColor": "orange",
|
||||
"target": {
|
||||
"namespace": "AWS/EC2",
|
||||
"metricName": "CPUUtilization",
|
||||
"dimensions": {
|
||||
"InstanceId": "i-1234567890abcdef"
|
||||
},
|
||||
"statistic": "Average",
|
||||
"refId": "Anno"
|
||||
},
|
||||
"showIn": 0,
|
||||
"builtIn": 0,
|
||||
"type": "cloudwatch"
|
||||
},
|
||||
{
|
||||
"name": "Disabled Built-in Annotation",
|
||||
"builtIn": true,
|
||||
"enable": false,
|
||||
"hide": true,
|
||||
"iconColor": "transparent",
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"target": {
|
||||
"expr": "ALERTS{alertstate=\"firing\"}",
|
||||
"refId": "Anno",
|
||||
"interval": "1m",
|
||||
"step": 60
|
||||
},
|
||||
"type": "prometheus"
|
||||
}
|
||||
]
|
||||
},
|
||||
"panels": [],
|
||||
"templating": {
|
||||
"list": []
|
||||
},
|
||||
"time": {
|
||||
"from": "now-24h",
|
||||
"to": "now"
|
||||
},
|
||||
"links": []
|
||||
}
|
||||
}
|
||||
171
apps/dashboard/pkg/migration/conversion/testdata/input/v1beta1.dashboard-properties.json
vendored
Normal file
171
apps/dashboard/pkg/migration/conversion/testdata/input/v1beta1.dashboard-properties.json
vendored
Normal file
@@ -0,0 +1,171 @@
|
||||
{
|
||||
"kind": "Dashboard",
|
||||
"apiVersion": "dashboard.grafana.app/v1beta1",
|
||||
"metadata": {
|
||||
"name": "dashboard-properties-test",
|
||||
"labels": {
|
||||
"test": "dashboard-properties"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"title": "Dashboard Properties Test",
|
||||
"description": "Testing dashboard-level property transformations including time settings, cursor sync, and links",
|
||||
"tags": ["test", "properties", "metadata"],
|
||||
"editable": true,
|
||||
"preload": true,
|
||||
"liveNow": true,
|
||||
"graphTooltip": 2,
|
||||
"fiscalYearStartMonth": 4,
|
||||
"timezone": "America/New_York",
|
||||
"weekStart": "sunday",
|
||||
"refresh": "30s",
|
||||
"time": {
|
||||
"from": "now-12h",
|
||||
"to": "now"
|
||||
},
|
||||
"timepicker": {
|
||||
"collapse": false,
|
||||
"enable": true,
|
||||
"notice": false,
|
||||
"now": true,
|
||||
"refresh_intervals": ["5s", "10s", "30s", "1m", "5m", "15m", "30m", "1h", "2h", "1d"],
|
||||
"status": "Stable",
|
||||
"time_options": ["5m", "15m", "1h", "6h", "12h", "24h", "2d", "7d", "30d"],
|
||||
"type": "timepicker",
|
||||
"hidden": false,
|
||||
"nowDelay": "1m"
|
||||
},
|
||||
"links": [
|
||||
{
|
||||
"asDropdown": false,
|
||||
"icon": "external link",
|
||||
"includeVars": true,
|
||||
"keepTime": true,
|
||||
"tags": ["monitoring", "alerts"],
|
||||
"targetBlank": true,
|
||||
"title": "External Monitoring System",
|
||||
"tooltip": "View in external system",
|
||||
"type": "link",
|
||||
"url": "https://monitoring.example.com/dashboard?from=${__from}&to=${__to}"
|
||||
},
|
||||
{
|
||||
"asDropdown": true,
|
||||
"icon": "dashboard",
|
||||
"includeVars": false,
|
||||
"keepTime": false,
|
||||
"tags": ["grafana", "internal"],
|
||||
"targetBlank": false,
|
||||
"title": "Related Dashboards",
|
||||
"tooltip": "Navigate to related dashboards",
|
||||
"type": "dashboards",
|
||||
"url": ""
|
||||
},
|
||||
{
|
||||
"asDropdown": false,
|
||||
"icon": "info",
|
||||
"includeVars": false,
|
||||
"keepTime": false,
|
||||
"tags": [],
|
||||
"targetBlank": true,
|
||||
"title": "Documentation",
|
||||
"tooltip": "View documentation",
|
||||
"type": "link",
|
||||
"url": "https://docs.example.com/dashboard-guide"
|
||||
},
|
||||
{
|
||||
"asDropdown": false,
|
||||
"icon": "tag",
|
||||
"includeVars": true,
|
||||
"keepTime": true,
|
||||
"tags": ["alerts"],
|
||||
"targetBlank": false,
|
||||
"title": "Tag-based Link",
|
||||
"tooltip": "Filtered by tags",
|
||||
"type": "tag",
|
||||
"url": "/dashboards/tag/alerts"
|
||||
}
|
||||
],
|
||||
"panels": [
|
||||
{
|
||||
"id": 1,
|
||||
"title": "Simple Panel",
|
||||
"type": "stat",
|
||||
"gridPos": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"w": 12,
|
||||
"h": 8
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"fieldConfig": {
|
||||
"defaults": {},
|
||||
"overrides": []
|
||||
},
|
||||
"options": {}
|
||||
}
|
||||
],
|
||||
"templating": {
|
||||
"list": [
|
||||
{
|
||||
"name": "simple_var",
|
||||
"type": "custom",
|
||||
"query": "value1,value2,value3",
|
||||
"current": {
|
||||
"text": "value1",
|
||||
"value": "value1"
|
||||
},
|
||||
"hide": 0,
|
||||
"skipUrlSync": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"annotations": {
|
||||
"list": [
|
||||
{
|
||||
"name": "Simple Annotation",
|
||||
"enable": true,
|
||||
"hide": false,
|
||||
"iconColor": "blue",
|
||||
"target": {
|
||||
"refId": "Anno"
|
||||
},
|
||||
"builtIn": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"style": "dark",
|
||||
"version": 42,
|
||||
"schemaVersion": 39,
|
||||
"gnetId": 12345,
|
||||
"iteration": 1640995200000,
|
||||
"snapshot": {
|
||||
"originalUrl": "http://localhost:3000/d/test",
|
||||
"timestamp": "2023-01-01T00:00:00Z"
|
||||
},
|
||||
"meta": {
|
||||
"canEdit": true,
|
||||
"canSave": true,
|
||||
"canStar": true,
|
||||
"canAdmin": false,
|
||||
"slug": "dashboard-properties-test",
|
||||
"url": "/d/test/dashboard-properties-test",
|
||||
"expires": "2024-01-01T00:00:00Z",
|
||||
"created": "2023-01-01T00:00:00Z",
|
||||
"updated": "2023-06-01T00:00:00Z",
|
||||
"updatedBy": "admin",
|
||||
"createdBy": "admin",
|
||||
"version": 42,
|
||||
"hasAcl": false,
|
||||
"isFolder": false,
|
||||
"folderId": 0,
|
||||
"folderTitle": "General",
|
||||
"folderUrl": "",
|
||||
"provisioned": false,
|
||||
"provisionedExternalId": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
340
apps/dashboard/pkg/migration/conversion/testdata/input/v1beta1.panel-conversions.json
vendored
Normal file
340
apps/dashboard/pkg/migration/conversion/testdata/input/v1beta1.panel-conversions.json
vendored
Normal file
@@ -0,0 +1,340 @@
|
||||
{
|
||||
"kind": "Dashboard",
|
||||
"apiVersion": "dashboard.grafana.app/v1beta1",
|
||||
"metadata": {
|
||||
"name": "panel-conversions-test",
|
||||
"labels": {
|
||||
"test": "panel-conversions"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"title": "Panel Conversions Test Dashboard",
|
||||
"description": "Testing panel to elements conversion",
|
||||
"tags": ["test", "panels"],
|
||||
"editable": true,
|
||||
"preload": false,
|
||||
"panels": [
|
||||
{
|
||||
"cacheTimeout": "60s",
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "existing-ref-uid"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"drawStyle": "line",
|
||||
"fillOpacity": 10,
|
||||
"lineWidth": 1
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green"
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
"id": 1,
|
||||
"interval": "1m",
|
||||
"links": [
|
||||
{
|
||||
"targetBlank": true,
|
||||
"title": "External Link",
|
||||
"url": "https://example.com"
|
||||
}
|
||||
],
|
||||
"maxDataPoints": 300,
|
||||
"options": {
|
||||
"legend": {
|
||||
"calcs": [],
|
||||
"displayMode": "list",
|
||||
"placement": "bottom",
|
||||
"showLegend": true
|
||||
},
|
||||
"tooltip": {
|
||||
"mode": "single"
|
||||
}
|
||||
},
|
||||
"pluginVersion": "10.0.0",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "existing-ref-uid"
|
||||
},
|
||||
"expr": "up",
|
||||
"hide": false,
|
||||
"interval": "30s",
|
||||
"refId": "A"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "existing-ref-uid"
|
||||
},
|
||||
"expr": "cpu_usage",
|
||||
"hide": true,
|
||||
"interval": "1m",
|
||||
"refId": "B"
|
||||
}
|
||||
],
|
||||
"title": "Regular Timeseries Panel",
|
||||
"transformations": [
|
||||
{
|
||||
"id": "reduce",
|
||||
"options": {
|
||||
"reducers": ["mean"]
|
||||
}
|
||||
}
|
||||
],
|
||||
"transparent": true,
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"gridPos": {
|
||||
"h": 4,
|
||||
"w": 6,
|
||||
"x": 12,
|
||||
"y": 0
|
||||
},
|
||||
"id": 2,
|
||||
"libraryPanel": {
|
||||
"name": "Shared Stats Panel",
|
||||
"uid": "library-panel-uid-123"
|
||||
},
|
||||
"title": "Library Panel Reference"
|
||||
},
|
||||
{
|
||||
"collapsed": false,
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "edprtf91hz01se"
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 1,
|
||||
"w": 24,
|
||||
"x": 0,
|
||||
"y": 8
|
||||
},
|
||||
"id": 3,
|
||||
"panels": [],
|
||||
"repeat": "server",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "edprtf91hz01se"
|
||||
},
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Row Panel",
|
||||
"type": "row"
|
||||
},
|
||||
{
|
||||
"autoMigrateFrom": "graph",
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"custom": {}
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 6,
|
||||
"w": 8,
|
||||
"x": 0,
|
||||
"y": 9
|
||||
},
|
||||
"id": 4,
|
||||
"maxPerRow": 4,
|
||||
"repeat": "region",
|
||||
"repeatDirection": "h",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"refId": "A",
|
||||
"scenarioId": "random_walk"
|
||||
}
|
||||
],
|
||||
"title": "Panel in Row",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "elasticsearch",
|
||||
"uid": "existing-target-uid"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "continuous-GrYlRd"
|
||||
},
|
||||
"custom": {
|
||||
"orientation": "horizontal"
|
||||
}
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 6,
|
||||
"w": 16,
|
||||
"x": 8,
|
||||
"y": 9
|
||||
},
|
||||
"hideTimeOverride": true,
|
||||
"id": 7,
|
||||
"links": [
|
||||
{
|
||||
"title": "Drill Down",
|
||||
"url": "/d/detailed-view"
|
||||
}
|
||||
],
|
||||
"maxDataPoints": 1000,
|
||||
"options": {
|
||||
"barWidth": 0.97,
|
||||
"groupWidth": 0.7,
|
||||
"orientation": "horizontal"
|
||||
},
|
||||
"pluginVersion": "9.5.0",
|
||||
"queryCachingTTL": 300,
|
||||
"targets": [
|
||||
{
|
||||
"bucketAggs": [
|
||||
{
|
||||
"field": "@timestamp",
|
||||
"id": "2",
|
||||
"type": "date_histogram"
|
||||
}
|
||||
],
|
||||
"datasource": {
|
||||
"type": "elasticsearch",
|
||||
"uid": "existing-target-uid"
|
||||
},
|
||||
"query": "*",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"timeFrom": "1h",
|
||||
"timeShift": "1h",
|
||||
"title": "Complex Panel with All Features",
|
||||
"transformations": [
|
||||
{
|
||||
"id": "groupBy",
|
||||
"options": {
|
||||
"fields": {
|
||||
"status": {
|
||||
"aggregations": ["count"],
|
||||
"operation": "groupby"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "sortBy",
|
||||
"options": {
|
||||
"sort": [
|
||||
{
|
||||
"desc": true,
|
||||
"field": "count"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"type": "barchart"
|
||||
},
|
||||
{
|
||||
"collapsed": true,
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "edprtf91hz01se"
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 1,
|
||||
"w": 24,
|
||||
"x": 0,
|
||||
"y": 15
|
||||
},
|
||||
"id": 5,
|
||||
"panels": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "non-default-test-ds-uid"
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 16
|
||||
},
|
||||
"id": 6,
|
||||
"options": {
|
||||
"showHeader": true
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "non-default-test-ds-uid"
|
||||
},
|
||||
"format": "table",
|
||||
"rawSql": "SELECT * FROM metrics",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Hidden Panel in Collapsed Row",
|
||||
"type": "table"
|
||||
}
|
||||
],
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "existing-ref-uid"
|
||||
},
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Collapsed Row",
|
||||
"type": "row"
|
||||
}
|
||||
],
|
||||
"time": {
|
||||
"from": "now-1h",
|
||||
"to": "now"
|
||||
},
|
||||
"templating": {
|
||||
"list": []
|
||||
},
|
||||
"annotations": {
|
||||
"list": []
|
||||
},
|
||||
"links": []
|
||||
}
|
||||
}
|
||||
331
apps/dashboard/pkg/migration/conversion/testdata/input/v1beta1.variable-conversions.json
vendored
Normal file
331
apps/dashboard/pkg/migration/conversion/testdata/input/v1beta1.variable-conversions.json
vendored
Normal file
@@ -0,0 +1,331 @@
|
||||
{
|
||||
"kind": "Dashboard",
|
||||
"apiVersion": "dashboard.grafana.app/v1beta1",
|
||||
"metadata": {
|
||||
"name": "variable-conversions-test",
|
||||
"labels": {
|
||||
"test": "variable-conversions"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"title": "Variable Conversions Test Dashboard",
|
||||
"description": "Testing all variable types and transformations",
|
||||
"tags": ["test", "variables"],
|
||||
"templating": {
|
||||
"list": [
|
||||
{
|
||||
"name": "datasource_var",
|
||||
"type": "datasource",
|
||||
"label": "Data Source",
|
||||
"description": "Select a data source",
|
||||
"query": "prometheus",
|
||||
"current": {
|
||||
"selected": false,
|
||||
"text": "Prometheus",
|
||||
"value": "prometheus-uid"
|
||||
},
|
||||
"options": [
|
||||
{
|
||||
"selected": true,
|
||||
"text": "Prometheus",
|
||||
"value": "prometheus-uid"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"text": "InfluxDB",
|
||||
"value": "influx-uid"
|
||||
}
|
||||
],
|
||||
"hide": 0,
|
||||
"includeAll": false,
|
||||
"multi": false,
|
||||
"regex": "",
|
||||
"skipUrlSync": false,
|
||||
"refresh": 1
|
||||
},
|
||||
{
|
||||
"name": "query_var",
|
||||
"type": "query",
|
||||
"label": "Instance",
|
||||
"description": "Available instances",
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "existing-ref-uid"
|
||||
},
|
||||
"definition": "label_values(up, instance)",
|
||||
"query": "label_values(up, instance)",
|
||||
"current": {
|
||||
"selected": true,
|
||||
"text": ["All", "localhost:9090"],
|
||||
"value": ["$__all", "localhost:9090"]
|
||||
},
|
||||
"options": [
|
||||
{
|
||||
"selected": false,
|
||||
"text": "All",
|
||||
"value": "$__all"
|
||||
},
|
||||
{
|
||||
"selected": true,
|
||||
"text": "localhost:9090",
|
||||
"value": "localhost:9090"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"text": "localhost:9091",
|
||||
"value": "localhost:9091"
|
||||
}
|
||||
],
|
||||
"hide": 1,
|
||||
"includeAll": true,
|
||||
"allValue": ".*",
|
||||
"multi": true,
|
||||
"regex": "/.*9090.*/",
|
||||
"skipUrlSync": false,
|
||||
"refresh": 2,
|
||||
"sort": 1,
|
||||
"tagValuesQuery": "",
|
||||
"tagsQuery": "",
|
||||
"useTags": false
|
||||
},
|
||||
{
|
||||
"name": "custom_var",
|
||||
"type": "custom",
|
||||
"label": "Environment",
|
||||
"description": "Deployment environment",
|
||||
"query": "prod,staging,dev",
|
||||
"current": {
|
||||
"selected": false,
|
||||
"text": "prod",
|
||||
"value": "prod"
|
||||
},
|
||||
"options": [
|
||||
{
|
||||
"selected": true,
|
||||
"text": "prod",
|
||||
"value": "prod"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"text": "staging",
|
||||
"value": "staging"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"text": "dev",
|
||||
"value": "dev"
|
||||
}
|
||||
],
|
||||
"hide": 0,
|
||||
"includeAll": true,
|
||||
"allValue": null,
|
||||
"multi": false,
|
||||
"skipUrlSync": false
|
||||
},
|
||||
{
|
||||
"name": "adhoc_var",
|
||||
"type": "adhoc",
|
||||
"label": "Filters",
|
||||
"description": "Add filters",
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "existing-ref-uid"
|
||||
},
|
||||
"filters": [
|
||||
{
|
||||
"key": "job",
|
||||
"operator": "=",
|
||||
"value": "prometheus"
|
||||
}
|
||||
],
|
||||
"baseFilters": [
|
||||
{
|
||||
"key": "environment",
|
||||
"operator": "=",
|
||||
"value": "production"
|
||||
}
|
||||
],
|
||||
"hide": 0,
|
||||
"skipUrlSync": false,
|
||||
"defaultKeys": [
|
||||
{
|
||||
"text": "job",
|
||||
"value": "job"
|
||||
},
|
||||
{
|
||||
"text": "instance",
|
||||
"value": "instance"
|
||||
}
|
||||
],
|
||||
"allowCustomValue": true
|
||||
},
|
||||
{
|
||||
"name": "constant_var",
|
||||
"type": "constant",
|
||||
"label": "App Name",
|
||||
"description": "Application name constant",
|
||||
"query": "my-application",
|
||||
"current": {
|
||||
"selected": false,
|
||||
"text": "my-application",
|
||||
"value": "my-application"
|
||||
},
|
||||
"hide": 2,
|
||||
"skipUrlSync": true
|
||||
},
|
||||
{
|
||||
"name": "interval_var",
|
||||
"type": "interval",
|
||||
"label": "Interval",
|
||||
"description": "Time interval for queries",
|
||||
"query": "1m,5m,10m,30m,1h,6h,12h,1d,7d,14d,30d",
|
||||
"current": {
|
||||
"selected": false,
|
||||
"text": "5m",
|
||||
"value": "5m"
|
||||
},
|
||||
"options": [
|
||||
{
|
||||
"selected": false,
|
||||
"text": "1m",
|
||||
"value": "1m"
|
||||
},
|
||||
{
|
||||
"selected": true,
|
||||
"text": "5m",
|
||||
"value": "5m"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"text": "10m",
|
||||
"value": "10m"
|
||||
}
|
||||
],
|
||||
"hide": 0,
|
||||
"auto": true,
|
||||
"auto_count": 30,
|
||||
"auto_min": "10s",
|
||||
"skipUrlSync": false,
|
||||
"refresh": 2
|
||||
},
|
||||
{
|
||||
"name": "textbox_var",
|
||||
"type": "textbox",
|
||||
"label": "Search Term",
|
||||
"description": "Enter search term",
|
||||
"query": "default_search",
|
||||
"current": {
|
||||
"selected": false,
|
||||
"text": "error",
|
||||
"value": "error"
|
||||
},
|
||||
"hide": 0,
|
||||
"skipUrlSync": false
|
||||
},
|
||||
{
|
||||
"name": "groupby_var",
|
||||
"type": "groupby",
|
||||
"label": "Group By",
|
||||
"description": "Group results by field",
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "existing-ref-uid"
|
||||
},
|
||||
"query": "",
|
||||
"current": {
|
||||
"selected": true,
|
||||
"text": ["job", "instance"],
|
||||
"value": ["job", "instance"]
|
||||
},
|
||||
"options": [
|
||||
{
|
||||
"selected": true,
|
||||
"text": "job",
|
||||
"value": "job"
|
||||
},
|
||||
{
|
||||
"selected": true,
|
||||
"text": "instance",
|
||||
"value": "instance"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"text": "region",
|
||||
"value": "region"
|
||||
}
|
||||
],
|
||||
"hide": 0,
|
||||
"multi": true,
|
||||
"skipUrlSync": false
|
||||
},
|
||||
{
|
||||
"name": "legacy_string_var",
|
||||
"type": "query",
|
||||
"label": "Legacy Variable",
|
||||
"description": "Variable with legacy string value",
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "existing-ref-uid"
|
||||
},
|
||||
"query": "up",
|
||||
"current": {
|
||||
"selected": false,
|
||||
"text": "legacy_value",
|
||||
"value": "legacy_string_content"
|
||||
},
|
||||
"hide": 0,
|
||||
"refresh": 1,
|
||||
"skipUrlSync": false
|
||||
},
|
||||
{
|
||||
"name": "complex_query_var",
|
||||
"type": "query",
|
||||
"label": "Complex Query Variable",
|
||||
"description": "Variable with complex query and all features",
|
||||
"datasource": {
|
||||
"type": "elasticsearch",
|
||||
"uid": "existing-target-uid"
|
||||
},
|
||||
"definition": "terms field:@host size:100",
|
||||
"query": {
|
||||
"query": "*",
|
||||
"size": 100,
|
||||
"bucketAggs": [
|
||||
{
|
||||
"field": "@host",
|
||||
"id": "2",
|
||||
"type": "terms"
|
||||
}
|
||||
]
|
||||
},
|
||||
"current": {
|
||||
"selected": true,
|
||||
"text": ["All", "host1", "host2"],
|
||||
"value": ["$__all", "host1", "host2"]
|
||||
},
|
||||
"options": [],
|
||||
"hide": 0,
|
||||
"includeAll": true,
|
||||
"allValue": "*",
|
||||
"multi": true,
|
||||
"regex": "/host[0-9]+/",
|
||||
"skipUrlSync": false,
|
||||
"refresh": 1,
|
||||
"sort": 2,
|
||||
"tagValuesQuery": "",
|
||||
"tagsQuery": "",
|
||||
"useTags": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"panels": [],
|
||||
"time": {
|
||||
"from": "now-6h",
|
||||
"to": "now"
|
||||
},
|
||||
"annotations": {
|
||||
"list": []
|
||||
},
|
||||
"links": []
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
{
|
||||
"kind": "Dashboard",
|
||||
"apiVersion": "dashboard.grafana.app/v0alpha1",
|
||||
"metadata": {
|
||||
"name": "v10.table_thresholds.v42"
|
||||
},
|
||||
"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"
|
||||
}
|
||||
]
|
||||
},
|
||||
"editable": true,
|
||||
"fiscalYearStartMonth": 0,
|
||||
"graphTooltip": 0,
|
||||
"links": [],
|
||||
"panels": [
|
||||
{
|
||||
"autoMigrateFrom": "table-old",
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"id": 1,
|
||||
"styles": [
|
||||
{
|
||||
"align": "auto",
|
||||
"thresholds": [
|
||||
"20",
|
||||
"30"
|
||||
]
|
||||
},
|
||||
{
|
||||
"align": "auto",
|
||||
"thresholds": [
|
||||
"200",
|
||||
"300"
|
||||
]
|
||||
}
|
||||
],
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"type": "table"
|
||||
},
|
||||
{
|
||||
"autoMigrateFrom": "table-old",
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"id": 2,
|
||||
"styles": [
|
||||
{
|
||||
"align": "auto",
|
||||
"thresholds": [
|
||||
"50",
|
||||
"75"
|
||||
]
|
||||
}
|
||||
],
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"type": "table"
|
||||
},
|
||||
{
|
||||
"autoMigrateFrom": "graph",
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"id": 3,
|
||||
"styles": [
|
||||
{
|
||||
"thresholds": [
|
||||
"5",
|
||||
"10",
|
||||
"15"
|
||||
]
|
||||
}
|
||||
],
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"type": "timeseries"
|
||||
}
|
||||
],
|
||||
"refresh": "",
|
||||
"schemaVersion": 42,
|
||||
"tags": [],
|
||||
"templating": {
|
||||
"list": []
|
||||
},
|
||||
"time": {
|
||||
"from": "now-6h",
|
||||
"to": "now"
|
||||
},
|
||||
"timepicker": {},
|
||||
"timezone": "",
|
||||
"title": "V10 Table Thresholds Test",
|
||||
"weekStart": ""
|
||||
},
|
||||
"status": {
|
||||
"conversion": {
|
||||
"failed": false,
|
||||
"storedVersion": "v1beta1"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,241 @@
|
||||
{
|
||||
"kind": "Dashboard",
|
||||
"apiVersion": "dashboard.grafana.app/v2alpha1",
|
||||
"metadata": {
|
||||
"name": "v10.table_thresholds.v42"
|
||||
},
|
||||
"spec": {
|
||||
"annotations": [
|
||||
{
|
||||
"kind": "AnnotationQuery",
|
||||
"spec": {
|
||||
"datasource": {
|
||||
"type": "grafana",
|
||||
"uid": "-- Grafana --"
|
||||
},
|
||||
"query": {
|
||||
"kind": "DataQuery",
|
||||
"spec": {}
|
||||
},
|
||||
"enable": true,
|
||||
"hide": true,
|
||||
"iconColor": "rgba(0, 211, 255, 1)",
|
||||
"name": "Annotations \u0026 Alerts",
|
||||
"builtIn": true,
|
||||
"legacyOptions": {
|
||||
"type": "dashboard"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"cursorSync": "Off",
|
||||
"editable": true,
|
||||
"elements": {
|
||||
"panel-1": {
|
||||
"kind": "Panel",
|
||||
"spec": {
|
||||
"id": 1,
|
||||
"title": "",
|
||||
"description": "",
|
||||
"links": [],
|
||||
"data": {
|
||||
"kind": "QueryGroup",
|
||||
"spec": {
|
||||
"queries": [
|
||||
{
|
||||
"kind": "PanelQuery",
|
||||
"spec": {
|
||||
"query": {
|
||||
"kind": "DataQuery",
|
||||
"spec": {}
|
||||
},
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"refId": "A",
|
||||
"hidden": false
|
||||
}
|
||||
}
|
||||
],
|
||||
"transformations": [],
|
||||
"queryOptions": {}
|
||||
}
|
||||
},
|
||||
"vizConfig": {
|
||||
"kind": "table",
|
||||
"spec": {
|
||||
"pluginVersion": "",
|
||||
"options": {},
|
||||
"fieldConfig": {
|
||||
"defaults": {},
|
||||
"overrides": []
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"panel-2": {
|
||||
"kind": "Panel",
|
||||
"spec": {
|
||||
"id": 2,
|
||||
"title": "",
|
||||
"description": "",
|
||||
"links": [],
|
||||
"data": {
|
||||
"kind": "QueryGroup",
|
||||
"spec": {
|
||||
"queries": [
|
||||
{
|
||||
"kind": "PanelQuery",
|
||||
"spec": {
|
||||
"query": {
|
||||
"kind": "DataQuery",
|
||||
"spec": {}
|
||||
},
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"refId": "A",
|
||||
"hidden": false
|
||||
}
|
||||
}
|
||||
],
|
||||
"transformations": [],
|
||||
"queryOptions": {}
|
||||
}
|
||||
},
|
||||
"vizConfig": {
|
||||
"kind": "table",
|
||||
"spec": {
|
||||
"pluginVersion": "",
|
||||
"options": {},
|
||||
"fieldConfig": {
|
||||
"defaults": {},
|
||||
"overrides": []
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"panel-3": {
|
||||
"kind": "Panel",
|
||||
"spec": {
|
||||
"id": 3,
|
||||
"title": "",
|
||||
"description": "",
|
||||
"links": [],
|
||||
"data": {
|
||||
"kind": "QueryGroup",
|
||||
"spec": {
|
||||
"queries": [
|
||||
{
|
||||
"kind": "PanelQuery",
|
||||
"spec": {
|
||||
"query": {
|
||||
"kind": "DataQuery",
|
||||
"spec": {}
|
||||
},
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"refId": "A",
|
||||
"hidden": false
|
||||
}
|
||||
}
|
||||
],
|
||||
"transformations": [],
|
||||
"queryOptions": {}
|
||||
}
|
||||
},
|
||||
"vizConfig": {
|
||||
"kind": "timeseries",
|
||||
"spec": {
|
||||
"pluginVersion": "",
|
||||
"options": {},
|
||||
"fieldConfig": {
|
||||
"defaults": {},
|
||||
"overrides": []
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"layout": {
|
||||
"kind": "GridLayout",
|
||||
"spec": {
|
||||
"items": [
|
||||
{
|
||||
"kind": "GridLayoutItem",
|
||||
"spec": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"width": 6,
|
||||
"height": 3,
|
||||
"element": {
|
||||
"kind": "ElementReference",
|
||||
"name": "panel-1"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "GridLayoutItem",
|
||||
"spec": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"width": 6,
|
||||
"height": 3,
|
||||
"element": {
|
||||
"kind": "ElementReference",
|
||||
"name": "panel-2"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "GridLayoutItem",
|
||||
"spec": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"width": 6,
|
||||
"height": 3,
|
||||
"element": {
|
||||
"kind": "ElementReference",
|
||||
"name": "panel-3"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"links": [],
|
||||
"liveNow": false,
|
||||
"preload": false,
|
||||
"tags": [],
|
||||
"timeSettings": {
|
||||
"timezone": "",
|
||||
"from": "now-6h",
|
||||
"to": "now",
|
||||
"autoRefresh": "",
|
||||
"autoRefreshIntervals": [
|
||||
"5s",
|
||||
"10s",
|
||||
"30s",
|
||||
"1m",
|
||||
"5m",
|
||||
"15m",
|
||||
"30m",
|
||||
"1h",
|
||||
"2h",
|
||||
"1d"
|
||||
],
|
||||
"hideTimepicker": false,
|
||||
"fiscalYearStartMonth": 0
|
||||
},
|
||||
"title": "V10 Table Thresholds Test",
|
||||
"variables": []
|
||||
},
|
||||
"status": {}
|
||||
}
|
||||
@@ -0,0 +1,248 @@
|
||||
{
|
||||
"kind": "Dashboard",
|
||||
"apiVersion": "dashboard.grafana.app/v2beta1",
|
||||
"metadata": {
|
||||
"name": "v10.table_thresholds.v42"
|
||||
},
|
||||
"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",
|
||||
"editable": true,
|
||||
"elements": {
|
||||
"panel-1": {
|
||||
"kind": "Panel",
|
||||
"spec": {
|
||||
"id": 1,
|
||||
"title": "",
|
||||
"description": "",
|
||||
"links": [],
|
||||
"data": {
|
||||
"kind": "QueryGroup",
|
||||
"spec": {
|
||||
"queries": [
|
||||
{
|
||||
"kind": "PanelQuery",
|
||||
"spec": {
|
||||
"query": {
|
||||
"kind": "DataQuery",
|
||||
"group": "prometheus",
|
||||
"version": "v0",
|
||||
"datasource": {
|
||||
"name": "default-ds-uid"
|
||||
},
|
||||
"spec": {}
|
||||
},
|
||||
"refId": "A",
|
||||
"hidden": false
|
||||
}
|
||||
}
|
||||
],
|
||||
"transformations": [],
|
||||
"queryOptions": {}
|
||||
}
|
||||
},
|
||||
"vizConfig": {
|
||||
"kind": "VizConfig",
|
||||
"group": "table",
|
||||
"version": "",
|
||||
"spec": {
|
||||
"options": {},
|
||||
"fieldConfig": {
|
||||
"defaults": {},
|
||||
"overrides": []
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"panel-2": {
|
||||
"kind": "Panel",
|
||||
"spec": {
|
||||
"id": 2,
|
||||
"title": "",
|
||||
"description": "",
|
||||
"links": [],
|
||||
"data": {
|
||||
"kind": "QueryGroup",
|
||||
"spec": {
|
||||
"queries": [
|
||||
{
|
||||
"kind": "PanelQuery",
|
||||
"spec": {
|
||||
"query": {
|
||||
"kind": "DataQuery",
|
||||
"group": "prometheus",
|
||||
"version": "v0",
|
||||
"datasource": {
|
||||
"name": "default-ds-uid"
|
||||
},
|
||||
"spec": {}
|
||||
},
|
||||
"refId": "A",
|
||||
"hidden": false
|
||||
}
|
||||
}
|
||||
],
|
||||
"transformations": [],
|
||||
"queryOptions": {}
|
||||
}
|
||||
},
|
||||
"vizConfig": {
|
||||
"kind": "VizConfig",
|
||||
"group": "table",
|
||||
"version": "",
|
||||
"spec": {
|
||||
"options": {},
|
||||
"fieldConfig": {
|
||||
"defaults": {},
|
||||
"overrides": []
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"panel-3": {
|
||||
"kind": "Panel",
|
||||
"spec": {
|
||||
"id": 3,
|
||||
"title": "",
|
||||
"description": "",
|
||||
"links": [],
|
||||
"data": {
|
||||
"kind": "QueryGroup",
|
||||
"spec": {
|
||||
"queries": [
|
||||
{
|
||||
"kind": "PanelQuery",
|
||||
"spec": {
|
||||
"query": {
|
||||
"kind": "DataQuery",
|
||||
"group": "prometheus",
|
||||
"version": "v0",
|
||||
"datasource": {
|
||||
"name": "default-ds-uid"
|
||||
},
|
||||
"spec": {}
|
||||
},
|
||||
"refId": "A",
|
||||
"hidden": false
|
||||
}
|
||||
}
|
||||
],
|
||||
"transformations": [],
|
||||
"queryOptions": {}
|
||||
}
|
||||
},
|
||||
"vizConfig": {
|
||||
"kind": "VizConfig",
|
||||
"group": "timeseries",
|
||||
"version": "",
|
||||
"spec": {
|
||||
"options": {},
|
||||
"fieldConfig": {
|
||||
"defaults": {},
|
||||
"overrides": []
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"layout": {
|
||||
"kind": "GridLayout",
|
||||
"spec": {
|
||||
"items": [
|
||||
{
|
||||
"kind": "GridLayoutItem",
|
||||
"spec": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"width": 6,
|
||||
"height": 3,
|
||||
"element": {
|
||||
"kind": "ElementReference",
|
||||
"name": "panel-1"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "GridLayoutItem",
|
||||
"spec": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"width": 6,
|
||||
"height": 3,
|
||||
"element": {
|
||||
"kind": "ElementReference",
|
||||
"name": "panel-2"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "GridLayoutItem",
|
||||
"spec": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"width": 6,
|
||||
"height": 3,
|
||||
"element": {
|
||||
"kind": "ElementReference",
|
||||
"name": "panel-3"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"links": [],
|
||||
"liveNow": false,
|
||||
"preload": false,
|
||||
"tags": [],
|
||||
"timeSettings": {
|
||||
"timezone": "",
|
||||
"from": "now-6h",
|
||||
"to": "now",
|
||||
"autoRefresh": "",
|
||||
"autoRefreshIntervals": [
|
||||
"5s",
|
||||
"10s",
|
||||
"30s",
|
||||
"1m",
|
||||
"5m",
|
||||
"15m",
|
||||
"30m",
|
||||
"1h",
|
||||
"2h",
|
||||
"1d"
|
||||
],
|
||||
"hideTimepicker": false,
|
||||
"fiscalYearStartMonth": 0
|
||||
},
|
||||
"title": "V10 Table Thresholds Test",
|
||||
"variables": []
|
||||
},
|
||||
"status": {}
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
{
|
||||
"kind": "Dashboard",
|
||||
"apiVersion": "dashboard.grafana.app/v0alpha1",
|
||||
"metadata": {
|
||||
"name": "v11.no-op-migration.v42"
|
||||
},
|
||||
"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"
|
||||
}
|
||||
]
|
||||
},
|
||||
"editable": true,
|
||||
"fiscalYearStartMonth": 0,
|
||||
"graphTooltip": 0,
|
||||
"links": [],
|
||||
"panels": [
|
||||
{
|
||||
"autoMigrateFrom": "graph",
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"id": 1,
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "CPU Usage",
|
||||
"type": "timeseries",
|
||||
"yAxes": [
|
||||
{
|
||||
"show": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"autoMigrateFrom": "singlestat",
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"id": 2,
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Memory Usage",
|
||||
"type": "stat",
|
||||
"valueMaps": [
|
||||
{
|
||||
"op": "=",
|
||||
"text": "N/A",
|
||||
"value": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"refresh": "",
|
||||
"schemaVersion": 42,
|
||||
"tags": [],
|
||||
"templating": {
|
||||
"list": [
|
||||
{
|
||||
"datasource": "prometheus",
|
||||
"name": "server",
|
||||
"options": [],
|
||||
"query": "label_values(server)",
|
||||
"refresh": 1,
|
||||
"type": "query"
|
||||
}
|
||||
]
|
||||
},
|
||||
"time": {
|
||||
"from": "now-6h",
|
||||
"to": "now"
|
||||
},
|
||||
"timepicker": {
|
||||
"refresh_intervals": [
|
||||
"5s",
|
||||
"10s",
|
||||
"30s",
|
||||
"1m",
|
||||
"5m",
|
||||
"15m",
|
||||
"30m",
|
||||
"1h",
|
||||
"2h",
|
||||
"1d"
|
||||
]
|
||||
},
|
||||
"timezone": "",
|
||||
"title": "V11 No-Op Migration Test Dashboard",
|
||||
"weekStart": ""
|
||||
},
|
||||
"status": {
|
||||
"conversion": {
|
||||
"failed": false,
|
||||
"storedVersion": "v1beta1"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,210 @@
|
||||
{
|
||||
"kind": "Dashboard",
|
||||
"apiVersion": "dashboard.grafana.app/v2alpha1",
|
||||
"metadata": {
|
||||
"name": "v11.no-op-migration.v42"
|
||||
},
|
||||
"spec": {
|
||||
"annotations": [
|
||||
{
|
||||
"kind": "AnnotationQuery",
|
||||
"spec": {
|
||||
"datasource": {
|
||||
"type": "grafana",
|
||||
"uid": "-- Grafana --"
|
||||
},
|
||||
"query": {
|
||||
"kind": "DataQuery",
|
||||
"spec": {}
|
||||
},
|
||||
"enable": true,
|
||||
"hide": true,
|
||||
"iconColor": "rgba(0, 211, 255, 1)",
|
||||
"name": "Annotations \u0026 Alerts",
|
||||
"builtIn": true,
|
||||
"legacyOptions": {
|
||||
"type": "dashboard"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"cursorSync": "Off",
|
||||
"editable": true,
|
||||
"elements": {
|
||||
"panel-1": {
|
||||
"kind": "Panel",
|
||||
"spec": {
|
||||
"id": 1,
|
||||
"title": "CPU Usage",
|
||||
"description": "",
|
||||
"links": [],
|
||||
"data": {
|
||||
"kind": "QueryGroup",
|
||||
"spec": {
|
||||
"queries": [
|
||||
{
|
||||
"kind": "PanelQuery",
|
||||
"spec": {
|
||||
"query": {
|
||||
"kind": "DataQuery",
|
||||
"spec": {}
|
||||
},
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"refId": "A",
|
||||
"hidden": false
|
||||
}
|
||||
}
|
||||
],
|
||||
"transformations": [],
|
||||
"queryOptions": {}
|
||||
}
|
||||
},
|
||||
"vizConfig": {
|
||||
"kind": "timeseries",
|
||||
"spec": {
|
||||
"pluginVersion": "",
|
||||
"options": {},
|
||||
"fieldConfig": {
|
||||
"defaults": {},
|
||||
"overrides": []
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"panel-2": {
|
||||
"kind": "Panel",
|
||||
"spec": {
|
||||
"id": 2,
|
||||
"title": "Memory Usage",
|
||||
"description": "",
|
||||
"links": [],
|
||||
"data": {
|
||||
"kind": "QueryGroup",
|
||||
"spec": {
|
||||
"queries": [
|
||||
{
|
||||
"kind": "PanelQuery",
|
||||
"spec": {
|
||||
"query": {
|
||||
"kind": "DataQuery",
|
||||
"spec": {}
|
||||
},
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"refId": "A",
|
||||
"hidden": false
|
||||
}
|
||||
}
|
||||
],
|
||||
"transformations": [],
|
||||
"queryOptions": {}
|
||||
}
|
||||
},
|
||||
"vizConfig": {
|
||||
"kind": "stat",
|
||||
"spec": {
|
||||
"pluginVersion": "",
|
||||
"options": {},
|
||||
"fieldConfig": {
|
||||
"defaults": {},
|
||||
"overrides": []
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"layout": {
|
||||
"kind": "GridLayout",
|
||||
"spec": {
|
||||
"items": [
|
||||
{
|
||||
"kind": "GridLayoutItem",
|
||||
"spec": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"width": 6,
|
||||
"height": 3,
|
||||
"element": {
|
||||
"kind": "ElementReference",
|
||||
"name": "panel-1"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "GridLayoutItem",
|
||||
"spec": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"width": 6,
|
||||
"height": 3,
|
||||
"element": {
|
||||
"kind": "ElementReference",
|
||||
"name": "panel-2"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"links": [],
|
||||
"liveNow": false,
|
||||
"preload": false,
|
||||
"tags": [],
|
||||
"timeSettings": {
|
||||
"timezone": "",
|
||||
"from": "now-6h",
|
||||
"to": "now",
|
||||
"autoRefresh": "",
|
||||
"autoRefreshIntervals": [
|
||||
"5s",
|
||||
"10s",
|
||||
"30s",
|
||||
"1m",
|
||||
"5m",
|
||||
"15m",
|
||||
"30m",
|
||||
"1h",
|
||||
"2h",
|
||||
"1d"
|
||||
],
|
||||
"hideTimepicker": false,
|
||||
"fiscalYearStartMonth": 0
|
||||
},
|
||||
"title": "V11 No-Op Migration Test Dashboard",
|
||||
"variables": [
|
||||
{
|
||||
"kind": "QueryVariable",
|
||||
"spec": {
|
||||
"name": "server",
|
||||
"current": {
|
||||
"text": "",
|
||||
"value": ""
|
||||
},
|
||||
"hide": "dontHide",
|
||||
"refresh": "onDashboardLoad",
|
||||
"skipUrlSync": false,
|
||||
"query": {
|
||||
"kind": "DataQuery",
|
||||
"spec": {
|
||||
"__legacyStringValue": "label_values(server)"
|
||||
}
|
||||
},
|
||||
"regex": "",
|
||||
"sort": "disabled",
|
||||
"options": [],
|
||||
"multi": false,
|
||||
"includeAll": false,
|
||||
"allowCustomValue": true
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"status": {}
|
||||
}
|
||||
@@ -0,0 +1,217 @@
|
||||
{
|
||||
"kind": "Dashboard",
|
||||
"apiVersion": "dashboard.grafana.app/v2beta1",
|
||||
"metadata": {
|
||||
"name": "v11.no-op-migration.v42"
|
||||
},
|
||||
"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",
|
||||
"editable": true,
|
||||
"elements": {
|
||||
"panel-1": {
|
||||
"kind": "Panel",
|
||||
"spec": {
|
||||
"id": 1,
|
||||
"title": "CPU Usage",
|
||||
"description": "",
|
||||
"links": [],
|
||||
"data": {
|
||||
"kind": "QueryGroup",
|
||||
"spec": {
|
||||
"queries": [
|
||||
{
|
||||
"kind": "PanelQuery",
|
||||
"spec": {
|
||||
"query": {
|
||||
"kind": "DataQuery",
|
||||
"group": "prometheus",
|
||||
"version": "v0",
|
||||
"datasource": {
|
||||
"name": "default-ds-uid"
|
||||
},
|
||||
"spec": {}
|
||||
},
|
||||
"refId": "A",
|
||||
"hidden": false
|
||||
}
|
||||
}
|
||||
],
|
||||
"transformations": [],
|
||||
"queryOptions": {}
|
||||
}
|
||||
},
|
||||
"vizConfig": {
|
||||
"kind": "VizConfig",
|
||||
"group": "timeseries",
|
||||
"version": "",
|
||||
"spec": {
|
||||
"options": {},
|
||||
"fieldConfig": {
|
||||
"defaults": {},
|
||||
"overrides": []
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"panel-2": {
|
||||
"kind": "Panel",
|
||||
"spec": {
|
||||
"id": 2,
|
||||
"title": "Memory Usage",
|
||||
"description": "",
|
||||
"links": [],
|
||||
"data": {
|
||||
"kind": "QueryGroup",
|
||||
"spec": {
|
||||
"queries": [
|
||||
{
|
||||
"kind": "PanelQuery",
|
||||
"spec": {
|
||||
"query": {
|
||||
"kind": "DataQuery",
|
||||
"group": "prometheus",
|
||||
"version": "v0",
|
||||
"datasource": {
|
||||
"name": "default-ds-uid"
|
||||
},
|
||||
"spec": {}
|
||||
},
|
||||
"refId": "A",
|
||||
"hidden": false
|
||||
}
|
||||
}
|
||||
],
|
||||
"transformations": [],
|
||||
"queryOptions": {}
|
||||
}
|
||||
},
|
||||
"vizConfig": {
|
||||
"kind": "VizConfig",
|
||||
"group": "stat",
|
||||
"version": "",
|
||||
"spec": {
|
||||
"options": {},
|
||||
"fieldConfig": {
|
||||
"defaults": {},
|
||||
"overrides": []
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"layout": {
|
||||
"kind": "GridLayout",
|
||||
"spec": {
|
||||
"items": [
|
||||
{
|
||||
"kind": "GridLayoutItem",
|
||||
"spec": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"width": 6,
|
||||
"height": 3,
|
||||
"element": {
|
||||
"kind": "ElementReference",
|
||||
"name": "panel-1"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "GridLayoutItem",
|
||||
"spec": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"width": 6,
|
||||
"height": 3,
|
||||
"element": {
|
||||
"kind": "ElementReference",
|
||||
"name": "panel-2"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"links": [],
|
||||
"liveNow": false,
|
||||
"preload": false,
|
||||
"tags": [],
|
||||
"timeSettings": {
|
||||
"timezone": "",
|
||||
"from": "now-6h",
|
||||
"to": "now",
|
||||
"autoRefresh": "",
|
||||
"autoRefreshIntervals": [
|
||||
"5s",
|
||||
"10s",
|
||||
"30s",
|
||||
"1m",
|
||||
"5m",
|
||||
"15m",
|
||||
"30m",
|
||||
"1h",
|
||||
"2h",
|
||||
"1d"
|
||||
],
|
||||
"hideTimepicker": false,
|
||||
"fiscalYearStartMonth": 0
|
||||
},
|
||||
"title": "V11 No-Op Migration Test Dashboard",
|
||||
"variables": [
|
||||
{
|
||||
"kind": "QueryVariable",
|
||||
"spec": {
|
||||
"name": "server",
|
||||
"current": {
|
||||
"text": "",
|
||||
"value": ""
|
||||
},
|
||||
"hide": "dontHide",
|
||||
"refresh": "onDashboardLoad",
|
||||
"skipUrlSync": false,
|
||||
"query": {
|
||||
"kind": "DataQuery",
|
||||
"group": "",
|
||||
"version": "v0",
|
||||
"spec": {
|
||||
"__legacyStringValue": "label_values(server)"
|
||||
}
|
||||
},
|
||||
"regex": "",
|
||||
"sort": "disabled",
|
||||
"options": [],
|
||||
"multi": false,
|
||||
"includeAll": false,
|
||||
"allowCustomValue": true
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"status": {}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
{
|
||||
"kind": "Dashboard",
|
||||
"apiVersion": "dashboard.grafana.app/v0alpha1",
|
||||
"metadata": {
|
||||
"name": "v12.template-variables.v42"
|
||||
},
|
||||
"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"
|
||||
}
|
||||
]
|
||||
},
|
||||
"editable": true,
|
||||
"fiscalYearStartMonth": 0,
|
||||
"graphTooltip": 0,
|
||||
"links": [],
|
||||
"panels": [],
|
||||
"refresh": "",
|
||||
"schemaVersion": 42,
|
||||
"tags": [],
|
||||
"templating": {
|
||||
"list": [
|
||||
{
|
||||
"name": "refresh_true_var",
|
||||
"options": [],
|
||||
"refresh": 1,
|
||||
"type": "query"
|
||||
},
|
||||
{
|
||||
"name": "refresh_false_var",
|
||||
"options": [],
|
||||
"refresh": 1,
|
||||
"type": "query"
|
||||
},
|
||||
{
|
||||
"hide": 2,
|
||||
"hideVariable": true,
|
||||
"name": "hide_variable_var",
|
||||
"options": [],
|
||||
"refresh": 1,
|
||||
"type": "query"
|
||||
},
|
||||
{
|
||||
"hide": 1,
|
||||
"hideLabel": true,
|
||||
"name": "hide_label_var",
|
||||
"options": [],
|
||||
"refresh": 1,
|
||||
"type": "query"
|
||||
},
|
||||
{
|
||||
"hide": 2,
|
||||
"hideLabel": true,
|
||||
"hideVariable": true,
|
||||
"name": "priority_var",
|
||||
"options": [],
|
||||
"refresh": 1,
|
||||
"type": "query"
|
||||
},
|
||||
{
|
||||
"name": "no_properties_var",
|
||||
"options": [],
|
||||
"refresh": 1,
|
||||
"type": "query"
|
||||
}
|
||||
]
|
||||
},
|
||||
"time": {
|
||||
"from": "now-6h",
|
||||
"to": "now"
|
||||
},
|
||||
"timepicker": {},
|
||||
"timezone": "",
|
||||
"title": "V12 Template Variables Migration Test",
|
||||
"weekStart": ""
|
||||
},
|
||||
"status": {
|
||||
"conversion": {
|
||||
"failed": false,
|
||||
"storedVersion": "v1beta1"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,207 @@
|
||||
{
|
||||
"kind": "Dashboard",
|
||||
"apiVersion": "dashboard.grafana.app/v2alpha1",
|
||||
"metadata": {
|
||||
"name": "v12.template-variables.v42"
|
||||
},
|
||||
"spec": {
|
||||
"annotations": [
|
||||
{
|
||||
"kind": "AnnotationQuery",
|
||||
"spec": {
|
||||
"datasource": {
|
||||
"type": "grafana",
|
||||
"uid": "-- Grafana --"
|
||||
},
|
||||
"query": {
|
||||
"kind": "DataQuery",
|
||||
"spec": {}
|
||||
},
|
||||
"enable": true,
|
||||
"hide": true,
|
||||
"iconColor": "rgba(0, 211, 255, 1)",
|
||||
"name": "Annotations \u0026 Alerts",
|
||||
"builtIn": true,
|
||||
"legacyOptions": {
|
||||
"type": "dashboard"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"cursorSync": "Off",
|
||||
"editable": true,
|
||||
"elements": {},
|
||||
"layout": {
|
||||
"kind": "GridLayout",
|
||||
"spec": {
|
||||
"items": []
|
||||
}
|
||||
},
|
||||
"links": [],
|
||||
"liveNow": false,
|
||||
"preload": false,
|
||||
"tags": [],
|
||||
"timeSettings": {
|
||||
"timezone": "",
|
||||
"from": "now-6h",
|
||||
"to": "now",
|
||||
"autoRefresh": "",
|
||||
"autoRefreshIntervals": [
|
||||
"5s",
|
||||
"10s",
|
||||
"30s",
|
||||
"1m",
|
||||
"5m",
|
||||
"15m",
|
||||
"30m",
|
||||
"1h",
|
||||
"2h",
|
||||
"1d"
|
||||
],
|
||||
"hideTimepicker": false,
|
||||
"fiscalYearStartMonth": 0
|
||||
},
|
||||
"title": "V12 Template Variables Migration Test",
|
||||
"variables": [
|
||||
{
|
||||
"kind": "QueryVariable",
|
||||
"spec": {
|
||||
"name": "refresh_true_var",
|
||||
"current": {
|
||||
"text": "",
|
||||
"value": ""
|
||||
},
|
||||
"hide": "dontHide",
|
||||
"refresh": "onDashboardLoad",
|
||||
"skipUrlSync": false,
|
||||
"query": {
|
||||
"kind": "DataQuery",
|
||||
"spec": {}
|
||||
},
|
||||
"regex": "",
|
||||
"sort": "disabled",
|
||||
"options": [],
|
||||
"multi": false,
|
||||
"includeAll": false,
|
||||
"allowCustomValue": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "QueryVariable",
|
||||
"spec": {
|
||||
"name": "refresh_false_var",
|
||||
"current": {
|
||||
"text": "",
|
||||
"value": ""
|
||||
},
|
||||
"hide": "dontHide",
|
||||
"refresh": "onDashboardLoad",
|
||||
"skipUrlSync": false,
|
||||
"query": {
|
||||
"kind": "DataQuery",
|
||||
"spec": {}
|
||||
},
|
||||
"regex": "",
|
||||
"sort": "disabled",
|
||||
"options": [],
|
||||
"multi": false,
|
||||
"includeAll": false,
|
||||
"allowCustomValue": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "QueryVariable",
|
||||
"spec": {
|
||||
"name": "hide_variable_var",
|
||||
"current": {
|
||||
"text": "",
|
||||
"value": ""
|
||||
},
|
||||
"hide": "hideVariable",
|
||||
"refresh": "onDashboardLoad",
|
||||
"skipUrlSync": false,
|
||||
"query": {
|
||||
"kind": "DataQuery",
|
||||
"spec": {}
|
||||
},
|
||||
"regex": "",
|
||||
"sort": "disabled",
|
||||
"options": [],
|
||||
"multi": false,
|
||||
"includeAll": false,
|
||||
"allowCustomValue": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "QueryVariable",
|
||||
"spec": {
|
||||
"name": "hide_label_var",
|
||||
"current": {
|
||||
"text": "",
|
||||
"value": ""
|
||||
},
|
||||
"hide": "hideLabel",
|
||||
"refresh": "onDashboardLoad",
|
||||
"skipUrlSync": false,
|
||||
"query": {
|
||||
"kind": "DataQuery",
|
||||
"spec": {}
|
||||
},
|
||||
"regex": "",
|
||||
"sort": "disabled",
|
||||
"options": [],
|
||||
"multi": false,
|
||||
"includeAll": false,
|
||||
"allowCustomValue": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "QueryVariable",
|
||||
"spec": {
|
||||
"name": "priority_var",
|
||||
"current": {
|
||||
"text": "",
|
||||
"value": ""
|
||||
},
|
||||
"hide": "hideVariable",
|
||||
"refresh": "onDashboardLoad",
|
||||
"skipUrlSync": false,
|
||||
"query": {
|
||||
"kind": "DataQuery",
|
||||
"spec": {}
|
||||
},
|
||||
"regex": "",
|
||||
"sort": "disabled",
|
||||
"options": [],
|
||||
"multi": false,
|
||||
"includeAll": false,
|
||||
"allowCustomValue": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "QueryVariable",
|
||||
"spec": {
|
||||
"name": "no_properties_var",
|
||||
"current": {
|
||||
"text": "",
|
||||
"value": ""
|
||||
},
|
||||
"hide": "dontHide",
|
||||
"refresh": "onDashboardLoad",
|
||||
"skipUrlSync": false,
|
||||
"query": {
|
||||
"kind": "DataQuery",
|
||||
"spec": {}
|
||||
},
|
||||
"regex": "",
|
||||
"sort": "disabled",
|
||||
"options": [],
|
||||
"multi": false,
|
||||
"includeAll": false,
|
||||
"allowCustomValue": true
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"status": {}
|
||||
}
|
||||
@@ -0,0 +1,220 @@
|
||||
{
|
||||
"kind": "Dashboard",
|
||||
"apiVersion": "dashboard.grafana.app/v2beta1",
|
||||
"metadata": {
|
||||
"name": "v12.template-variables.v42"
|
||||
},
|
||||
"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",
|
||||
"editable": true,
|
||||
"elements": {},
|
||||
"layout": {
|
||||
"kind": "GridLayout",
|
||||
"spec": {
|
||||
"items": []
|
||||
}
|
||||
},
|
||||
"links": [],
|
||||
"liveNow": false,
|
||||
"preload": false,
|
||||
"tags": [],
|
||||
"timeSettings": {
|
||||
"timezone": "",
|
||||
"from": "now-6h",
|
||||
"to": "now",
|
||||
"autoRefresh": "",
|
||||
"autoRefreshIntervals": [
|
||||
"5s",
|
||||
"10s",
|
||||
"30s",
|
||||
"1m",
|
||||
"5m",
|
||||
"15m",
|
||||
"30m",
|
||||
"1h",
|
||||
"2h",
|
||||
"1d"
|
||||
],
|
||||
"hideTimepicker": false,
|
||||
"fiscalYearStartMonth": 0
|
||||
},
|
||||
"title": "V12 Template Variables Migration Test",
|
||||
"variables": [
|
||||
{
|
||||
"kind": "QueryVariable",
|
||||
"spec": {
|
||||
"name": "refresh_true_var",
|
||||
"current": {
|
||||
"text": "",
|
||||
"value": ""
|
||||
},
|
||||
"hide": "dontHide",
|
||||
"refresh": "onDashboardLoad",
|
||||
"skipUrlSync": false,
|
||||
"query": {
|
||||
"kind": "DataQuery",
|
||||
"group": "",
|
||||
"version": "v0",
|
||||
"spec": {}
|
||||
},
|
||||
"regex": "",
|
||||
"sort": "disabled",
|
||||
"options": [],
|
||||
"multi": false,
|
||||
"includeAll": false,
|
||||
"allowCustomValue": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "QueryVariable",
|
||||
"spec": {
|
||||
"name": "refresh_false_var",
|
||||
"current": {
|
||||
"text": "",
|
||||
"value": ""
|
||||
},
|
||||
"hide": "dontHide",
|
||||
"refresh": "onDashboardLoad",
|
||||
"skipUrlSync": false,
|
||||
"query": {
|
||||
"kind": "DataQuery",
|
||||
"group": "",
|
||||
"version": "v0",
|
||||
"spec": {}
|
||||
},
|
||||
"regex": "",
|
||||
"sort": "disabled",
|
||||
"options": [],
|
||||
"multi": false,
|
||||
"includeAll": false,
|
||||
"allowCustomValue": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "QueryVariable",
|
||||
"spec": {
|
||||
"name": "hide_variable_var",
|
||||
"current": {
|
||||
"text": "",
|
||||
"value": ""
|
||||
},
|
||||
"hide": "hideVariable",
|
||||
"refresh": "onDashboardLoad",
|
||||
"skipUrlSync": false,
|
||||
"query": {
|
||||
"kind": "DataQuery",
|
||||
"group": "",
|
||||
"version": "v0",
|
||||
"spec": {}
|
||||
},
|
||||
"regex": "",
|
||||
"sort": "disabled",
|
||||
"options": [],
|
||||
"multi": false,
|
||||
"includeAll": false,
|
||||
"allowCustomValue": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "QueryVariable",
|
||||
"spec": {
|
||||
"name": "hide_label_var",
|
||||
"current": {
|
||||
"text": "",
|
||||
"value": ""
|
||||
},
|
||||
"hide": "hideLabel",
|
||||
"refresh": "onDashboardLoad",
|
||||
"skipUrlSync": false,
|
||||
"query": {
|
||||
"kind": "DataQuery",
|
||||
"group": "",
|
||||
"version": "v0",
|
||||
"spec": {}
|
||||
},
|
||||
"regex": "",
|
||||
"sort": "disabled",
|
||||
"options": [],
|
||||
"multi": false,
|
||||
"includeAll": false,
|
||||
"allowCustomValue": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "QueryVariable",
|
||||
"spec": {
|
||||
"name": "priority_var",
|
||||
"current": {
|
||||
"text": "",
|
||||
"value": ""
|
||||
},
|
||||
"hide": "hideVariable",
|
||||
"refresh": "onDashboardLoad",
|
||||
"skipUrlSync": false,
|
||||
"query": {
|
||||
"kind": "DataQuery",
|
||||
"group": "",
|
||||
"version": "v0",
|
||||
"spec": {}
|
||||
},
|
||||
"regex": "",
|
||||
"sort": "disabled",
|
||||
"options": [],
|
||||
"multi": false,
|
||||
"includeAll": false,
|
||||
"allowCustomValue": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "QueryVariable",
|
||||
"spec": {
|
||||
"name": "no_properties_var",
|
||||
"current": {
|
||||
"text": "",
|
||||
"value": ""
|
||||
},
|
||||
"hide": "dontHide",
|
||||
"refresh": "onDashboardLoad",
|
||||
"skipUrlSync": false,
|
||||
"query": {
|
||||
"kind": "DataQuery",
|
||||
"group": "",
|
||||
"version": "v0",
|
||||
"spec": {}
|
||||
},
|
||||
"regex": "",
|
||||
"sort": "disabled",
|
||||
"options": [],
|
||||
"multi": false,
|
||||
"includeAll": false,
|
||||
"allowCustomValue": true
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"status": {}
|
||||
}
|
||||
@@ -0,0 +1,187 @@
|
||||
{
|
||||
"kind": "Dashboard",
|
||||
"apiVersion": "dashboard.grafana.app/v0alpha1",
|
||||
"metadata": {
|
||||
"name": "v13.graph_thresholds.v42"
|
||||
},
|
||||
"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"
|
||||
}
|
||||
]
|
||||
},
|
||||
"editable": true,
|
||||
"fiscalYearStartMonth": 0,
|
||||
"graphTooltip": 0,
|
||||
"links": [],
|
||||
"panels": [
|
||||
{
|
||||
"autoMigrateFrom": "graph",
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"grid": {
|
||||
"threshold1": 200,
|
||||
"threshold1Color": "yellow",
|
||||
"threshold2": 400,
|
||||
"threshold2Color": "red",
|
||||
"thresholdLine": true
|
||||
},
|
||||
"id": 1,
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Graph with Line Thresholds",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"autoMigrateFrom": "graph",
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"grid": {
|
||||
"threshold1": 100,
|
||||
"threshold1Color": "green",
|
||||
"threshold2": 300,
|
||||
"threshold2Color": "blue",
|
||||
"thresholdLine": false
|
||||
},
|
||||
"id": 2,
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Graph with Fill Thresholds",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"autoMigrateFrom": "graph",
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"grid": {
|
||||
"threshold1": 150,
|
||||
"threshold1Color": "orange",
|
||||
"thresholdLine": true
|
||||
},
|
||||
"id": 3,
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Graph with Single Threshold",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"autoMigrateFrom": "graph",
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"grid": {
|
||||
"threshold1": 200,
|
||||
"threshold1Color": "yellow",
|
||||
"thresholdLine": false
|
||||
},
|
||||
"id": 4,
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"thresholds": [
|
||||
{
|
||||
"color": "purple",
|
||||
"colorMode": "custom",
|
||||
"value": 50
|
||||
}
|
||||
],
|
||||
"title": "Graph with Existing Thresholds",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"autoMigrateFrom": "singlestat",
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"id": 5,
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Non-Graph Panel",
|
||||
"type": "stat"
|
||||
}
|
||||
],
|
||||
"refresh": "",
|
||||
"schemaVersion": 42,
|
||||
"tags": [],
|
||||
"templating": {
|
||||
"list": []
|
||||
},
|
||||
"time": {
|
||||
"from": "now-6h",
|
||||
"to": "now"
|
||||
},
|
||||
"timepicker": {},
|
||||
"timezone": "",
|
||||
"title": "V13 Graph Thresholds Migration Test",
|
||||
"weekStart": ""
|
||||
},
|
||||
"status": {
|
||||
"conversion": {
|
||||
"failed": false,
|
||||
"storedVersion": "v1beta1"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,355 @@
|
||||
{
|
||||
"kind": "Dashboard",
|
||||
"apiVersion": "dashboard.grafana.app/v2alpha1",
|
||||
"metadata": {
|
||||
"name": "v13.graph_thresholds.v42"
|
||||
},
|
||||
"spec": {
|
||||
"annotations": [
|
||||
{
|
||||
"kind": "AnnotationQuery",
|
||||
"spec": {
|
||||
"datasource": {
|
||||
"type": "grafana",
|
||||
"uid": "-- Grafana --"
|
||||
},
|
||||
"query": {
|
||||
"kind": "DataQuery",
|
||||
"spec": {}
|
||||
},
|
||||
"enable": true,
|
||||
"hide": true,
|
||||
"iconColor": "rgba(0, 211, 255, 1)",
|
||||
"name": "Annotations \u0026 Alerts",
|
||||
"builtIn": true,
|
||||
"legacyOptions": {
|
||||
"type": "dashboard"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"cursorSync": "Off",
|
||||
"editable": true,
|
||||
"elements": {
|
||||
"panel-1": {
|
||||
"kind": "Panel",
|
||||
"spec": {
|
||||
"id": 1,
|
||||
"title": "Graph with Line Thresholds",
|
||||
"description": "",
|
||||
"links": [],
|
||||
"data": {
|
||||
"kind": "QueryGroup",
|
||||
"spec": {
|
||||
"queries": [
|
||||
{
|
||||
"kind": "PanelQuery",
|
||||
"spec": {
|
||||
"query": {
|
||||
"kind": "DataQuery",
|
||||
"spec": {}
|
||||
},
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"refId": "A",
|
||||
"hidden": false
|
||||
}
|
||||
}
|
||||
],
|
||||
"transformations": [],
|
||||
"queryOptions": {}
|
||||
}
|
||||
},
|
||||
"vizConfig": {
|
||||
"kind": "timeseries",
|
||||
"spec": {
|
||||
"pluginVersion": "",
|
||||
"options": {},
|
||||
"fieldConfig": {
|
||||
"defaults": {},
|
||||
"overrides": []
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"panel-2": {
|
||||
"kind": "Panel",
|
||||
"spec": {
|
||||
"id": 2,
|
||||
"title": "Graph with Fill Thresholds",
|
||||
"description": "",
|
||||
"links": [],
|
||||
"data": {
|
||||
"kind": "QueryGroup",
|
||||
"spec": {
|
||||
"queries": [
|
||||
{
|
||||
"kind": "PanelQuery",
|
||||
"spec": {
|
||||
"query": {
|
||||
"kind": "DataQuery",
|
||||
"spec": {}
|
||||
},
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"refId": "A",
|
||||
"hidden": false
|
||||
}
|
||||
}
|
||||
],
|
||||
"transformations": [],
|
||||
"queryOptions": {}
|
||||
}
|
||||
},
|
||||
"vizConfig": {
|
||||
"kind": "timeseries",
|
||||
"spec": {
|
||||
"pluginVersion": "",
|
||||
"options": {},
|
||||
"fieldConfig": {
|
||||
"defaults": {},
|
||||
"overrides": []
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"panel-3": {
|
||||
"kind": "Panel",
|
||||
"spec": {
|
||||
"id": 3,
|
||||
"title": "Graph with Single Threshold",
|
||||
"description": "",
|
||||
"links": [],
|
||||
"data": {
|
||||
"kind": "QueryGroup",
|
||||
"spec": {
|
||||
"queries": [
|
||||
{
|
||||
"kind": "PanelQuery",
|
||||
"spec": {
|
||||
"query": {
|
||||
"kind": "DataQuery",
|
||||
"spec": {}
|
||||
},
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"refId": "A",
|
||||
"hidden": false
|
||||
}
|
||||
}
|
||||
],
|
||||
"transformations": [],
|
||||
"queryOptions": {}
|
||||
}
|
||||
},
|
||||
"vizConfig": {
|
||||
"kind": "timeseries",
|
||||
"spec": {
|
||||
"pluginVersion": "",
|
||||
"options": {},
|
||||
"fieldConfig": {
|
||||
"defaults": {},
|
||||
"overrides": []
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"panel-4": {
|
||||
"kind": "Panel",
|
||||
"spec": {
|
||||
"id": 4,
|
||||
"title": "Graph with Existing Thresholds",
|
||||
"description": "",
|
||||
"links": [],
|
||||
"data": {
|
||||
"kind": "QueryGroup",
|
||||
"spec": {
|
||||
"queries": [
|
||||
{
|
||||
"kind": "PanelQuery",
|
||||
"spec": {
|
||||
"query": {
|
||||
"kind": "DataQuery",
|
||||
"spec": {}
|
||||
},
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"refId": "A",
|
||||
"hidden": false
|
||||
}
|
||||
}
|
||||
],
|
||||
"transformations": [],
|
||||
"queryOptions": {}
|
||||
}
|
||||
},
|
||||
"vizConfig": {
|
||||
"kind": "timeseries",
|
||||
"spec": {
|
||||
"pluginVersion": "",
|
||||
"options": {},
|
||||
"fieldConfig": {
|
||||
"defaults": {},
|
||||
"overrides": []
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"panel-5": {
|
||||
"kind": "Panel",
|
||||
"spec": {
|
||||
"id": 5,
|
||||
"title": "Non-Graph Panel",
|
||||
"description": "",
|
||||
"links": [],
|
||||
"data": {
|
||||
"kind": "QueryGroup",
|
||||
"spec": {
|
||||
"queries": [
|
||||
{
|
||||
"kind": "PanelQuery",
|
||||
"spec": {
|
||||
"query": {
|
||||
"kind": "DataQuery",
|
||||
"spec": {}
|
||||
},
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"refId": "A",
|
||||
"hidden": false
|
||||
}
|
||||
}
|
||||
],
|
||||
"transformations": [],
|
||||
"queryOptions": {}
|
||||
}
|
||||
},
|
||||
"vizConfig": {
|
||||
"kind": "stat",
|
||||
"spec": {
|
||||
"pluginVersion": "",
|
||||
"options": {},
|
||||
"fieldConfig": {
|
||||
"defaults": {},
|
||||
"overrides": []
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"layout": {
|
||||
"kind": "GridLayout",
|
||||
"spec": {
|
||||
"items": [
|
||||
{
|
||||
"kind": "GridLayoutItem",
|
||||
"spec": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"width": 6,
|
||||
"height": 3,
|
||||
"element": {
|
||||
"kind": "ElementReference",
|
||||
"name": "panel-1"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "GridLayoutItem",
|
||||
"spec": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"width": 6,
|
||||
"height": 3,
|
||||
"element": {
|
||||
"kind": "ElementReference",
|
||||
"name": "panel-2"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "GridLayoutItem",
|
||||
"spec": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"width": 6,
|
||||
"height": 3,
|
||||
"element": {
|
||||
"kind": "ElementReference",
|
||||
"name": "panel-3"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "GridLayoutItem",
|
||||
"spec": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"width": 6,
|
||||
"height": 3,
|
||||
"element": {
|
||||
"kind": "ElementReference",
|
||||
"name": "panel-4"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "GridLayoutItem",
|
||||
"spec": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"width": 6,
|
||||
"height": 3,
|
||||
"element": {
|
||||
"kind": "ElementReference",
|
||||
"name": "panel-5"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"links": [],
|
||||
"liveNow": false,
|
||||
"preload": false,
|
||||
"tags": [],
|
||||
"timeSettings": {
|
||||
"timezone": "",
|
||||
"from": "now-6h",
|
||||
"to": "now",
|
||||
"autoRefresh": "",
|
||||
"autoRefreshIntervals": [
|
||||
"5s",
|
||||
"10s",
|
||||
"30s",
|
||||
"1m",
|
||||
"5m",
|
||||
"15m",
|
||||
"30m",
|
||||
"1h",
|
||||
"2h",
|
||||
"1d"
|
||||
],
|
||||
"hideTimepicker": false,
|
||||
"fiscalYearStartMonth": 0
|
||||
},
|
||||
"title": "V13 Graph Thresholds Migration Test",
|
||||
"variables": []
|
||||
},
|
||||
"status": {}
|
||||
}
|
||||
@@ -0,0 +1,366 @@
|
||||
{
|
||||
"kind": "Dashboard",
|
||||
"apiVersion": "dashboard.grafana.app/v2beta1",
|
||||
"metadata": {
|
||||
"name": "v13.graph_thresholds.v42"
|
||||
},
|
||||
"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",
|
||||
"editable": true,
|
||||
"elements": {
|
||||
"panel-1": {
|
||||
"kind": "Panel",
|
||||
"spec": {
|
||||
"id": 1,
|
||||
"title": "Graph with Line Thresholds",
|
||||
"description": "",
|
||||
"links": [],
|
||||
"data": {
|
||||
"kind": "QueryGroup",
|
||||
"spec": {
|
||||
"queries": [
|
||||
{
|
||||
"kind": "PanelQuery",
|
||||
"spec": {
|
||||
"query": {
|
||||
"kind": "DataQuery",
|
||||
"group": "prometheus",
|
||||
"version": "v0",
|
||||
"datasource": {
|
||||
"name": "default-ds-uid"
|
||||
},
|
||||
"spec": {}
|
||||
},
|
||||
"refId": "A",
|
||||
"hidden": false
|
||||
}
|
||||
}
|
||||
],
|
||||
"transformations": [],
|
||||
"queryOptions": {}
|
||||
}
|
||||
},
|
||||
"vizConfig": {
|
||||
"kind": "VizConfig",
|
||||
"group": "timeseries",
|
||||
"version": "",
|
||||
"spec": {
|
||||
"options": {},
|
||||
"fieldConfig": {
|
||||
"defaults": {},
|
||||
"overrides": []
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"panel-2": {
|
||||
"kind": "Panel",
|
||||
"spec": {
|
||||
"id": 2,
|
||||
"title": "Graph with Fill Thresholds",
|
||||
"description": "",
|
||||
"links": [],
|
||||
"data": {
|
||||
"kind": "QueryGroup",
|
||||
"spec": {
|
||||
"queries": [
|
||||
{
|
||||
"kind": "PanelQuery",
|
||||
"spec": {
|
||||
"query": {
|
||||
"kind": "DataQuery",
|
||||
"group": "prometheus",
|
||||
"version": "v0",
|
||||
"datasource": {
|
||||
"name": "default-ds-uid"
|
||||
},
|
||||
"spec": {}
|
||||
},
|
||||
"refId": "A",
|
||||
"hidden": false
|
||||
}
|
||||
}
|
||||
],
|
||||
"transformations": [],
|
||||
"queryOptions": {}
|
||||
}
|
||||
},
|
||||
"vizConfig": {
|
||||
"kind": "VizConfig",
|
||||
"group": "timeseries",
|
||||
"version": "",
|
||||
"spec": {
|
||||
"options": {},
|
||||
"fieldConfig": {
|
||||
"defaults": {},
|
||||
"overrides": []
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"panel-3": {
|
||||
"kind": "Panel",
|
||||
"spec": {
|
||||
"id": 3,
|
||||
"title": "Graph with Single Threshold",
|
||||
"description": "",
|
||||
"links": [],
|
||||
"data": {
|
||||
"kind": "QueryGroup",
|
||||
"spec": {
|
||||
"queries": [
|
||||
{
|
||||
"kind": "PanelQuery",
|
||||
"spec": {
|
||||
"query": {
|
||||
"kind": "DataQuery",
|
||||
"group": "prometheus",
|
||||
"version": "v0",
|
||||
"datasource": {
|
||||
"name": "default-ds-uid"
|
||||
},
|
||||
"spec": {}
|
||||
},
|
||||
"refId": "A",
|
||||
"hidden": false
|
||||
}
|
||||
}
|
||||
],
|
||||
"transformations": [],
|
||||
"queryOptions": {}
|
||||
}
|
||||
},
|
||||
"vizConfig": {
|
||||
"kind": "VizConfig",
|
||||
"group": "timeseries",
|
||||
"version": "",
|
||||
"spec": {
|
||||
"options": {},
|
||||
"fieldConfig": {
|
||||
"defaults": {},
|
||||
"overrides": []
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"panel-4": {
|
||||
"kind": "Panel",
|
||||
"spec": {
|
||||
"id": 4,
|
||||
"title": "Graph with Existing Thresholds",
|
||||
"description": "",
|
||||
"links": [],
|
||||
"data": {
|
||||
"kind": "QueryGroup",
|
||||
"spec": {
|
||||
"queries": [
|
||||
{
|
||||
"kind": "PanelQuery",
|
||||
"spec": {
|
||||
"query": {
|
||||
"kind": "DataQuery",
|
||||
"group": "prometheus",
|
||||
"version": "v0",
|
||||
"datasource": {
|
||||
"name": "default-ds-uid"
|
||||
},
|
||||
"spec": {}
|
||||
},
|
||||
"refId": "A",
|
||||
"hidden": false
|
||||
}
|
||||
}
|
||||
],
|
||||
"transformations": [],
|
||||
"queryOptions": {}
|
||||
}
|
||||
},
|
||||
"vizConfig": {
|
||||
"kind": "VizConfig",
|
||||
"group": "timeseries",
|
||||
"version": "",
|
||||
"spec": {
|
||||
"options": {},
|
||||
"fieldConfig": {
|
||||
"defaults": {},
|
||||
"overrides": []
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"panel-5": {
|
||||
"kind": "Panel",
|
||||
"spec": {
|
||||
"id": 5,
|
||||
"title": "Non-Graph Panel",
|
||||
"description": "",
|
||||
"links": [],
|
||||
"data": {
|
||||
"kind": "QueryGroup",
|
||||
"spec": {
|
||||
"queries": [
|
||||
{
|
||||
"kind": "PanelQuery",
|
||||
"spec": {
|
||||
"query": {
|
||||
"kind": "DataQuery",
|
||||
"group": "prometheus",
|
||||
"version": "v0",
|
||||
"datasource": {
|
||||
"name": "default-ds-uid"
|
||||
},
|
||||
"spec": {}
|
||||
},
|
||||
"refId": "A",
|
||||
"hidden": false
|
||||
}
|
||||
}
|
||||
],
|
||||
"transformations": [],
|
||||
"queryOptions": {}
|
||||
}
|
||||
},
|
||||
"vizConfig": {
|
||||
"kind": "VizConfig",
|
||||
"group": "stat",
|
||||
"version": "",
|
||||
"spec": {
|
||||
"options": {},
|
||||
"fieldConfig": {
|
||||
"defaults": {},
|
||||
"overrides": []
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"layout": {
|
||||
"kind": "GridLayout",
|
||||
"spec": {
|
||||
"items": [
|
||||
{
|
||||
"kind": "GridLayoutItem",
|
||||
"spec": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"width": 6,
|
||||
"height": 3,
|
||||
"element": {
|
||||
"kind": "ElementReference",
|
||||
"name": "panel-1"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "GridLayoutItem",
|
||||
"spec": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"width": 6,
|
||||
"height": 3,
|
||||
"element": {
|
||||
"kind": "ElementReference",
|
||||
"name": "panel-2"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "GridLayoutItem",
|
||||
"spec": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"width": 6,
|
||||
"height": 3,
|
||||
"element": {
|
||||
"kind": "ElementReference",
|
||||
"name": "panel-3"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "GridLayoutItem",
|
||||
"spec": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"width": 6,
|
||||
"height": 3,
|
||||
"element": {
|
||||
"kind": "ElementReference",
|
||||
"name": "panel-4"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "GridLayoutItem",
|
||||
"spec": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"width": 6,
|
||||
"height": 3,
|
||||
"element": {
|
||||
"kind": "ElementReference",
|
||||
"name": "panel-5"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"links": [],
|
||||
"liveNow": false,
|
||||
"preload": false,
|
||||
"tags": [],
|
||||
"timeSettings": {
|
||||
"timezone": "",
|
||||
"from": "now-6h",
|
||||
"to": "now",
|
||||
"autoRefresh": "",
|
||||
"autoRefreshIntervals": [
|
||||
"5s",
|
||||
"10s",
|
||||
"30s",
|
||||
"1m",
|
||||
"5m",
|
||||
"15m",
|
||||
"30m",
|
||||
"1h",
|
||||
"2h",
|
||||
"1d"
|
||||
],
|
||||
"hideTimepicker": false,
|
||||
"fiscalYearStartMonth": 0
|
||||
},
|
||||
"title": "V13 Graph Thresholds Migration Test",
|
||||
"variables": []
|
||||
},
|
||||
"status": {}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
{
|
||||
"kind": "Dashboard",
|
||||
"apiVersion": "dashboard.grafana.app/v0alpha1",
|
||||
"metadata": {
|
||||
"name": "v13.minimal_graph_config.v42"
|
||||
},
|
||||
"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"
|
||||
}
|
||||
]
|
||||
},
|
||||
"editable": true,
|
||||
"fiscalYearStartMonth": 0,
|
||||
"graphTooltip": 0,
|
||||
"links": [],
|
||||
"panels": [
|
||||
{
|
||||
"autoMigrateFrom": "graph",
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "gdev-prometheus"
|
||||
},
|
||||
"id": 4,
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "gdev-prometheus"
|
||||
},
|
||||
"editorMode": "builder",
|
||||
"expr": "{\"a.utf8.metric 🤘\", job=\"prometheus-utf8\"}",
|
||||
"instant": false,
|
||||
"legendFormat": "__auto",
|
||||
"range": true,
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"type": "timeseries"
|
||||
}
|
||||
],
|
||||
"refresh": "",
|
||||
"schemaVersion": 42,
|
||||
"tags": [],
|
||||
"templating": {
|
||||
"list": []
|
||||
},
|
||||
"time": {
|
||||
"from": "now-6h",
|
||||
"to": "now"
|
||||
},
|
||||
"timepicker": {},
|
||||
"timezone": "browser",
|
||||
"title": "Dashboard with minimal graph panel settings",
|
||||
"weekStart": ""
|
||||
},
|
||||
"status": {
|
||||
"conversion": {
|
||||
"failed": false,
|
||||
"storedVersion": "v1beta1"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
{
|
||||
"kind": "Dashboard",
|
||||
"apiVersion": "dashboard.grafana.app/v2alpha1",
|
||||
"metadata": {
|
||||
"name": "v13.minimal_graph_config.v42"
|
||||
},
|
||||
"spec": {
|
||||
"annotations": [
|
||||
{
|
||||
"kind": "AnnotationQuery",
|
||||
"spec": {
|
||||
"datasource": {
|
||||
"type": "grafana",
|
||||
"uid": "-- Grafana --"
|
||||
},
|
||||
"query": {
|
||||
"kind": "DataQuery",
|
||||
"spec": {}
|
||||
},
|
||||
"enable": true,
|
||||
"hide": true,
|
||||
"iconColor": "rgba(0, 211, 255, 1)",
|
||||
"name": "Annotations \u0026 Alerts",
|
||||
"builtIn": true,
|
||||
"legacyOptions": {
|
||||
"type": "dashboard"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"cursorSync": "Off",
|
||||
"editable": true,
|
||||
"elements": {
|
||||
"panel-4": {
|
||||
"kind": "Panel",
|
||||
"spec": {
|
||||
"id": 4,
|
||||
"title": "",
|
||||
"description": "",
|
||||
"links": [],
|
||||
"data": {
|
||||
"kind": "QueryGroup",
|
||||
"spec": {
|
||||
"queries": [
|
||||
{
|
||||
"kind": "PanelQuery",
|
||||
"spec": {
|
||||
"query": {
|
||||
"kind": "DataQuery",
|
||||
"spec": {
|
||||
"editorMode": "builder",
|
||||
"expr": "{\"a.utf8.metric 🤘\", job=\"prometheus-utf8\"}",
|
||||
"instant": false,
|
||||
"legendFormat": "__auto",
|
||||
"range": true
|
||||
}
|
||||
},
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "gdev-prometheus"
|
||||
},
|
||||
"refId": "A",
|
||||
"hidden": false
|
||||
}
|
||||
}
|
||||
],
|
||||
"transformations": [],
|
||||
"queryOptions": {}
|
||||
}
|
||||
},
|
||||
"vizConfig": {
|
||||
"kind": "timeseries",
|
||||
"spec": {
|
||||
"pluginVersion": "",
|
||||
"options": {},
|
||||
"fieldConfig": {
|
||||
"defaults": {},
|
||||
"overrides": []
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"layout": {
|
||||
"kind": "GridLayout",
|
||||
"spec": {
|
||||
"items": [
|
||||
{
|
||||
"kind": "GridLayoutItem",
|
||||
"spec": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"width": 6,
|
||||
"height": 3,
|
||||
"element": {
|
||||
"kind": "ElementReference",
|
||||
"name": "panel-4"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"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 minimal graph panel settings",
|
||||
"variables": []
|
||||
},
|
||||
"status": {}
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
{
|
||||
"kind": "Dashboard",
|
||||
"apiVersion": "dashboard.grafana.app/v2beta1",
|
||||
"metadata": {
|
||||
"name": "v13.minimal_graph_config.v42"
|
||||
},
|
||||
"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",
|
||||
"editable": true,
|
||||
"elements": {
|
||||
"panel-4": {
|
||||
"kind": "Panel",
|
||||
"spec": {
|
||||
"id": 4,
|
||||
"title": "",
|
||||
"description": "",
|
||||
"links": [],
|
||||
"data": {
|
||||
"kind": "QueryGroup",
|
||||
"spec": {
|
||||
"queries": [
|
||||
{
|
||||
"kind": "PanelQuery",
|
||||
"spec": {
|
||||
"query": {
|
||||
"kind": "DataQuery",
|
||||
"group": "prometheus",
|
||||
"version": "v0",
|
||||
"datasource": {
|
||||
"name": "gdev-prometheus"
|
||||
},
|
||||
"spec": {
|
||||
"editorMode": "builder",
|
||||
"expr": "{\"a.utf8.metric 🤘\", job=\"prometheus-utf8\"}",
|
||||
"instant": false,
|
||||
"legendFormat": "__auto",
|
||||
"range": true
|
||||
}
|
||||
},
|
||||
"refId": "A",
|
||||
"hidden": false
|
||||
}
|
||||
}
|
||||
],
|
||||
"transformations": [],
|
||||
"queryOptions": {}
|
||||
}
|
||||
},
|
||||
"vizConfig": {
|
||||
"kind": "VizConfig",
|
||||
"group": "timeseries",
|
||||
"version": "",
|
||||
"spec": {
|
||||
"options": {},
|
||||
"fieldConfig": {
|
||||
"defaults": {},
|
||||
"overrides": []
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"layout": {
|
||||
"kind": "GridLayout",
|
||||
"spec": {
|
||||
"items": [
|
||||
{
|
||||
"kind": "GridLayoutItem",
|
||||
"spec": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"width": 6,
|
||||
"height": 3,
|
||||
"element": {
|
||||
"kind": "ElementReference",
|
||||
"name": "panel-4"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"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 minimal graph panel settings",
|
||||
"variables": []
|
||||
},
|
||||
"status": {}
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
{
|
||||
"kind": "Dashboard",
|
||||
"apiVersion": "dashboard.grafana.app/v0alpha1",
|
||||
"metadata": {
|
||||
"name": "v14.shared_crosshair_to_graph_tooltip.v42"
|
||||
},
|
||||
"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"
|
||||
}
|
||||
]
|
||||
},
|
||||
"editable": true,
|
||||
"fiscalYearStartMonth": 0,
|
||||
"graphTooltip": 1,
|
||||
"links": [],
|
||||
"panels": [
|
||||
{
|
||||
"autoMigrateFrom": "graph",
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"id": 1,
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"expr": "cpu_usage",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "CPU Usage Over Time",
|
||||
"type": "timeseries",
|
||||
"yAxes": [
|
||||
{
|
||||
"show": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"autoMigrateFrom": "graph",
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"id": 2,
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"expr": "memory_usage",
|
||||
"refId": "B"
|
||||
}
|
||||
],
|
||||
"title": "Memory Usage",
|
||||
"type": "timeseries",
|
||||
"yAxes": [
|
||||
{
|
||||
"max": 100,
|
||||
"min": 0,
|
||||
"show": true
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"refresh": "",
|
||||
"schemaVersion": 42,
|
||||
"tags": [],
|
||||
"templating": {
|
||||
"list": [
|
||||
{
|
||||
"datasource": "prometheus",
|
||||
"name": "server",
|
||||
"options": [],
|
||||
"query": "label_values(server)",
|
||||
"refresh": 1,
|
||||
"type": "query"
|
||||
}
|
||||
]
|
||||
},
|
||||
"time": {
|
||||
"from": "now-1h",
|
||||
"to": "now"
|
||||
},
|
||||
"timepicker": {
|
||||
"refresh_intervals": [
|
||||
"5s",
|
||||
"10s",
|
||||
"30s",
|
||||
"1m",
|
||||
"5m",
|
||||
"15m",
|
||||
"30m",
|
||||
"1h",
|
||||
"2h",
|
||||
"1d"
|
||||
]
|
||||
},
|
||||
"timezone": "",
|
||||
"title": "V14 Shared Crosshair Migration Test Dashboard",
|
||||
"weekStart": ""
|
||||
},
|
||||
"status": {
|
||||
"conversion": {
|
||||
"failed": false,
|
||||
"storedVersion": "v1beta1"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,214 @@
|
||||
{
|
||||
"kind": "Dashboard",
|
||||
"apiVersion": "dashboard.grafana.app/v2alpha1",
|
||||
"metadata": {
|
||||
"name": "v14.shared_crosshair_to_graph_tooltip.v42"
|
||||
},
|
||||
"spec": {
|
||||
"annotations": [
|
||||
{
|
||||
"kind": "AnnotationQuery",
|
||||
"spec": {
|
||||
"datasource": {
|
||||
"type": "grafana",
|
||||
"uid": "-- Grafana --"
|
||||
},
|
||||
"query": {
|
||||
"kind": "DataQuery",
|
||||
"spec": {}
|
||||
},
|
||||
"enable": true,
|
||||
"hide": true,
|
||||
"iconColor": "rgba(0, 211, 255, 1)",
|
||||
"name": "Annotations \u0026 Alerts",
|
||||
"builtIn": true,
|
||||
"legacyOptions": {
|
||||
"type": "dashboard"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"cursorSync": "Crosshair",
|
||||
"editable": true,
|
||||
"elements": {
|
||||
"panel-1": {
|
||||
"kind": "Panel",
|
||||
"spec": {
|
||||
"id": 1,
|
||||
"title": "CPU Usage Over Time",
|
||||
"description": "",
|
||||
"links": [],
|
||||
"data": {
|
||||
"kind": "QueryGroup",
|
||||
"spec": {
|
||||
"queries": [
|
||||
{
|
||||
"kind": "PanelQuery",
|
||||
"spec": {
|
||||
"query": {
|
||||
"kind": "DataQuery",
|
||||
"spec": {
|
||||
"expr": "cpu_usage"
|
||||
}
|
||||
},
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"refId": "A",
|
||||
"hidden": false
|
||||
}
|
||||
}
|
||||
],
|
||||
"transformations": [],
|
||||
"queryOptions": {}
|
||||
}
|
||||
},
|
||||
"vizConfig": {
|
||||
"kind": "timeseries",
|
||||
"spec": {
|
||||
"pluginVersion": "",
|
||||
"options": {},
|
||||
"fieldConfig": {
|
||||
"defaults": {},
|
||||
"overrides": []
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"panel-2": {
|
||||
"kind": "Panel",
|
||||
"spec": {
|
||||
"id": 2,
|
||||
"title": "Memory Usage",
|
||||
"description": "",
|
||||
"links": [],
|
||||
"data": {
|
||||
"kind": "QueryGroup",
|
||||
"spec": {
|
||||
"queries": [
|
||||
{
|
||||
"kind": "PanelQuery",
|
||||
"spec": {
|
||||
"query": {
|
||||
"kind": "DataQuery",
|
||||
"spec": {
|
||||
"expr": "memory_usage"
|
||||
}
|
||||
},
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"refId": "B",
|
||||
"hidden": false
|
||||
}
|
||||
}
|
||||
],
|
||||
"transformations": [],
|
||||
"queryOptions": {}
|
||||
}
|
||||
},
|
||||
"vizConfig": {
|
||||
"kind": "timeseries",
|
||||
"spec": {
|
||||
"pluginVersion": "",
|
||||
"options": {},
|
||||
"fieldConfig": {
|
||||
"defaults": {},
|
||||
"overrides": []
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"layout": {
|
||||
"kind": "GridLayout",
|
||||
"spec": {
|
||||
"items": [
|
||||
{
|
||||
"kind": "GridLayoutItem",
|
||||
"spec": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"width": 6,
|
||||
"height": 3,
|
||||
"element": {
|
||||
"kind": "ElementReference",
|
||||
"name": "panel-1"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "GridLayoutItem",
|
||||
"spec": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"width": 6,
|
||||
"height": 3,
|
||||
"element": {
|
||||
"kind": "ElementReference",
|
||||
"name": "panel-2"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"links": [],
|
||||
"liveNow": false,
|
||||
"preload": false,
|
||||
"tags": [],
|
||||
"timeSettings": {
|
||||
"timezone": "",
|
||||
"from": "now-1h",
|
||||
"to": "now",
|
||||
"autoRefresh": "",
|
||||
"autoRefreshIntervals": [
|
||||
"5s",
|
||||
"10s",
|
||||
"30s",
|
||||
"1m",
|
||||
"5m",
|
||||
"15m",
|
||||
"30m",
|
||||
"1h",
|
||||
"2h",
|
||||
"1d"
|
||||
],
|
||||
"hideTimepicker": false,
|
||||
"fiscalYearStartMonth": 0
|
||||
},
|
||||
"title": "V14 Shared Crosshair Migration Test Dashboard",
|
||||
"variables": [
|
||||
{
|
||||
"kind": "QueryVariable",
|
||||
"spec": {
|
||||
"name": "server",
|
||||
"current": {
|
||||
"text": "",
|
||||
"value": ""
|
||||
},
|
||||
"hide": "dontHide",
|
||||
"refresh": "onDashboardLoad",
|
||||
"skipUrlSync": false,
|
||||
"query": {
|
||||
"kind": "DataQuery",
|
||||
"spec": {
|
||||
"__legacyStringValue": "label_values(server)"
|
||||
}
|
||||
},
|
||||
"regex": "",
|
||||
"sort": "disabled",
|
||||
"options": [],
|
||||
"multi": false,
|
||||
"includeAll": false,
|
||||
"allowCustomValue": true
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"status": {}
|
||||
}
|
||||
@@ -0,0 +1,221 @@
|
||||
{
|
||||
"kind": "Dashboard",
|
||||
"apiVersion": "dashboard.grafana.app/v2beta1",
|
||||
"metadata": {
|
||||
"name": "v14.shared_crosshair_to_graph_tooltip.v42"
|
||||
},
|
||||
"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": "Crosshair",
|
||||
"editable": true,
|
||||
"elements": {
|
||||
"panel-1": {
|
||||
"kind": "Panel",
|
||||
"spec": {
|
||||
"id": 1,
|
||||
"title": "CPU Usage Over Time",
|
||||
"description": "",
|
||||
"links": [],
|
||||
"data": {
|
||||
"kind": "QueryGroup",
|
||||
"spec": {
|
||||
"queries": [
|
||||
{
|
||||
"kind": "PanelQuery",
|
||||
"spec": {
|
||||
"query": {
|
||||
"kind": "DataQuery",
|
||||
"group": "prometheus",
|
||||
"version": "v0",
|
||||
"datasource": {
|
||||
"name": "default-ds-uid"
|
||||
},
|
||||
"spec": {
|
||||
"expr": "cpu_usage"
|
||||
}
|
||||
},
|
||||
"refId": "A",
|
||||
"hidden": false
|
||||
}
|
||||
}
|
||||
],
|
||||
"transformations": [],
|
||||
"queryOptions": {}
|
||||
}
|
||||
},
|
||||
"vizConfig": {
|
||||
"kind": "VizConfig",
|
||||
"group": "timeseries",
|
||||
"version": "",
|
||||
"spec": {
|
||||
"options": {},
|
||||
"fieldConfig": {
|
||||
"defaults": {},
|
||||
"overrides": []
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"panel-2": {
|
||||
"kind": "Panel",
|
||||
"spec": {
|
||||
"id": 2,
|
||||
"title": "Memory Usage",
|
||||
"description": "",
|
||||
"links": [],
|
||||
"data": {
|
||||
"kind": "QueryGroup",
|
||||
"spec": {
|
||||
"queries": [
|
||||
{
|
||||
"kind": "PanelQuery",
|
||||
"spec": {
|
||||
"query": {
|
||||
"kind": "DataQuery",
|
||||
"group": "prometheus",
|
||||
"version": "v0",
|
||||
"datasource": {
|
||||
"name": "default-ds-uid"
|
||||
},
|
||||
"spec": {
|
||||
"expr": "memory_usage"
|
||||
}
|
||||
},
|
||||
"refId": "B",
|
||||
"hidden": false
|
||||
}
|
||||
}
|
||||
],
|
||||
"transformations": [],
|
||||
"queryOptions": {}
|
||||
}
|
||||
},
|
||||
"vizConfig": {
|
||||
"kind": "VizConfig",
|
||||
"group": "timeseries",
|
||||
"version": "",
|
||||
"spec": {
|
||||
"options": {},
|
||||
"fieldConfig": {
|
||||
"defaults": {},
|
||||
"overrides": []
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"layout": {
|
||||
"kind": "GridLayout",
|
||||
"spec": {
|
||||
"items": [
|
||||
{
|
||||
"kind": "GridLayoutItem",
|
||||
"spec": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"width": 6,
|
||||
"height": 3,
|
||||
"element": {
|
||||
"kind": "ElementReference",
|
||||
"name": "panel-1"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "GridLayoutItem",
|
||||
"spec": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"width": 6,
|
||||
"height": 3,
|
||||
"element": {
|
||||
"kind": "ElementReference",
|
||||
"name": "panel-2"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"links": [],
|
||||
"liveNow": false,
|
||||
"preload": false,
|
||||
"tags": [],
|
||||
"timeSettings": {
|
||||
"timezone": "",
|
||||
"from": "now-1h",
|
||||
"to": "now",
|
||||
"autoRefresh": "",
|
||||
"autoRefreshIntervals": [
|
||||
"5s",
|
||||
"10s",
|
||||
"30s",
|
||||
"1m",
|
||||
"5m",
|
||||
"15m",
|
||||
"30m",
|
||||
"1h",
|
||||
"2h",
|
||||
"1d"
|
||||
],
|
||||
"hideTimepicker": false,
|
||||
"fiscalYearStartMonth": 0
|
||||
},
|
||||
"title": "V14 Shared Crosshair Migration Test Dashboard",
|
||||
"variables": [
|
||||
{
|
||||
"kind": "QueryVariable",
|
||||
"spec": {
|
||||
"name": "server",
|
||||
"current": {
|
||||
"text": "",
|
||||
"value": ""
|
||||
},
|
||||
"hide": "dontHide",
|
||||
"refresh": "onDashboardLoad",
|
||||
"skipUrlSync": false,
|
||||
"query": {
|
||||
"kind": "DataQuery",
|
||||
"group": "",
|
||||
"version": "v0",
|
||||
"spec": {
|
||||
"__legacyStringValue": "label_values(server)"
|
||||
}
|
||||
},
|
||||
"regex": "",
|
||||
"sort": "disabled",
|
||||
"options": [],
|
||||
"multi": false,
|
||||
"includeAll": false,
|
||||
"allowCustomValue": true
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"status": {}
|
||||
}
|
||||
@@ -0,0 +1,813 @@
|
||||
{
|
||||
"kind": "Dashboard",
|
||||
"apiVersion": "dashboard.grafana.app/v0alpha1",
|
||||
"metadata": {
|
||||
"name": "v15.mimir_rollout_debugging.v42"
|
||||
},
|
||||
"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"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"uid": "$datasource"
|
||||
},
|
||||
"enable": true,
|
||||
"expr": "up",
|
||||
"hide": false,
|
||||
"iconColor": "rgba(255, 96, 96, 1)",
|
||||
"name": "rollouts",
|
||||
"showIn": 0,
|
||||
"tags": [],
|
||||
"titleFormat": "Rollout was underway in {{cluster}}/{{namespace}}",
|
||||
"type": "tags"
|
||||
}
|
||||
]
|
||||
},
|
||||
"editable": false,
|
||||
"fiscalYearStartMonth": 0,
|
||||
"graphTooltip": 1,
|
||||
"links": [
|
||||
{
|
||||
"asDropdown": true,
|
||||
"icon": "external link",
|
||||
"includeVars": true,
|
||||
"keepTime": true,
|
||||
"tags": [
|
||||
"show-in-mimir-links-dropdown"
|
||||
],
|
||||
"targetBlank": false,
|
||||
"title": "Mimir dashboards",
|
||||
"type": "dashboards"
|
||||
}
|
||||
],
|
||||
"panels": [
|
||||
{
|
||||
"collapsed": false,
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 19,
|
||||
"w": 24,
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
"id": 7,
|
||||
"panels": [],
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Rollout progress",
|
||||
"type": "row"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"uid": "$datasource"
|
||||
},
|
||||
"description": "### Versions running\nShows the versions reported by each running pod.\n\nThe rollout will fail if any pod is not running the expected version.\n\nPods in green are running the expected version, while pods running other versions are shown in orange.\n\n",
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"fixedColor": "orange",
|
||||
"mode": "shades"
|
||||
},
|
||||
"custom": {
|
||||
"axisCenteredZero": false,
|
||||
"axisColorMode": "text",
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"fillOpacity": 80,
|
||||
"gradientMode": "none",
|
||||
"hideFrom": {
|
||||
"legend": false,
|
||||
"tooltip": false,
|
||||
"viz": false
|
||||
},
|
||||
"lineWidth": 1,
|
||||
"scaleDistribution": {
|
||||
"type": "linear"
|
||||
},
|
||||
"thresholdsStyle": {
|
||||
"mode": "off"
|
||||
}
|
||||
},
|
||||
"mappings": [],
|
||||
"max": 1,
|
||||
"min": 0,
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": []
|
||||
},
|
||||
"unit": "short"
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"matcher": {
|
||||
"id": "byRegexp",
|
||||
"options": "/.*(target)/"
|
||||
},
|
||||
"properties": [
|
||||
{
|
||||
"id": "color",
|
||||
"value": {
|
||||
"fixedColor": "green",
|
||||
"mode": "fixed"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 19,
|
||||
"w": 8,
|
||||
"x": 0,
|
||||
"y": 1
|
||||
},
|
||||
"id": 1,
|
||||
"options": {
|
||||
"barRadius": 0,
|
||||
"barWidth": 0.97,
|
||||
"fullHighlight": false,
|
||||
"groupWidth": 0.7,
|
||||
"legend": {
|
||||
"calcs": [],
|
||||
"displayMode": "list",
|
||||
"placement": "bottom",
|
||||
"showLegend": true
|
||||
},
|
||||
"orientation": "horizontal",
|
||||
"showValue": "auto",
|
||||
"stacking": "percent",
|
||||
"tooltip": {
|
||||
"mode": "single",
|
||||
"sort": "none"
|
||||
},
|
||||
"xField": "job\\version",
|
||||
"xTickLabelRotation": 0,
|
||||
"xTickLabelSpacing": 0
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"uid": "$datasource"
|
||||
},
|
||||
"expr": "sum by (job, version) (up{job=~\".*\"})",
|
||||
"format": "table",
|
||||
"instant": true,
|
||||
"legendFormat": "__auto",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Versions running",
|
||||
"transformations": [
|
||||
{
|
||||
"id": "groupingToMatrix",
|
||||
"options": {
|
||||
"columnField": "version",
|
||||
"rowField": "job",
|
||||
"valueField": "Value"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "sortBy",
|
||||
"options": {
|
||||
"sort": [
|
||||
{
|
||||
"field": "job\\version"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"type": "barchart"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"uid": "$datasource"
|
||||
},
|
||||
"description": "### Deployment rollout progress\nShows the number of pods for each `Deployment` that match the desired configuration, as a proportion of the desired number of pods.\n\nThe rollout will fail if insufficient pods match the desired configuration for any `Deployment`.\n\nPods in green match the desired configuration, while pods that do not match the desired configuration are shown in orange.\n\n",
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "thresholds"
|
||||
},
|
||||
"custom": {
|
||||
"axisCenteredZero": false,
|
||||
"axisColorMode": "text",
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"fillOpacity": 80,
|
||||
"gradientMode": "scheme",
|
||||
"hideFrom": {
|
||||
"legend": false,
|
||||
"tooltip": false,
|
||||
"viz": false
|
||||
},
|
||||
"lineWidth": 1,
|
||||
"scaleDistribution": {
|
||||
"type": "linear"
|
||||
},
|
||||
"thresholdsStyle": {
|
||||
"mode": "off"
|
||||
}
|
||||
},
|
||||
"mappings": [],
|
||||
"max": 1,
|
||||
"min": 0,
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "orange"
|
||||
},
|
||||
{
|
||||
"color": "green",
|
||||
"value": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
"unit": "percentunit"
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 19,
|
||||
"w": 8,
|
||||
"x": 8,
|
||||
"y": 1
|
||||
},
|
||||
"id": 2,
|
||||
"options": {
|
||||
"barRadius": 0,
|
||||
"barWidth": 0.97,
|
||||
"fullHighlight": false,
|
||||
"groupWidth": 0.7,
|
||||
"legend": {
|
||||
"displayMode": "list",
|
||||
"showLegend": false
|
||||
},
|
||||
"orientation": "horizontal",
|
||||
"showValue": "auto",
|
||||
"stacking": "none",
|
||||
"tooltip": {
|
||||
"mode": "single",
|
||||
"sort": "none"
|
||||
},
|
||||
"xTickLabelRotation": 0,
|
||||
"xTickLabelSpacing": 0
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"uid": "$datasource"
|
||||
},
|
||||
"expr": "sum by (deployment) (up{job=\"kube-state-metrics\"})",
|
||||
"format": "table",
|
||||
"instant": true,
|
||||
"legendFormat": "__auto",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Deployment rollout progress",
|
||||
"transformations": [
|
||||
{
|
||||
"id": "sortBy",
|
||||
"options": {
|
||||
"fields": {},
|
||||
"sort": [
|
||||
{
|
||||
"field": "deployment"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"type": "barchart"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"uid": "$datasource"
|
||||
},
|
||||
"description": "### StatefulSet rollout progress\nShows the number of pods for each `StatefulSet` that match the desired configuration, as a proportion of the desired number of pods.\n\nThe rollout will fail if insufficient pods match the desired configuration for any `StatefulSet`.\n\nPods in green match the desired configuration, while pods that do not match the desired configuration are shown in orange.\n\n",
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "thresholds"
|
||||
},
|
||||
"custom": {
|
||||
"axisCenteredZero": false,
|
||||
"axisColorMode": "text",
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"fillOpacity": 80,
|
||||
"gradientMode": "scheme",
|
||||
"hideFrom": {
|
||||
"legend": false,
|
||||
"tooltip": false,
|
||||
"viz": false
|
||||
},
|
||||
"lineWidth": 1,
|
||||
"scaleDistribution": {
|
||||
"type": "linear"
|
||||
},
|
||||
"thresholdsStyle": {
|
||||
"mode": "off"
|
||||
}
|
||||
},
|
||||
"mappings": [],
|
||||
"max": 1,
|
||||
"min": 0,
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "orange"
|
||||
},
|
||||
{
|
||||
"color": "green",
|
||||
"value": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
"unit": "percentunit"
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 19,
|
||||
"w": 8,
|
||||
"x": 16,
|
||||
"y": 1
|
||||
},
|
||||
"id": 3,
|
||||
"options": {
|
||||
"barRadius": 0,
|
||||
"barWidth": 0.97,
|
||||
"fullHighlight": false,
|
||||
"groupWidth": 0.7,
|
||||
"legend": {
|
||||
"displayMode": "list",
|
||||
"showLegend": false
|
||||
},
|
||||
"orientation": "horizontal",
|
||||
"showValue": "auto",
|
||||
"stacking": "none",
|
||||
"tooltip": {
|
||||
"mode": "single",
|
||||
"sort": "none"
|
||||
},
|
||||
"xTickLabelRotation": 0,
|
||||
"xTickLabelSpacing": 0
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"uid": "$datasource"
|
||||
},
|
||||
"expr": "sum by (statefulset) (up{job=\"kube-state-metrics\"})",
|
||||
"format": "table",
|
||||
"instant": true,
|
||||
"legendFormat": "__auto",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "StatefulSet rollout progress",
|
||||
"transformations": [
|
||||
{
|
||||
"id": "sortBy",
|
||||
"options": {
|
||||
"fields": {},
|
||||
"sort": [
|
||||
{
|
||||
"field": "statefulset"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"type": "barchart"
|
||||
},
|
||||
{
|
||||
"collapsed": false,
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 19,
|
||||
"w": 24,
|
||||
"x": 0,
|
||||
"y": 20
|
||||
},
|
||||
"id": 8,
|
||||
"panels": [],
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Rollout health",
|
||||
"type": "row"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"uid": "$datasource"
|
||||
},
|
||||
"description": "### Aggregator lag\nShows the consumption lag of each aggregator pod.\n\nThis panel may show no data if aggregators are not deployed to this cell.\n\nThe rollout will fail if any pod's consumption lag is both:\n* greater than 30s (red area on graph), and\n* trending upwards compared to 1 minute earlier\n\n",
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"custom": {
|
||||
"drawStyle": "line",
|
||||
"fillOpacity": 0,
|
||||
"lineWidth": 1,
|
||||
"pointSize": 5,
|
||||
"showPoints": "never",
|
||||
"spanNulls": false,
|
||||
"stacking": {
|
||||
"group": "A",
|
||||
"mode": "none"
|
||||
},
|
||||
"thresholdsStyle": {
|
||||
"mode": "area"
|
||||
}
|
||||
},
|
||||
"min": 0,
|
||||
"noValue": "No data (are aggregators deployed in this cell?)",
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green"
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 30
|
||||
}
|
||||
]
|
||||
},
|
||||
"unit": "s"
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 19,
|
||||
"w": 8,
|
||||
"x": 0,
|
||||
"y": 21
|
||||
},
|
||||
"id": 4,
|
||||
"options": {
|
||||
"legend": {
|
||||
"showLegend": true
|
||||
},
|
||||
"tooltip": {
|
||||
"mode": "multi",
|
||||
"sort": "none"
|
||||
}
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"uid": "$datasource"
|
||||
},
|
||||
"expr": "max by (pod) (up{job=\"mimir-aggregator\"})",
|
||||
"format": "time_series",
|
||||
"legendFormat": "__auto",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Aggregator lag",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"uid": "$datasource"
|
||||
},
|
||||
"description": "### Unhealthy Deployment replicas\nShows the number of unavailable pods for each `Deployment`.\n\nThe rollout will fail if any `Deployment` has an unavailable pod.\n\nBoth this panel and the rollout check ignore any `Deployment`s that require spot nodes, as these are expected to be unavailable from time to time.\n\n`Deployment`s shown in green do not have any unavailable pods, while `Deployment`s shown in orange have one or more unavailable pods.\n\n",
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "thresholds"
|
||||
},
|
||||
"custom": {
|
||||
"axisCenteredZero": false,
|
||||
"axisColorMode": "text",
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"axisSoftMax": 10,
|
||||
"fillOpacity": 80,
|
||||
"gradientMode": "scheme",
|
||||
"hideFrom": {
|
||||
"legend": false,
|
||||
"tooltip": false,
|
||||
"viz": false
|
||||
},
|
||||
"lineWidth": 1,
|
||||
"scaleDistribution": {
|
||||
"type": "linear"
|
||||
},
|
||||
"thresholdsStyle": {
|
||||
"mode": "off"
|
||||
}
|
||||
},
|
||||
"mappings": [],
|
||||
"min": 0,
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green"
|
||||
},
|
||||
{
|
||||
"color": "orange",
|
||||
"value": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
"unit": ""
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 19,
|
||||
"w": 8,
|
||||
"x": 8,
|
||||
"y": 21
|
||||
},
|
||||
"id": 5,
|
||||
"options": {
|
||||
"barRadius": 0,
|
||||
"barWidth": 0.97,
|
||||
"fullHighlight": false,
|
||||
"groupWidth": 0.7,
|
||||
"legend": {
|
||||
"displayMode": "list",
|
||||
"showLegend": false
|
||||
},
|
||||
"orientation": "horizontal",
|
||||
"showValue": "auto",
|
||||
"stacking": "none",
|
||||
"tooltip": {
|
||||
"mode": "single",
|
||||
"sort": "none"
|
||||
},
|
||||
"xTickLabelRotation": 0,
|
||||
"xTickLabelSpacing": 0
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"uid": "$datasource"
|
||||
},
|
||||
"expr": "sum by (deployment) (up{job=\"kube-state-metrics\"})",
|
||||
"format": "table",
|
||||
"instant": true,
|
||||
"legendFormat": "__auto",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Unhealthy Deployment replicas",
|
||||
"transformations": [
|
||||
{
|
||||
"id": "sortBy",
|
||||
"options": {
|
||||
"fields": {},
|
||||
"sort": [
|
||||
{
|
||||
"field": "deployment"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"type": "barchart"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"uid": "$datasource"
|
||||
},
|
||||
"description": "### Unhealthy StatefulSet replicas\nShows the number of pods for each `StatefulSet` that are not ready.\n\nThe rollout will fail if any `StatefulSet` has fewer ready pods than requested.\n\nBoth this panel and the rollout check ignore any `StatefulSets`s that require spot nodes, as these are expected to be unavailable from time to time.\n\n`StatefulSets`s shown in green do not have any pods that are not ready, while `StatefulSet`s shown in orange have one or more pods that are not ready.\n\n",
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "thresholds"
|
||||
},
|
||||
"custom": {
|
||||
"axisCenteredZero": false,
|
||||
"axisColorMode": "text",
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"axisSoftMax": 10,
|
||||
"fillOpacity": 80,
|
||||
"gradientMode": "scheme",
|
||||
"hideFrom": {
|
||||
"legend": false,
|
||||
"tooltip": false,
|
||||
"viz": false
|
||||
},
|
||||
"lineWidth": 1,
|
||||
"scaleDistribution": {
|
||||
"type": "linear"
|
||||
},
|
||||
"thresholdsStyle": {
|
||||
"mode": "off"
|
||||
}
|
||||
},
|
||||
"mappings": [],
|
||||
"min": 0,
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green"
|
||||
},
|
||||
{
|
||||
"color": "orange",
|
||||
"value": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
"unit": ""
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 19,
|
||||
"w": 8,
|
||||
"x": 16,
|
||||
"y": 21
|
||||
},
|
||||
"id": 6,
|
||||
"options": {
|
||||
"barRadius": 0,
|
||||
"barWidth": 0.97,
|
||||
"fullHighlight": false,
|
||||
"groupWidth": 0.7,
|
||||
"legend": {
|
||||
"displayMode": "list",
|
||||
"showLegend": false
|
||||
},
|
||||
"orientation": "horizontal",
|
||||
"showValue": "auto",
|
||||
"stacking": "none",
|
||||
"tooltip": {
|
||||
"mode": "single",
|
||||
"sort": "none"
|
||||
},
|
||||
"xTickLabelRotation": 0,
|
||||
"xTickLabelSpacing": 0
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"uid": "$datasource"
|
||||
},
|
||||
"expr": "sum by (statefulset) (up{job=\"kube-state-metrics\"})",
|
||||
"format": "table",
|
||||
"instant": true,
|
||||
"legendFormat": "__auto",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Unhealthy StatefulSet replicas",
|
||||
"transformations": [
|
||||
{
|
||||
"id": "sortBy",
|
||||
"options": {
|
||||
"fields": {},
|
||||
"sort": [
|
||||
{
|
||||
"field": "statefulset"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"type": "barchart"
|
||||
}
|
||||
],
|
||||
"refresh": "5m",
|
||||
"schemaVersion": 42,
|
||||
"tags": [
|
||||
"mimir",
|
||||
"betterops-mimir",
|
||||
"show-in-mimir-links-dropdown",
|
||||
"as-code"
|
||||
],
|
||||
"templating": {
|
||||
"list": [
|
||||
{
|
||||
"current": {
|
||||
"value": "grafanacloud-prom"
|
||||
},
|
||||
"hide": 0,
|
||||
"label": "Data source",
|
||||
"name": "datasource",
|
||||
"options": [],
|
||||
"query": "prometheus",
|
||||
"refresh": 1,
|
||||
"regex": "",
|
||||
"type": "datasource"
|
||||
},
|
||||
{
|
||||
"allValue": ".*",
|
||||
"current": {
|
||||
"text": "prod",
|
||||
"value": "prod"
|
||||
},
|
||||
"datasource": "$datasource",
|
||||
"hide": 0,
|
||||
"includeAll": true,
|
||||
"label": "cluster",
|
||||
"multi": false,
|
||||
"name": "cluster",
|
||||
"options": [],
|
||||
"query": "label_values(up, job)",
|
||||
"refresh": 1,
|
||||
"regex": "",
|
||||
"sort": 1,
|
||||
"tagValuesQuery": "",
|
||||
"tagsQuery": "",
|
||||
"type": "query",
|
||||
"useTags": false
|
||||
},
|
||||
{
|
||||
"current": {
|
||||
"text": "prod",
|
||||
"value": "prod"
|
||||
},
|
||||
"datasource": "$datasource",
|
||||
"hide": 0,
|
||||
"includeAll": false,
|
||||
"label": "namespace",
|
||||
"multi": false,
|
||||
"name": "namespace",
|
||||
"options": [],
|
||||
"query": "label_values(up{job=~\"$cluster\"}, instance)",
|
||||
"refresh": 1,
|
||||
"regex": "",
|
||||
"sort": 1,
|
||||
"tagValuesQuery": "",
|
||||
"tagsQuery": "",
|
||||
"type": "query",
|
||||
"useTags": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"time": {
|
||||
"from": "now-1h",
|
||||
"to": "now"
|
||||
},
|
||||
"timepicker": {
|
||||
"refresh_intervals": [
|
||||
"5s",
|
||||
"10s",
|
||||
"30s",
|
||||
"1m",
|
||||
"5m",
|
||||
"15m",
|
||||
"30m",
|
||||
"1h",
|
||||
"2h",
|
||||
"1d"
|
||||
]
|
||||
},
|
||||
"timezone": "utc",
|
||||
"title": "Mimir / Rollout debugging",
|
||||
"weekStart": ""
|
||||
},
|
||||
"status": {
|
||||
"conversion": {
|
||||
"failed": false,
|
||||
"storedVersion": "v1beta1"
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,135 @@
|
||||
{
|
||||
"kind": "Dashboard",
|
||||
"apiVersion": "dashboard.grafana.app/v0alpha1",
|
||||
"metadata": {
|
||||
"name": "v15.no-op-migration.v42"
|
||||
},
|
||||
"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"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "grafana",
|
||||
"uid": "grafana"
|
||||
},
|
||||
"enable": true,
|
||||
"name": "Annotations \u0026 Alerts"
|
||||
}
|
||||
]
|
||||
},
|
||||
"editable": true,
|
||||
"fiscalYearStartMonth": 0,
|
||||
"graphTooltip": 0,
|
||||
"links": [],
|
||||
"panels": [
|
||||
{
|
||||
"autoMigrateFrom": "graph",
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"id": 1,
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "CPU Usage",
|
||||
"type": "timeseries",
|
||||
"yAxes": [
|
||||
{
|
||||
"show": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"autoMigrateFrom": "singlestat",
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"id": 2,
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Memory Usage",
|
||||
"type": "stat",
|
||||
"valueMaps": [
|
||||
{
|
||||
"op": "=",
|
||||
"text": "N/A",
|
||||
"value": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"refresh": "",
|
||||
"schemaVersion": 42,
|
||||
"tags": [],
|
||||
"templating": {
|
||||
"list": [
|
||||
{
|
||||
"datasource": "prometheus",
|
||||
"name": "server",
|
||||
"options": [],
|
||||
"query": "label_values(server)",
|
||||
"refresh": 1,
|
||||
"type": "query"
|
||||
}
|
||||
]
|
||||
},
|
||||
"time": {
|
||||
"from": "now-6h",
|
||||
"to": "now"
|
||||
},
|
||||
"timepicker": {
|
||||
"refresh_intervals": [
|
||||
"5s",
|
||||
"10s",
|
||||
"30s",
|
||||
"1m",
|
||||
"5m",
|
||||
"15m",
|
||||
"30m",
|
||||
"1h",
|
||||
"2h",
|
||||
"1d"
|
||||
]
|
||||
},
|
||||
"timezone": "",
|
||||
"title": "V15 No-Op Migration Test Dashboard",
|
||||
"weekStart": ""
|
||||
},
|
||||
"status": {
|
||||
"conversion": {
|
||||
"failed": false,
|
||||
"storedVersion": "v1beta1"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,227 @@
|
||||
{
|
||||
"kind": "Dashboard",
|
||||
"apiVersion": "dashboard.grafana.app/v2alpha1",
|
||||
"metadata": {
|
||||
"name": "v15.no-op-migration.v42"
|
||||
},
|
||||
"spec": {
|
||||
"annotations": [
|
||||
{
|
||||
"kind": "AnnotationQuery",
|
||||
"spec": {
|
||||
"datasource": {
|
||||
"type": "grafana",
|
||||
"uid": "-- Grafana --"
|
||||
},
|
||||
"query": {
|
||||
"kind": "DataQuery",
|
||||
"spec": {}
|
||||
},
|
||||
"enable": true,
|
||||
"hide": true,
|
||||
"iconColor": "rgba(0, 211, 255, 1)",
|
||||
"name": "Annotations \u0026 Alerts",
|
||||
"builtIn": true,
|
||||
"legacyOptions": {
|
||||
"type": "dashboard"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "AnnotationQuery",
|
||||
"spec": {
|
||||
"datasource": {
|
||||
"type": "grafana",
|
||||
"uid": "grafana"
|
||||
},
|
||||
"query": {
|
||||
"kind": "DataQuery",
|
||||
"spec": {}
|
||||
},
|
||||
"enable": true,
|
||||
"hide": false,
|
||||
"iconColor": "",
|
||||
"name": "Annotations \u0026 Alerts"
|
||||
}
|
||||
}
|
||||
],
|
||||
"cursorSync": "Off",
|
||||
"editable": true,
|
||||
"elements": {
|
||||
"panel-1": {
|
||||
"kind": "Panel",
|
||||
"spec": {
|
||||
"id": 1,
|
||||
"title": "CPU Usage",
|
||||
"description": "",
|
||||
"links": [],
|
||||
"data": {
|
||||
"kind": "QueryGroup",
|
||||
"spec": {
|
||||
"queries": [
|
||||
{
|
||||
"kind": "PanelQuery",
|
||||
"spec": {
|
||||
"query": {
|
||||
"kind": "DataQuery",
|
||||
"spec": {}
|
||||
},
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"refId": "A",
|
||||
"hidden": false
|
||||
}
|
||||
}
|
||||
],
|
||||
"transformations": [],
|
||||
"queryOptions": {}
|
||||
}
|
||||
},
|
||||
"vizConfig": {
|
||||
"kind": "timeseries",
|
||||
"spec": {
|
||||
"pluginVersion": "",
|
||||
"options": {},
|
||||
"fieldConfig": {
|
||||
"defaults": {},
|
||||
"overrides": []
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"panel-2": {
|
||||
"kind": "Panel",
|
||||
"spec": {
|
||||
"id": 2,
|
||||
"title": "Memory Usage",
|
||||
"description": "",
|
||||
"links": [],
|
||||
"data": {
|
||||
"kind": "QueryGroup",
|
||||
"spec": {
|
||||
"queries": [
|
||||
{
|
||||
"kind": "PanelQuery",
|
||||
"spec": {
|
||||
"query": {
|
||||
"kind": "DataQuery",
|
||||
"spec": {}
|
||||
},
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"refId": "A",
|
||||
"hidden": false
|
||||
}
|
||||
}
|
||||
],
|
||||
"transformations": [],
|
||||
"queryOptions": {}
|
||||
}
|
||||
},
|
||||
"vizConfig": {
|
||||
"kind": "stat",
|
||||
"spec": {
|
||||
"pluginVersion": "",
|
||||
"options": {},
|
||||
"fieldConfig": {
|
||||
"defaults": {},
|
||||
"overrides": []
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"layout": {
|
||||
"kind": "GridLayout",
|
||||
"spec": {
|
||||
"items": [
|
||||
{
|
||||
"kind": "GridLayoutItem",
|
||||
"spec": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"width": 6,
|
||||
"height": 3,
|
||||
"element": {
|
||||
"kind": "ElementReference",
|
||||
"name": "panel-1"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "GridLayoutItem",
|
||||
"spec": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"width": 6,
|
||||
"height": 3,
|
||||
"element": {
|
||||
"kind": "ElementReference",
|
||||
"name": "panel-2"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"links": [],
|
||||
"liveNow": false,
|
||||
"preload": false,
|
||||
"tags": [],
|
||||
"timeSettings": {
|
||||
"timezone": "",
|
||||
"from": "now-6h",
|
||||
"to": "now",
|
||||
"autoRefresh": "",
|
||||
"autoRefreshIntervals": [
|
||||
"5s",
|
||||
"10s",
|
||||
"30s",
|
||||
"1m",
|
||||
"5m",
|
||||
"15m",
|
||||
"30m",
|
||||
"1h",
|
||||
"2h",
|
||||
"1d"
|
||||
],
|
||||
"hideTimepicker": false,
|
||||
"fiscalYearStartMonth": 0
|
||||
},
|
||||
"title": "V15 No-Op Migration Test Dashboard",
|
||||
"variables": [
|
||||
{
|
||||
"kind": "QueryVariable",
|
||||
"spec": {
|
||||
"name": "server",
|
||||
"current": {
|
||||
"text": "",
|
||||
"value": ""
|
||||
},
|
||||
"hide": "dontHide",
|
||||
"refresh": "onDashboardLoad",
|
||||
"skipUrlSync": false,
|
||||
"query": {
|
||||
"kind": "DataQuery",
|
||||
"spec": {
|
||||
"__legacyStringValue": "label_values(server)"
|
||||
}
|
||||
},
|
||||
"regex": "",
|
||||
"sort": "disabled",
|
||||
"options": [],
|
||||
"multi": false,
|
||||
"includeAll": false,
|
||||
"allowCustomValue": true
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"status": {}
|
||||
}
|
||||
@@ -0,0 +1,235 @@
|
||||
{
|
||||
"kind": "Dashboard",
|
||||
"apiVersion": "dashboard.grafana.app/v2beta1",
|
||||
"metadata": {
|
||||
"name": "v15.no-op-migration.v42"
|
||||
},
|
||||
"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"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "AnnotationQuery",
|
||||
"spec": {
|
||||
"query": {
|
||||
"kind": "DataQuery",
|
||||
"group": "grafana",
|
||||
"version": "v0",
|
||||
"datasource": {
|
||||
"name": "grafana"
|
||||
},
|
||||
"spec": {}
|
||||
},
|
||||
"enable": true,
|
||||
"hide": false,
|
||||
"iconColor": "",
|
||||
"name": "Annotations \u0026 Alerts"
|
||||
}
|
||||
}
|
||||
],
|
||||
"cursorSync": "Off",
|
||||
"editable": true,
|
||||
"elements": {
|
||||
"panel-1": {
|
||||
"kind": "Panel",
|
||||
"spec": {
|
||||
"id": 1,
|
||||
"title": "CPU Usage",
|
||||
"description": "",
|
||||
"links": [],
|
||||
"data": {
|
||||
"kind": "QueryGroup",
|
||||
"spec": {
|
||||
"queries": [
|
||||
{
|
||||
"kind": "PanelQuery",
|
||||
"spec": {
|
||||
"query": {
|
||||
"kind": "DataQuery",
|
||||
"group": "prometheus",
|
||||
"version": "v0",
|
||||
"datasource": {
|
||||
"name": "default-ds-uid"
|
||||
},
|
||||
"spec": {}
|
||||
},
|
||||
"refId": "A",
|
||||
"hidden": false
|
||||
}
|
||||
}
|
||||
],
|
||||
"transformations": [],
|
||||
"queryOptions": {}
|
||||
}
|
||||
},
|
||||
"vizConfig": {
|
||||
"kind": "VizConfig",
|
||||
"group": "timeseries",
|
||||
"version": "",
|
||||
"spec": {
|
||||
"options": {},
|
||||
"fieldConfig": {
|
||||
"defaults": {},
|
||||
"overrides": []
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"panel-2": {
|
||||
"kind": "Panel",
|
||||
"spec": {
|
||||
"id": 2,
|
||||
"title": "Memory Usage",
|
||||
"description": "",
|
||||
"links": [],
|
||||
"data": {
|
||||
"kind": "QueryGroup",
|
||||
"spec": {
|
||||
"queries": [
|
||||
{
|
||||
"kind": "PanelQuery",
|
||||
"spec": {
|
||||
"query": {
|
||||
"kind": "DataQuery",
|
||||
"group": "prometheus",
|
||||
"version": "v0",
|
||||
"datasource": {
|
||||
"name": "default-ds-uid"
|
||||
},
|
||||
"spec": {}
|
||||
},
|
||||
"refId": "A",
|
||||
"hidden": false
|
||||
}
|
||||
}
|
||||
],
|
||||
"transformations": [],
|
||||
"queryOptions": {}
|
||||
}
|
||||
},
|
||||
"vizConfig": {
|
||||
"kind": "VizConfig",
|
||||
"group": "stat",
|
||||
"version": "",
|
||||
"spec": {
|
||||
"options": {},
|
||||
"fieldConfig": {
|
||||
"defaults": {},
|
||||
"overrides": []
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"layout": {
|
||||
"kind": "GridLayout",
|
||||
"spec": {
|
||||
"items": [
|
||||
{
|
||||
"kind": "GridLayoutItem",
|
||||
"spec": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"width": 6,
|
||||
"height": 3,
|
||||
"element": {
|
||||
"kind": "ElementReference",
|
||||
"name": "panel-1"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "GridLayoutItem",
|
||||
"spec": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"width": 6,
|
||||
"height": 3,
|
||||
"element": {
|
||||
"kind": "ElementReference",
|
||||
"name": "panel-2"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"links": [],
|
||||
"liveNow": false,
|
||||
"preload": false,
|
||||
"tags": [],
|
||||
"timeSettings": {
|
||||
"timezone": "",
|
||||
"from": "now-6h",
|
||||
"to": "now",
|
||||
"autoRefresh": "",
|
||||
"autoRefreshIntervals": [
|
||||
"5s",
|
||||
"10s",
|
||||
"30s",
|
||||
"1m",
|
||||
"5m",
|
||||
"15m",
|
||||
"30m",
|
||||
"1h",
|
||||
"2h",
|
||||
"1d"
|
||||
],
|
||||
"hideTimepicker": false,
|
||||
"fiscalYearStartMonth": 0
|
||||
},
|
||||
"title": "V15 No-Op Migration Test Dashboard",
|
||||
"variables": [
|
||||
{
|
||||
"kind": "QueryVariable",
|
||||
"spec": {
|
||||
"name": "server",
|
||||
"current": {
|
||||
"text": "",
|
||||
"value": ""
|
||||
},
|
||||
"hide": "dontHide",
|
||||
"refresh": "onDashboardLoad",
|
||||
"skipUrlSync": false,
|
||||
"query": {
|
||||
"kind": "DataQuery",
|
||||
"group": "",
|
||||
"version": "v0",
|
||||
"spec": {
|
||||
"__legacyStringValue": "label_values(server)"
|
||||
}
|
||||
},
|
||||
"regex": "",
|
||||
"sort": "disabled",
|
||||
"options": [],
|
||||
"multi": false,
|
||||
"includeAll": false,
|
||||
"allowCustomValue": true
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"status": {}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user