Compare commits

..

1 Commits

Author SHA1 Message Date
renovate-sh-app[bot] 18f7f95c3b fix(deps): update react-data-grid digest to 1a92ea1
Signed-off-by: renovate-sh-app[bot] <219655108+renovate-sh-app[bot]@users.noreply.github.com>
2025-10-16 12:06:45 +00:00
2415 changed files with 30286 additions and 110877 deletions
-5
View File
@@ -1,6 +1 @@
* text=auto eol=lf * text=auto eol=lf
*.gen.ts linguist-generated
*_gen.ts linguist-generated
*_gen.go linguist-generated
**/openapi_snapshots/*.json linguist-generated
apps/**/pkg/apis/*_manifest.go linguist-generated
+22 -21
View File
@@ -96,9 +96,6 @@
/apps/iam/ @grafana/access-squad /apps/iam/ @grafana/access-squad
/apps/sdk.mk @grafana/grafana-app-platform-squad /apps/sdk.mk @grafana/grafana-app-platform-squad
/apps/correlations @grafana/datapro /apps/correlations @grafana/datapro
/apps/example/ @grafana/grafana-app-platform-squad
/apps/logsdrilldown/ @grafana/observability-logs
/apps/annotation/ @grafana/grafana-backend-services-squad
/pkg/api/ @grafana/grafana-backend-group /pkg/api/ @grafana/grafana-backend-group
/pkg/apis/ @grafana/grafana-app-platform-squad /pkg/apis/ @grafana/grafana-app-platform-squad
/pkg/apis/query @grafana/grafana-datasources-core-services /pkg/apis/query @grafana/grafana-datasources-core-services
@@ -152,7 +149,7 @@
/pkg/promlib @grafana/oss-big-tent /pkg/promlib @grafana/oss-big-tent
/pkg/storage/ @grafana/grafana-search-and-storage /pkg/storage/ @grafana/grafana-search-and-storage
/pkg/storage/secret/ @grafana/grafana-operator-experience-squad /pkg/storage/secret/ @grafana/grafana-operator-experience-squad
/pkg/services/annotations/ @grafana/grafana-backend-services-squad /pkg/services/annotations/ @grafana/grafana-search-and-storage
/pkg/services/apikey/ @grafana/identity-squad /pkg/services/apikey/ @grafana/identity-squad
/pkg/services/cleanup/ @grafana/grafana-backend-group /pkg/services/cleanup/ @grafana/grafana-backend-group
/pkg/services/contexthandler/ @grafana/grafana-backend-group @grafana/grafana-app-platform-squad /pkg/services/contexthandler/ @grafana/grafana-backend-group @grafana/grafana-app-platform-squad
@@ -168,7 +165,7 @@
/pkg/services/kmsproviders/ @grafana/grafana-operator-experience-squad /pkg/services/kmsproviders/ @grafana/grafana-operator-experience-squad
/pkg/services/licensing/ @grafana/grafana-operator-experience-squad /pkg/services/licensing/ @grafana/grafana-operator-experience-squad
/pkg/services/dsquerierclient/ @grafana/grafana-datasources-core-services /pkg/services/dsquerierclient/ @grafana/grafana-datasources-core-services
/pkg/services/navtree/ @grafana/grafana-backend-group @grafana/grafana-search-navigate-organise /pkg/services/navtree/ @grafana/grafana-backend-group
/pkg/services/notifications/ @grafana/grafana-backend-group /pkg/services/notifications/ @grafana/grafana-backend-group
/pkg/services/org/ @grafana/grafana-backend-group /pkg/services/org/ @grafana/grafana-backend-group
/pkg/services/playlist/ @grafana/grafana-app-platform-squad /pkg/services/playlist/ @grafana/grafana-app-platform-squad
@@ -182,7 +179,7 @@
/pkg/services/search/ @grafana/grafana-search-and-storage /pkg/services/search/ @grafana/grafana-search-and-storage
/pkg/services/searchusers/ @grafana/grafana-search-and-storage /pkg/services/searchusers/ @grafana/grafana-search-and-storage
/pkg/services/secrets/ @grafana/grafana-operator-experience-squad /pkg/services/secrets/ @grafana/grafana-operator-experience-squad
/pkg/services/shorturls/ @grafana/sharing-squad /pkg/services/shorturls/ @grafana/grafana-backend-group
/pkg/services/sqlstore/ @grafana/grafana-search-and-storage /pkg/services/sqlstore/ @grafana/grafana-search-and-storage
/pkg/services/ssosettings/ @grafana/identity-squad /pkg/services/ssosettings/ @grafana/identity-squad
/pkg/services/star/ @grafana/grafana-search-and-storage /pkg/services/star/ @grafana/grafana-search-and-storage
@@ -200,7 +197,6 @@
/pkg/tests/apis/features @grafana/grafana-backend-services-squad /pkg/tests/apis/features @grafana/grafana-backend-services-squad
/pkg/tests/apis/folder @grafana/grafana-search-and-storage /pkg/tests/apis/folder @grafana/grafana-search-and-storage
/pkg/tests/apis/iam @grafana/identity-access-team /pkg/tests/apis/iam @grafana/identity-access-team
/pkg/tests/apis/shorturl @grafana/sharing-squad
/pkg/tests/api/correlations/ @grafana/datapro /pkg/tests/api/correlations/ @grafana/datapro
/pkg/tsdb/grafanads/ @grafana/grafana-backend-group /pkg/tsdb/grafanads/ @grafana/grafana-backend-group
/pkg/tsdb/opentsdb/ @grafana/partner-datasources /pkg/tsdb/opentsdb/ @grafana/partner-datasources
@@ -227,7 +223,6 @@
/devenv/datasources.yaml @grafana/grafana-backend-group /devenv/datasources.yaml @grafana/grafana-backend-group
/devenv/datasources_docker.yaml @grafana/grafana-backend-group /devenv/datasources_docker.yaml @grafana/grafana-backend-group
/devenv/dev-dashboards-without-uid/ @grafana/dashboards-squad /devenv/dev-dashboards-without-uid/ @grafana/dashboards-squad
/devenv/scopes/ @grafana/grafana-operator-experience-squad
/devenv/dev-dashboards/annotations @grafana/dataviz-squad /devenv/dev-dashboards/annotations @grafana/dataviz-squad
/devenv/dev-dashboards/migrations @grafana/dataviz-squad /devenv/dev-dashboards/migrations @grafana/dataviz-squad
@@ -244,7 +239,6 @@
/devenv/dev-dashboards/panel-library @grafana/dataviz-squad /devenv/dev-dashboards/panel-library @grafana/dataviz-squad
/devenv/dev-dashboards/panel-piechart @grafana/dataviz-squad /devenv/dev-dashboards/panel-piechart @grafana/dataviz-squad
/devenv/dev-dashboards/panel-stat @grafana/dataviz-squad /devenv/dev-dashboards/panel-stat @grafana/dataviz-squad
/devenv/dev-dashboards/panel-status-history @grafana/dataviz-squad
/devenv/dev-dashboards/panel-table @grafana/dataviz-squad /devenv/dev-dashboards/panel-table @grafana/dataviz-squad
/devenv/dev-dashboards/panel-timeline @grafana/dataviz-squad /devenv/dev-dashboards/panel-timeline @grafana/dataviz-squad
/devenv/dev-dashboards/panel-timeseries @grafana/dataviz-squad /devenv/dev-dashboards/panel-timeseries @grafana/dataviz-squad
@@ -254,6 +248,7 @@
/devenv/dev-dashboards/all-panels.json @grafana/dataviz-squad /devenv/dev-dashboards/all-panels.json @grafana/dataviz-squad
/devenv/dev-dashboards/dashboards.go @grafana/dataviz-squad /devenv/dev-dashboards/dashboards.go @grafana/dataviz-squad
/devenv/dev-dashboards/home.json @grafana/dataviz-squad /devenv/dev-dashboards/home.json @grafana/dataviz-squad
/devenv/dev-dashboards/datasource-elasticsearch/ @grafana/partner-datasources /devenv/dev-dashboards/datasource-elasticsearch/ @grafana/partner-datasources
/devenv/dev-dashboards/datasource-opentsdb/ @grafana/partner-datasources /devenv/dev-dashboards/datasource-opentsdb/ @grafana/partner-datasources
/devenv/dev-dashboards/datasource-influxdb/ @grafana/partner-datasources /devenv/dev-dashboards/datasource-influxdb/ @grafana/partner-datasources
@@ -417,8 +412,8 @@
/crowdin.yml @grafana/grafana-frontend-platform /crowdin.yml @grafana/grafana-frontend-platform
/public/locales/ @grafanabot /public/locales/ @grafanabot
i18next.config.ts @grafana/grafana-frontend-platform /public/locales/i18next-parser.config.cjs @grafana/grafana-frontend-platform
/public/locales/enterprise/i18next.config.ts @grafana/grafana-frontend-platform /public/locales/i18next-parser-enterprise.config.cjs @grafana/grafana-frontend-platform
/public/app/core/internationalization/ @grafana/grafana-frontend-platform /public/app/core/internationalization/ @grafana/grafana-frontend-platform
/e2e/ @grafana/grafana-frontend-platform /e2e/ @grafana/grafana-frontend-platform
/e2e-playwright/cloud-plugins-suite/ @grafana/partner-datasources /e2e-playwright/cloud-plugins-suite/ @grafana/partner-datasources
@@ -475,12 +470,22 @@ i18next.config.ts @grafana/grafana-frontend-platform
/e2e-playwright/fixtures/long-trace-response.json @grafana/observability-traces-and-profiling /e2e-playwright/fixtures/long-trace-response.json @grafana/observability-traces-and-profiling
/e2e-playwright/fixtures/tempo-response.json @grafana/oss-big-tent /e2e-playwright/fixtures/tempo-response.json @grafana/oss-big-tent
/e2e-playwright/fixtures/prometheus-response.json @grafana/datapro /e2e-playwright/fixtures/prometheus-response.json @grafana/datapro
/e2e-playwright/panels-suite/ @grafana/dataviz-squad /e2e-playwright/panels-suite/canvas-scene.spec.ts @grafana/dataviz-squad
/e2e-playwright/panels-suite/dashlist.spec.ts @grafana/grafana-search-navigate-organise /e2e-playwright/panels-suite/dashlist.spec.ts @grafana/grafana-search-navigate-organise
/e2e-playwright/panels-suite/datagrid-data-change.spec.ts @grafana/dataviz-squad
/e2e-playwright/panels-suite/datagrid-editing-features.spec.ts @grafana/dataviz-squad
/e2e-playwright/panels-suite/frontend-sandbox-panel.spec.ts @grafana/plugins-platform-frontend /e2e-playwright/panels-suite/frontend-sandbox-panel.spec.ts @grafana/plugins-platform-frontend
/e2e-playwright/panels-suite/geomap-layer-types.spec.ts @grafana/dataviz-squad
/e2e-playwright/panels-suite/geomap-map-controls.spec.ts @grafana/dataviz-squad
/e2e-playwright/panels-suite/geomap-spatial-operations-transform.spec.ts @grafana/dataviz-squad
/e2e-playwright/panels-suite/panelEdit_base.spec.ts @grafana/dashboards-squad /e2e-playwright/panels-suite/panelEdit_base.spec.ts @grafana/dashboards-squad
/e2e-playwright/panels-suite/panelEdit_queries.spec.ts @grafana/dashboards-squad /e2e-playwright/panels-suite/panelEdit_queries.spec.ts @grafana/dashboards-squad
/e2e-playwright/panels-suite/panelEdit_transforms.spec.ts @grafana/datapro /e2e-playwright/panels-suite/panelEdit_transforms.spec.ts @grafana/datapro
/e2e-playwright/panels-suite/table-footer.spec.ts @grafana/dataviz-squad
/e2e-playwright/panels-suite/table-kitchenSink.spec.ts @grafana/dataviz-squad
/e2e-playwright/panels-suite/table-markdown.spec.ts @grafana/dataviz-squad
/e2e-playwright/panels-suite/table-sparkline.spec.ts @grafana/dataviz-squad
/e2e-playwright/panels-suite/table-utils.ts @grafana/dataviz-squad
/e2e-playwright/plugin-e2e/ @grafana/oss-big-tent @grafana/partner-datasources /e2e-playwright/plugin-e2e/ @grafana/oss-big-tent @grafana/partner-datasources
/e2e-playwright/plugin-e2e/plugin-e2e-api-tests/ @grafana/plugins-platform-frontend /e2e-playwright/plugin-e2e/plugin-e2e-api-tests/ @grafana/plugins-platform-frontend
/e2e-playwright/smoke-tests-suite/ @grafana/grafana-frontend-platform /e2e-playwright/smoke-tests-suite/ @grafana/grafana-frontend-platform
@@ -497,7 +502,6 @@ i18next.config.ts @grafana/grafana-frontend-platform
/e2e-playwright/various-suite/frontend-sandbox-app.spec.ts @grafana/plugins-platform-frontend /e2e-playwright/various-suite/frontend-sandbox-app.spec.ts @grafana/plugins-platform-frontend
/e2e-playwright/various-suite/frontend-sandbox-datasource.spec.ts @grafana/plugins-platform-frontend /e2e-playwright/various-suite/frontend-sandbox-datasource.spec.ts @grafana/plugins-platform-frontend
/e2e-playwright/various-suite/gauge.spec.ts @grafana/dataviz-squad /e2e-playwright/various-suite/gauge.spec.ts @grafana/dataviz-squad
/e2e-playwright/various-suite/grafana-datasource-random-walk.spec.ts @grafana/grafana-frontend-platform
/e2e-playwright/various-suite/graph-auto-migrate.spec.ts @grafana/dataviz-squad /e2e-playwright/various-suite/graph-auto-migrate.spec.ts @grafana/dataviz-squad
/e2e-playwright/various-suite/inspect-drawer.spec.ts @grafana/dashboards-squad /e2e-playwright/various-suite/inspect-drawer.spec.ts @grafana/dashboards-squad
/e2e-playwright/various-suite/keybinds.spec.ts @grafana/grafana-frontend-platform /e2e-playwright/various-suite/keybinds.spec.ts @grafana/grafana-frontend-platform
@@ -549,7 +553,6 @@ i18next.config.ts @grafana/grafana-frontend-platform
/packages/grafana-data/src/geo/ @grafana/dataviz-squad /packages/grafana-data/src/geo/ @grafana/dataviz-squad
/packages/grafana-data/src/monaco/ @grafana/partner-datasources /packages/grafana-data/src/monaco/ @grafana/partner-datasources
/packages/grafana-data/src/panel/ @grafana/dashboards-squad /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/query/ @grafana/grafana-datasources-core-services
/packages/grafana-data/src/rbac/ @grafana/access-squad /packages/grafana-data/src/rbac/ @grafana/access-squad
/packages/grafana-data/src/table/ @grafana/dataviz-squad /packages/grafana-data/src/table/ @grafana/dataviz-squad
@@ -557,7 +560,6 @@ i18next.config.ts @grafana/grafana-frontend-platform
/packages/grafana-data/src/themes/ @grafana/grafana-frontend-platform /packages/grafana-data/src/themes/ @grafana/grafana-frontend-platform
/packages/grafana-data/src/transformations/ @grafana/datapro /packages/grafana-data/src/transformations/ @grafana/datapro
/packages/grafana-data/src/types/ @grafana/grafana-frontend-platform /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/utils/__snapshots__/ @grafanabot /packages/grafana-data/src/utils/__snapshots__/ @grafanabot
/packages/grafana-data/src/utils/anyToNumber.ts @grafana/grafana-frontend-platform /packages/grafana-data/src/utils/anyToNumber.ts @grafana/grafana-frontend-platform
/packages/grafana-data/src/utils/arrayUtils* @grafana/grafana-frontend-platform /packages/grafana-data/src/utils/arrayUtils* @grafana/grafana-frontend-platform
@@ -715,7 +717,6 @@ i18next.config.ts @grafana/grafana-frontend-platform
/packages/grafana-ui/src/components/BarGauge/ @grafana/dataviz-squad /packages/grafana-ui/src/components/BarGauge/ @grafana/dataviz-squad
/packages/grafana-ui/src/components/DataLinks/ @grafana/dataviz-squad /packages/grafana-ui/src/components/DataLinks/ @grafana/dataviz-squad
/packages/grafana-ui/src/components/Gauge/ @grafana/dataviz-squad /packages/grafana-ui/src/components/Gauge/ @grafana/dataviz-squad
/packages/grafana-ui/src/components/RadialGauge/ @grafana/dataviz-squad
/packages/grafana-ui/src/components/PluginSignatureBadge/ @grafana/plugins-platform-frontend /packages/grafana-ui/src/components/PluginSignatureBadge/ @grafana/plugins-platform-frontend
/packages/grafana-ui/src/components/Sparkline/ @grafana/grafana-frontend-platform @grafana/app-o11y-visualizations /packages/grafana-ui/src/components/Sparkline/ @grafana/grafana-frontend-platform @grafana/app-o11y-visualizations
/packages/grafana-ui/src/components/Table/ @grafana/dataviz-squad /packages/grafana-ui/src/components/Table/ @grafana/dataviz-squad
@@ -738,9 +739,6 @@ i18next.config.ts @grafana/grafana-frontend-platform
# @grafana/test-utils # @grafana/test-utils
/packages/grafana-test-utils @grafana/grafana-frontend-platform /packages/grafana-test-utils @grafana/grafana-frontend-platform
# @grafana/api-clients
/packages/grafana-api-clients/ @grafana/grafana-frontend-platform @grafana/grafana-search-navigate-organise
# root files, mostly frontend # root files, mostly frontend
/.browserslistrc @grafana/frontend-ops /.browserslistrc @grafana/frontend-ops
/package.json @grafana/frontend-ops /package.json @grafana/frontend-ops
@@ -791,7 +789,7 @@ playwright.storybook.config.ts @grafana/grafana-frontend-platform
/public/app/core/components/ColorScale/ @grafana/dataviz-squad /public/app/core/components/ColorScale/ @grafana/dataviz-squad
/public/app/core/components/DynamicImports/ @grafana/grafana-search-navigate-organise /public/app/core/components/DynamicImports/ @grafana/grafana-search-navigate-organise
/public/app/core/components/EmptyListCTA/ @grafana/grafana-frontend-platform /public/app/core/components/EmptyListCTA/ @grafana/grafana-frontend-platform
/public/app/core/components/FolderFilter/ @grafana/grafana-search-navigate-organise /public/app/core/components/FolderFilter/ @grafana/sharing-squad
/public/app/core/components/Footer/ @grafana/grafana-search-navigate-organise /public/app/core/components/Footer/ @grafana/grafana-search-navigate-organise
/public/app/core/components/ForgottenPassword/ @grafana/grafana-search-navigate-organise /public/app/core/components/ForgottenPassword/ @grafana/grafana-search-navigate-organise
/public/app/core/components/Form/ @grafana/grafana-frontend-platform /public/app/core/components/Form/ @grafana/grafana-frontend-platform
@@ -959,6 +957,7 @@ playwright.storybook.config.ts @grafana/grafana-frontend-platform
/public/app/features/transformers/timeSeriesTable/ @grafana/dataviz-squad @grafana/app-o11y-visualizations /public/app/features/transformers/timeSeriesTable/ @grafana/dataviz-squad @grafana/app-o11y-visualizations
/public/app/features/users/ @grafana/access-squad /public/app/features/users/ @grafana/access-squad
/public/app/features/variables/ @grafana/dashboards-squad /public/app/features/variables/ @grafana/dashboards-squad
/public/app/features/preferences/ @grafana/grafana-frontend-platform
/public/app/features/bookmarks/ @grafana/grafana-search-navigate-organise /public/app/features/bookmarks/ @grafana/grafana-search-navigate-organise
/public/app/plugins/panel/* @grafana/dataviz-squad /public/app/plugins/panel/* @grafana/dataviz-squad
/public/app/plugins/panel/alertlist/ @grafana/alerting-frontend /public/app/plugins/panel/alertlist/ @grafana/alerting-frontend
@@ -1054,10 +1053,13 @@ playwright.storybook.config.ts @grafana/grafana-frontend-platform
/scripts/trigger_windows_build.sh @grafana/grafana-developer-enablement-squad /scripts/trigger_windows_build.sh @grafana/grafana-developer-enablement-squad
/scripts/cleanup-husky.sh @grafana/frontend-ops /scripts/cleanup-husky.sh @grafana/frontend-ops
/scripts/verify-repo-update/ @grafana/grafana-developer-enablement-squad /scripts/verify-repo-update/ @grafana/grafana-developer-enablement-squad
/scripts/generate-rtk-apis.ts @grafana/grafana-frontend-platform
/scripts/process-specs.ts @grafana/grafana-frontend-platform
/scripts/generate-alerting-rtk-apis.ts @grafana/alerting-frontend /scripts/generate-alerting-rtk-apis.ts @grafana/alerting-frontend
/scripts/levitate-parse-json-report.js @grafana/plugins-platform-frontend /scripts/levitate-parse-json-report.js @grafana/plugins-platform-frontend
/scripts/levitate-show-affected-plugins.js @grafana/plugins-platform-frontend /scripts/levitate-show-affected-plugins.js @grafana/plugins-platform-frontend
/scripts/codemods/explicit-barrel-imports.cjs @grafana/frontend-ops /scripts/codemods/explicit-barrel-imports.cjs @grafana/frontend-ops
/scripts/rtk-client-generator/ @grafana/grafana-search-navigate-organise
/scripts/codeowners-manifest/ @grafana/dataviz-squad /scripts/codeowners-manifest/ @grafana/dataviz-squad
/scripts/test-coverage-by-codeowner.js @grafana/dataviz-squad /scripts/test-coverage-by-codeowner.js @grafana/dataviz-squad
@@ -1168,7 +1170,6 @@ embed.go @grafana/grafana-as-code
/pkg/registry/ @grafana/grafana-as-code /pkg/registry/ @grafana/grafana-as-code
/pkg/registry/apis/ @grafana/grafana-app-platform-squad /pkg/registry/apis/ @grafana/grafana-app-platform-squad
/pkg/registry/apis/folders @grafana/grafana-search-and-storage /pkg/registry/apis/folders @grafana/grafana-search-and-storage
/pkg/registry/apis/datasource @grafana/grafana-datasources-core-services
/pkg/registry/apis/query @grafana/grafana-datasources-core-services /pkg/registry/apis/query @grafana/grafana-datasources-core-services
/pkg/registry/apis/secret @grafana/grafana-operator-experience-squad /pkg/registry/apis/secret @grafana/grafana-operator-experience-squad
/pkg/registry/apis/userstorage @grafana/grafana-app-platform-squad @grafana/plugins-platform-backend /pkg/registry/apis/userstorage @grafana/grafana-app-platform-squad @grafana/plugins-platform-backend
@@ -31,9 +31,6 @@ outputs:
dockerfile: dockerfile:
description: Whether the dockerfile or self have changed in any way description: Whether the dockerfile or self have changed in any way
value: ${{ steps.changed-files.outputs.dockerfile_any_changed || 'true' }} value: ${{ steps.changed-files.outputs.dockerfile_any_changed || 'true' }}
devenv:
description: Whether the devenv or self have changed in any way
value: ${{ steps.changed-files.outputs.devenv_any_changed || 'true' }}
runs: runs:
using: composite using: composite
steps: steps:
@@ -139,9 +136,6 @@ runs:
- '.vale.ini' - '.vale.ini'
- '.github/actions/change-detection/**' - '.github/actions/change-detection/**'
- '${{ inputs.self }}' - '${{ inputs.self }}'
devenv:
- 'devenv/**'
- '${{ inputs.self }}'
- name: Print all change groups - name: Print all change groups
shell: bash shell: bash
run: | run: |
@@ -163,5 +157,3 @@ runs:
echo " --> ${{ steps.changed-files.outputs.docs_all_changed_files }}" echo " --> ${{ steps.changed-files.outputs.docs_all_changed_files }}"
echo "Dockerfile: ${{ steps.changed-files.outputs.dockerfile_any_changed || 'true' }}" echo "Dockerfile: ${{ steps.changed-files.outputs.dockerfile_any_changed || 'true' }}"
echo " --> ${{ steps.changed-files.outputs.dockerfile_all_changed_files }}" echo " --> ${{ steps.changed-files.outputs.dockerfile_all_changed_files }}"
echo "devenv: ${{ steps.changed-files.outputs.devenv_any_changed || 'true' }}"
echo " --> ${{ steps.changed-files.outputs.devenv_all_changed_files }}"
+2 -2
View File
@@ -1,6 +1,6 @@
{ {
extends: ["config:recommended"], extends: ["config:recommended"],
enabledManagers: ["npm", "docker-compose"], enabledManagers: ["npm"],
ignorePresets: [ ignorePresets: [
"github>grafana/grafana-renovate-config//presets/labels", "github>grafana/grafana-renovate-config//presets/labels",
], ],
@@ -26,7 +26,7 @@
"@types/slate-react", // we don't want to continue using this on the long run, use Monaco editor instead of Slate "@types/slate-react", // we don't want to continue using this on the long run, use Monaco editor instead of Slate
"@types/slate", // we don't want to continue using this on the long run, use Monaco editor instead of Slate "@types/slate", // we don't want to continue using this on the long run, use Monaco editor instead of Slate
], ],
includePaths: ["package.json", "packages/**", "public/app/plugins/**", "devenv/frontend-service/docker-compose.yaml"], includePaths: ["package.json", "packages/**", "public/app/plugins/**"],
ignorePaths: ["emails/**", "**/mocks/**"], ignorePaths: ["emails/**", "**/mocks/**"],
labels: ["area/frontend", "dependencies", "no-changelog"], labels: ["area/frontend", "dependencies", "no-changelog"],
postUpdateOptions: ["yarnDedupeHighest"], postUpdateOptions: ["yarnDedupeHighest"],
+1 -1
View File
@@ -54,7 +54,7 @@ jobs:
- name: Upload to GitHub security events - name: Upload to GitHub security events
if: success() || failure() if: success() || failure()
# If there are security problems, GitHub will automatically comment on the PR for us. # If there are security problems, GitHub will automatically comment on the PR for us.
uses: github/codeql-action/upload-sarif@f443b600d91635bebf5b0d9ebc620189c0d6fba5 # v4.30.8 uses: github/codeql-action/upload-sarif@28deaeda66b76a05916b6923827895f2b14ab387 # v3.28.16
with: with:
sarif_file: results.sarif sarif_file: results.sarif
category: actionlint category: actionlint
+1 -1
View File
@@ -15,7 +15,7 @@ jobs:
fetch-depth: 2 fetch-depth: 2
persist-credentials: false persist-credentials: false
- name: Set go version - name: Set go version
uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5
with: with:
go-version-file: go.mod go-version-file: go.mod
- name: Build swagger - name: Build swagger
+1 -1
View File
@@ -29,7 +29,7 @@ jobs:
fi fi
- name: Setup Go - name: Setup Go
uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # 6.0.0 uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # 5.5.0
with: with:
"go-version-file": "go.mod" "go-version-file": "go.mod"
@@ -17,7 +17,7 @@ jobs:
persist-credentials: false persist-credentials: false
- name: Setup Node.js - name: Setup Node.js
uses: actions/setup-node@v6 uses: actions/setup-node@v4
with: with:
node-version-file: '.nvmrc' node-version-file: '.nvmrc'
cache: 'yarn' cache: 'yarn'
+6 -3
View File
@@ -46,9 +46,12 @@ jobs:
with: with:
persist-credentials: false persist-credentials: false
- name: Setup Go - name: Setup Go
uses: actions/setup-go@v6.0.0 uses: actions/setup-go@v5.5.0
with: with:
go-version-file: go.mod # Explicitly set Go version to 1.24.1 to ensure consistent OpenAPI spec generation
# The crypto/x509 package has additional fields in Go 1.24.1 that affect the generated specs
# This ensures the GHAs environment matches what we use in the Drone pipeline
go-version: 1.24.1
cache: true cache: true
- name: Verify code generation - name: Verify code generation
@@ -79,7 +82,7 @@ jobs:
make swagger-clean && make openapi3-gen make swagger-clean && make openapi3-gen
# Check if the generated specs differ from what's in the repository # Check if the generated specs differ from what's in the repository
for f in public/api-merged.json public/openapi3.json public/api-enterprise-spec.json; do git add $f; done for f in public/api-merged.json public/openapi3.json; do git add $f; done
if [ -z "$(git diff --name-only --cached)" ]; then if [ -z "$(git diff --name-only --cached)" ]; then
echo "OpenAPI specs are up to date!" echo "OpenAPI specs are up to date!"
else else
+2 -2
View File
@@ -59,7 +59,7 @@ jobs:
with: with:
persist-credentials: false persist-credentials: false
- name: Setup Go - name: Setup Go
uses: actions/setup-go@v6.0.0 uses: actions/setup-go@v5.5.0
with: with:
go-version-file: go.mod go-version-file: go.mod
- name: Run unit tests - name: Run unit tests
@@ -94,7 +94,7 @@ jobs:
with: with:
persist-credentials: false persist-credentials: false
- name: Setup Go - name: Setup Go
uses: actions/setup-go@v6.0.0 uses: actions/setup-go@v5.5.0
with: with:
go-version-file: go.mod go-version-file: go.mod
- name: Setup Enterprise - name: Setup Enterprise
+1 -1
View File
@@ -40,7 +40,7 @@ jobs:
}' "$GITHUB_EVENT_PATH" > /tmp/pr_info.json }' "$GITHUB_EVENT_PATH" > /tmp/pr_info.json
- name: Upload artifact - name: Upload artifact
uses: actions/upload-artifact@v5 uses: actions/upload-artifact@v4
with: with:
name: pr_info name: pr_info
path: /tmp/pr_info.json path: /tmp/pr_info.json
+1 -1
View File
@@ -36,7 +36,7 @@ jobs:
private_key: ${{ fromJSON(steps.secrets.outputs.secrets).APP_PEM }} private_key: ${{ fromJSON(steps.secrets.outputs.secrets).APP_PEM }}
- name: Download PR info artifact - name: Download PR info artifact
uses: actions/download-artifact@v6 uses: actions/download-artifact@v4
id: download-pr-info id: download-pr-info
with: with:
github-token: ${{ github.token }} github-token: ${{ github.token }}
+1 -1
View File
@@ -97,7 +97,7 @@ jobs:
fetch-depth: 0 fetch-depth: 0
fetch-tags: true fetch-tags: true
- name: Setup nodejs environment - name: Setup nodejs environment
uses: actions/setup-node@v6 uses: actions/setup-node@v4
with: with:
node-version-file: .nvmrc node-version-file: .nvmrc
- name: "Configure git user" - name: "Configure git user"
+1 -1
View File
@@ -12,7 +12,7 @@ jobs:
pull-requests: read pull-requests: read
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v5
- uses: grafana/shared-workflows/actions/cleanup-branches@cleanup-branches/v0.2.1 - uses: grafana/shared-workflows/actions/cleanup-branches@cleanup-branches/v1.0.0
with: with:
dry-run: true dry-run: true
max-date: "1 month ago" max-date: "1 month ago"
+3 -3
View File
@@ -72,14 +72,14 @@ jobs:
- if: matrix.language == 'go' && needs.detect-changes.outputs.go == 'true' - if: matrix.language == 'go' && needs.detect-changes.outputs.go == 'true'
name: Set go version name: Set go version
uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5
with: with:
go-version-file: go.mod go-version-file: go.mod
# Initializes the CodeQL tools for scanning. # Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL - name: Initialize CodeQL
if: needs.detect-changes.outputs[matrix.language] == 'true' if: needs.detect-changes.outputs[matrix.language] == 'true'
uses: github/codeql-action/init@v4 uses: github/codeql-action/init@v3
with: with:
languages: ${{ matrix.language }} languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file. # If you wish to specify custom queries, you can do so here or in a config file.
@@ -94,4 +94,4 @@ jobs:
make build-go make build-go
- name: Perform CodeQL Analysis - name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v4 uses: github/codeql-action/analyze@v3
@@ -64,7 +64,7 @@ jobs:
- name: 'Set up Cloud SDK' - name: 'Set up Cloud SDK'
uses: 'google-github-actions/setup-gcloud@aa5489c8933f4cc7a4f7d45035b3b1440c9c10db' uses: 'google-github-actions/setup-gcloud@aa5489c8933f4cc7a4f7d45035b3b1440c9c10db'
- name: Setup nodejs environment - name: Setup nodejs environment
uses: actions/setup-node@v6 uses: actions/setup-node@v4
with: with:
node-version-file: .nvmrc node-version-file: .nvmrc
cache: yarn cache: yarn
@@ -101,7 +101,7 @@ jobs:
echo "has_backend=false" >> "$GITHUB_OUTPUT" echo "has_backend=false" >> "$GITHUB_OUTPUT"
fi fi
- name: Setup golang environment - name: Setup golang environment
uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5
if: steps.check_backend.outputs.has_backend == 'true' if: steps.check_backend.outputs.has_backend == 'true'
with: with:
go-version-file: go.mod go-version-file: go.mod
@@ -193,7 +193,7 @@ jobs:
exit 1 exit 1
fi fi
- name: store build artifacts - name: store build artifacts
uses: actions/upload-artifact@v5 uses: actions/upload-artifact@v4
with: with:
name: build-artifacts name: build-artifacts
path: ${{ steps.get_dir.outputs.dir }}/ci/packages/*.zip path: ${{ steps.get_dir.outputs.dir }}/ci/packages/*.zip
@@ -25,5 +25,4 @@ jobs:
patch_ref: "${{ github.base_ref }}" # this is the target branch name, Ex: "main" patch_ref: "${{ github.base_ref }}" # this is the target branch name, Ex: "main"
patch_repo: "grafana/grafana-security-patches" patch_repo: "grafana/grafana-security-patches"
patch_prefix: "${{ github.event.pull_request.number }}" patch_prefix: "${{ github.event.pull_request.number }}"
sender: "${{ github.event.pull_request.user.login }}"
secrets: inherit # zizmor: ignore[secrets-inherit] secrets: inherit # zizmor: ignore[secrets-inherit]
@@ -34,7 +34,7 @@ jobs:
path: './pr' path: './pr'
persist-credentials: false persist-credentials: false
- uses: actions/setup-node@v6 - uses: actions/setup-node@v4
with: with:
node-version-file: './pr/.nvmrc' node-version-file: './pr/.nvmrc'
@@ -64,7 +64,7 @@ jobs:
run: zip -r ./pr_built_packages.zip ./packages/**/*.tgz run: zip -r ./pr_built_packages.zip ./packages/**/*.tgz
- name: Upload build output as artifact - name: Upload build output as artifact
uses: actions/upload-artifact@v5 uses: actions/upload-artifact@v4
with: with:
name: buildPr name: buildPr
path: './pr/pr_built_packages.zip' path: './pr/pr_built_packages.zip'
@@ -86,7 +86,7 @@ jobs:
ref: ${{ github.event.pull_request.base.ref }} ref: ${{ github.event.pull_request.base.ref }}
persist-credentials: false persist-credentials: false
- uses: actions/setup-node@v6 - uses: actions/setup-node@v4
with: with:
node-version-file: './base/.nvmrc' node-version-file: './base/.nvmrc'
@@ -116,7 +116,7 @@ jobs:
run: zip -r ./base_built_packages.zip ./packages/**/*.tgz run: zip -r ./base_built_packages.zip ./packages/**/*.tgz
- name: Upload build output as artifact - name: Upload build output as artifact
uses: actions/upload-artifact@v5 uses: actions/upload-artifact@v4
with: with:
name: buildBase name: buildBase
path: './base/base_built_packages.zip' path: './base/base_built_packages.zip'
@@ -136,17 +136,17 @@ jobs:
with: with:
persist-credentials: false persist-credentials: false
- uses: actions/setup-node@v6 - uses: actions/setup-node@v4
with: with:
node-version-file: '.nvmrc' node-version-file: '.nvmrc'
- name: Get built packages from pr - name: Get built packages from pr
uses: actions/download-artifact@v6 uses: actions/download-artifact@v4
with: with:
name: buildPr name: buildPr
- name: Get built packages from base - name: Get built packages from base
uses: actions/download-artifact@v6 uses: actions/download-artifact@v4
with: with:
name: buildBase name: buildBase
@@ -189,7 +189,7 @@ jobs:
PR_NUMBER: ${{ github.event.pull_request.number }} PR_NUMBER: ${{ github.event.pull_request.number }}
- name: Upload check output as artifact - name: Upload check output as artifact
uses: actions/upload-artifact@v5 uses: actions/upload-artifact@v4
with: with:
name: levitate name: levitate
path: levitate/ path: levitate/
@@ -225,7 +225,7 @@ jobs:
persist-credentials: false persist-credentials: false
- name: 'Download artifact' - name: 'Download artifact'
uses: actions/download-artifact@v6 uses: actions/download-artifact@v4
with: with:
name: levitate name: levitate
+1 -1
View File
@@ -24,7 +24,7 @@ jobs:
persist-credentials: false persist-credentials: false
- name: Set up Go - name: Set up Go
uses: actions/setup-go@v6.0.0 uses: actions/setup-go@v5.5.0
with: with:
go-version-file: 'go.mod' go-version-file: 'go.mod'
cache: true cache: true
+6 -6
View File
@@ -42,7 +42,7 @@ jobs:
- uses: actions/checkout@v5 - uses: actions/checkout@v5
with: with:
persist-credentials: false persist-credentials: false
- uses: actions/setup-node@v6 - uses: actions/setup-node@v4
with: with:
node-version-file: '.nvmrc' node-version-file: '.nvmrc'
cache: 'yarn' cache: 'yarn'
@@ -63,7 +63,7 @@ jobs:
- uses: actions/checkout@v5 - uses: actions/checkout@v5
with: with:
persist-credentials: false persist-credentials: false
- uses: actions/setup-node@v6 - uses: actions/setup-node@v4
with: with:
node-version-file: '.nvmrc' node-version-file: '.nvmrc'
cache: 'yarn' cache: 'yarn'
@@ -89,7 +89,7 @@ jobs:
- uses: actions/checkout@v5 - uses: actions/checkout@v5
with: with:
persist-credentials: false persist-credentials: false
- uses: actions/setup-node@v6 - uses: actions/setup-node@v4
with: with:
node-version-file: '.nvmrc' node-version-file: '.nvmrc'
cache: 'yarn' cache: 'yarn'
@@ -109,7 +109,7 @@ jobs:
- uses: actions/checkout@v5 - uses: actions/checkout@v5
with: with:
persist-credentials: false persist-credentials: false
- uses: actions/setup-node@v6 - uses: actions/setup-node@v4
with: with:
node-version-file: '.nvmrc' node-version-file: '.nvmrc'
cache: 'yarn' cache: 'yarn'
@@ -133,7 +133,7 @@ jobs:
- uses: actions/checkout@v5 - uses: actions/checkout@v5
with: with:
persist-credentials: false persist-credentials: false
- uses: actions/setup-node@v6 - uses: actions/setup-node@v4
with: with:
node-version-file: '.nvmrc' node-version-file: '.nvmrc'
cache: 'yarn' cache: 'yarn'
@@ -164,7 +164,7 @@ jobs:
- uses: actions/checkout@v5 - uses: actions/checkout@v5
with: with:
persist-credentials: false persist-credentials: false
- uses: actions/setup-node@v6 - uses: actions/setup-node@v4
with: with:
node-version-file: '.nvmrc' node-version-file: '.nvmrc'
cache: 'yarn' cache: 'yarn'
+2 -2
View File
@@ -41,7 +41,7 @@ jobs:
- uses: actions/checkout@v5 - uses: actions/checkout@v5
with: with:
persist-credentials: false persist-credentials: false
- uses: actions/setup-go@v6.0.0 - uses: actions/setup-go@v5.5.0
with: with:
go-version-file: ./go.mod go-version-file: ./go.mod
- name: Run gofmt - name: Run gofmt
@@ -62,7 +62,7 @@ jobs:
- uses: actions/checkout@v5 - uses: actions/checkout@v5
with: with:
persist-credentials: false persist-credentials: false
- uses: actions/setup-go@v6.0.0 - uses: actions/setup-go@v5.5.0
with: with:
go-version-file: ./go.mod go-version-file: ./go.mod
- name: golangci-lint - name: golangci-lint
+3 -3
View File
@@ -39,7 +39,7 @@ jobs:
- name: "Get vault secrets" - name: "Get vault secrets"
id: vault-secrets id: vault-secrets
uses: grafana/shared-workflows/actions/get-vault-secrets@get-vault-secrets/v1.3.0 # zizmor: ignore[unpinned-uses] uses: grafana/shared-workflows/actions/get-vault-secrets@get-vault-secrets/v1.2.1 # zizmor: ignore[unpinned-uses]
with: with:
# Secrets placed in the ci/repo/grafana/grafana/plugins_platform_issue_commands_github_bot path in Vault # Secrets placed in the ci/repo/grafana/grafana/plugins_platform_issue_commands_github_bot path in Vault
repo_secrets: | repo_secrets: |
@@ -71,7 +71,7 @@ jobs:
- name: "Get vault secrets" - name: "Get vault secrets"
id: vault-secrets id: vault-secrets
uses: grafana/shared-workflows/actions/get-vault-secrets@get-vault-secrets/v1.3.0 # zizmor: ignore[unpinned-uses] uses: grafana/shared-workflows/actions/get-vault-secrets@get-vault-secrets/v1.2.1 # zizmor: ignore[unpinned-uses]
with: with:
# Secrets placed in the ci/repo/grafana/grafana/plugins_platform_issue_triager path in Vault # Secrets placed in the ci/repo/grafana/grafana/plugins_platform_issue_triager path in Vault
repo_secrets: | repo_secrets: |
@@ -139,7 +139,7 @@ jobs:
steps: steps:
- name: "Get vault secrets" - name: "Get vault secrets"
id: vault-secrets id: vault-secrets
uses: grafana/shared-workflows/actions/get-vault-secrets@get-vault-secrets/v1.3.0 # zizmor: ignore[unpinned-uses] uses: grafana/shared-workflows/actions/get-vault-secrets@get-vault-secrets/v1.2.1 # zizmor: ignore[unpinned-uses]
with: with:
# Secrets placed in the ci/repo/grafana/grafana/plugins_platform_issue_triager path in Vault # Secrets placed in the ci/repo/grafana/grafana/plugins_platform_issue_triager path in Vault
repo_secrets: | repo_secrets: |
+1 -1
View File
@@ -35,7 +35,7 @@ jobs:
persist-credentials: false persist-credentials: false
- name: Setup Node.js - name: Setup Node.js
uses: actions/setup-node@v6 uses: actions/setup-node@v4
with: with:
node-version-file: '.nvmrc' node-version-file: '.nvmrc'
cache: 'yarn' cache: 'yarn'
@@ -29,9 +29,9 @@ jobs:
# Initializes the CodeQL tools for scanning. # Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL - name: Initialize CodeQL
uses: github/codeql-action/init@v4 uses: github/codeql-action/init@v3
with: with:
languages: "javascript" languages: "javascript"
- name: Perform CodeQL Analysis - name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v4 uses: github/codeql-action/analyze@v3
@@ -39,10 +39,10 @@ jobs:
# Initializes the CodeQL tools for scanning. # Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL - name: Initialize CodeQL
if: steps.check-python.outputs.skip != 'true' if: steps.check-python.outputs.skip != 'true'
uses: github/codeql-action/init@v4 uses: github/codeql-action/init@v3
with: with:
languages: "python" languages: "python"
- name: Perform CodeQL Analysis - name: Perform CodeQL Analysis
if: steps.check-python.outputs.skip != 'true' if: steps.check-python.outputs.skip != 'true'
uses: github/codeql-action/analyze@v4 uses: github/codeql-action/analyze@v3
@@ -45,7 +45,7 @@ jobs:
persist-credentials: false persist-credentials: false
- name: Set go version - name: Set go version
uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5
with: with:
go-version-file: go.mod go-version-file: go.mod
+19 -19
View File
@@ -94,14 +94,14 @@ jobs:
id: artifact id: artifact
- name: Upload grafana.tar.gz - name: Upload grafana.tar.gz
uses: actions/upload-artifact@v5 uses: actions/upload-artifact@v4
with: with:
retention-days: 1 retention-days: 1
name: grafana-tar-gz name: grafana-tar-gz
path: build-dir/grafana.tar.gz path: build-dir/grafana.tar.gz
- name: Upload grafana docker tarball - name: Upload grafana docker tarball
uses: actions/upload-artifact@v5 uses: actions/upload-artifact@v4
with: with:
retention-days: 1 retention-days: 1
name: grafana-docker-tar-gz name: grafana-docker-tar-gz
@@ -122,7 +122,7 @@ jobs:
with: with:
persist-credentials: false persist-credentials: false
- name: Setup Go - name: Setup Go
uses: actions/setup-go@v6.0.0 uses: actions/setup-go@v5.5.0
with: with:
go-version-file: go.mod go-version-file: go.mod
cache: ${{ !github.event.pull_request.head.repo.fork }} cache: ${{ !github.event.pull_request.head.repo.fork }}
@@ -133,7 +133,7 @@ jobs:
# We want a static binary, so we need to set CGO_ENABLED=0 # We want a static binary, so we need to set CGO_ENABLED=0
CGO_ENABLED=0 go build -o ./e2e-runner ./e2e/ CGO_ENABLED=0 go build -o ./e2e-runner ./e2e/
echo "artifact=e2e-runner-${{github.run_number}}" >> "$GITHUB_OUTPUT" echo "artifact=e2e-runner-${{github.run_number}}" >> "$GITHUB_OUTPUT"
- uses: actions/upload-artifact@v5 - uses: actions/upload-artifact@v4
id: upload id: upload
with: with:
retention-days: 1 retention-days: 1
@@ -159,7 +159,7 @@ jobs:
with: with:
registry: 'us-docker.pkg.dev' registry: 'us-docker.pkg.dev'
environment: 'dev' environment: 'dev'
- uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093
with: with:
name: grafana-docker-tar-gz name: grafana-docker-tar-gz
path: . path: .
@@ -221,10 +221,10 @@ jobs:
- uses: actions/checkout@v5 - uses: actions/checkout@v5
with: with:
persist-credentials: false persist-credentials: false
- uses: actions/download-artifact@v6 - uses: actions/download-artifact@v4
with: with:
name: grafana-tar-gz name: grafana-tar-gz
- uses: actions/download-artifact@v6 - uses: actions/download-artifact@v4
with: with:
name: ${{ needs.build-e2e-runner.outputs.artifact }} name: ${{ needs.build-e2e-runner.outputs.artifact }}
- name: chmod +x - name: chmod +x
@@ -245,7 +245,7 @@ jobs:
run: | run: |
set -euo pipefail set -euo pipefail
echo "suite=$(echo "$SUITE" | sed 's/\//-/g')" >> "$GITHUB_OUTPUT" echo "suite=$(echo "$SUITE" | sed 's/\//-/g')" >> "$GITHUB_OUTPUT"
- uses: actions/upload-artifact@v5 - uses: actions/upload-artifact@v4
if: success() || failure() if: success() || failure()
with: with:
name: ${{ steps.set-suite-name.outputs.suite }}-${{ github.run_number }} name: ${{ steps.set-suite-name.outputs.suite }}-${{ github.run_number }}
@@ -267,7 +267,7 @@ jobs:
persist-credentials: false persist-credentials: false
- name: Setup Node.js - name: Setup Node.js
uses: actions/setup-node@v6 uses: actions/setup-node@v4
with: with:
node-version-file: '.nvmrc' node-version-file: '.nvmrc'
@@ -298,7 +298,7 @@ jobs:
- uses: actions/checkout@v5 - uses: actions/checkout@v5
with: with:
persist-credentials: false persist-credentials: false
- uses: actions/download-artifact@v6 - uses: actions/download-artifact@v4
with: with:
name: grafana-tar-gz name: grafana-tar-gz
- name: Run E2E tests - name: Run E2E tests
@@ -307,7 +307,7 @@ jobs:
version: 0.18.8 version: 0.18.8
verb: run verb: run
args: go run ./pkg/build/e2e-playwright --package=grafana.tar.gz --shard=${{ matrix.shard }}/${{ matrix.shardTotal }} --blob-dir=./blob-report args: go run ./pkg/build/e2e-playwright --package=grafana.tar.gz --shard=${{ matrix.shard }}/${{ matrix.shardTotal }} --blob-dir=./blob-report
- uses: actions/upload-artifact@v5 - uses: actions/upload-artifact@v4
if: success() || failure() if: success() || failure()
with: with:
name: playwright-blob-${{ github.run_number }}-${{ matrix.shard }} name: playwright-blob-${{ github.run_number }}-${{ matrix.shard }}
@@ -360,7 +360,7 @@ jobs:
run: | run: |
docker cp cpp-e2e-deploy:/outputs.json /tmp/outputs.json docker cp cpp-e2e-deploy:/outputs.json /tmp/outputs.json
- uses: actions/download-artifact@v6 - uses: actions/download-artifact@v4
with: with:
name: grafana-tar-gz name: grafana-tar-gz
@@ -395,12 +395,12 @@ jobs:
with: with:
persist-credentials: false persist-credentials: false
- uses: actions/setup-node@v6 - uses: actions/setup-node@v4
with: with:
node-version-file: '.nvmrc' node-version-file: '.nvmrc'
- name: Download blob reports from GitHub Actions Artifacts - name: Download blob reports from GitHub Actions Artifacts
uses: actions/download-artifact@v6 uses: actions/download-artifact@v4
with: with:
path: blobs path: blobs
pattern: playwright-blob-* pattern: playwright-blob-*
@@ -439,7 +439,7 @@ jobs:
- name: Upload HTML report - name: Upload HTML report
id: upload-html id: upload-html
uses: actions/upload-artifact@v5 uses: actions/upload-artifact@v4
with: with:
name: playwright-html-${{ github.run_number }} name: playwright-html-${{ github.run_number }}
path: playwright-report path: playwright-report
@@ -479,7 +479,7 @@ jobs:
- uses: actions/checkout@v5 - uses: actions/checkout@v5
with: with:
persist-credentials: false persist-credentials: false
- uses: actions/download-artifact@v6 - uses: actions/download-artifact@v4
with: with:
name: grafana-tar-gz name: grafana-tar-gz
- name: Run PR a11y test - name: Run PR a11y test
@@ -498,7 +498,7 @@ jobs:
args: go run ./pkg/build/a11y --package=grafana.tar.gz --no-threshold-fail --results=./pa11y-ci-results.json args: go run ./pkg/build/a11y --package=grafana.tar.gz --no-threshold-fail --results=./pa11y-ci-results.json
- name: Upload pa11y results - name: Upload pa11y results
if: github.event_name != 'pull_request' if: github.event_name != 'pull_request'
uses: actions/upload-artifact@v5 uses: actions/upload-artifact@v4
with: with:
retention-days: 1 retention-days: 1
name: pa11y-ci-results name: pa11y-ci-results
@@ -525,13 +525,13 @@ jobs:
with: with:
persist-credentials: false persist-credentials: false
- name: Setup Node.js - name: Setup Node.js
uses: actions/setup-node@v6 uses: actions/setup-node@v4
with: with:
node-version-file: '.nvmrc' node-version-file: '.nvmrc'
- name: Install dependencies - name: Install dependencies
run: yarn install --immutable run: yarn install --immutable
- name: Get pa11y results - name: Get pa11y results
uses: actions/download-artifact@v6 uses: actions/download-artifact@v4
with: with:
name: pa11y-ci-results name: pa11y-ci-results
- name: Extract and publish metrics - name: Extract and publish metrics
@@ -18,7 +18,6 @@ jobs:
contents: read contents: read
outputs: outputs:
changed: ${{ steps.detect-changes.outputs.frontend }} changed: ${{ steps.detect-changes.outputs.frontend }}
devenv-changed: ${{ steps.detect-changes.outputs.devenv }}
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v5
with: with:
@@ -170,26 +169,3 @@ jobs:
needs: ${{ toJson(needs) }} needs: ${{ toJson(needs) }}
failure-message: "One or more unit test jobs have failed" failure-message: "One or more unit test jobs have failed"
success-message: "All unit tests completed successfully" success-message: "All unit tests completed successfully"
devenv:
needs:
- detect-changes
if: needs.detect-changes.outputs.devenv-changed == 'true'
runs-on: ubuntu-x64-large
name: "Devenv frontend-service build"
steps:
- uses: actions/checkout@v5
with:
persist-credentials: false
- name: Setup Docker
uses: docker/setup-docker-action@3fb92d6d9c634363128c8cce4bc3b2826526370a # v4
- name: Setup Node.js
uses: ./.github/actions/setup-node
- name: Install Tilt
run: curl -fsSL https://raw.githubusercontent.com/tilt-dev/tilt/master/scripts/install.sh | bash
- name: Create empty config files # TODO: the tiltfile should conditionally mount these only if they exist, like the enterprise license
run: |
touch devenv/frontend-service/configs/grafana-api.local.ini
touch devenv/frontend-service/configs/frontend-service.local.ini
- name: Test frontend-service Tiltfile
run: tilt ci --file devenv/frontend-service/Tiltfile
+2 -2
View File
@@ -39,7 +39,7 @@ jobs:
persist-credentials: false persist-credentials: false
- name: Set go version - name: Set go version
uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5
with: with:
cache: false cache: false
go-version-file: go.mod go-version-file: go.mod
@@ -76,7 +76,7 @@ jobs:
persist-credentials: false persist-credentials: false
- name: Set go version - name: Set go version
uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5
with: with:
cache: false cache: false
go-version-file: go.mod go-version-file: go.mod
+1 -1
View File
@@ -24,7 +24,7 @@ jobs:
persist-credentials: false persist-credentials: false
- name: Set go version - name: Set go version
uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5
with: with:
go-version-file: go.mod go-version-file: go.mod
+2 -2
View File
@@ -21,7 +21,7 @@ jobs:
id: detect-changes id: detect-changes
uses: ./.github/actions/change-detection uses: ./.github/actions/change-detection
with: with:
self: .github/workflows/pr-test-docker.yml self: .github/workflows/pr-test-integration.yml
build-dockerfile: build-dockerfile:
needs: detect-changes needs: detect-changes
@@ -34,6 +34,6 @@ jobs:
uses: actions/checkout@v5 uses: actions/checkout@v5
with: with:
persist-credentials: false persist-credentials: false
- uses: docker/setup-docker-action@3fb92d6d9c634363128c8cce4bc3b2826526370a # v4 - uses: docker/setup-docker-action@b60f85385d03ac8acfca6d9996982511d8620a19 # v4
- name: Build Dockerfile - name: Build Dockerfile
run: make build-docker-full run: make build-docker-full
+7 -70
View File
@@ -58,7 +58,7 @@ jobs:
with: with:
persist-credentials: false persist-credentials: false
- name: Setup Go - name: Setup Go
uses: actions/setup-go@v6.0.0 uses: actions/setup-go@v5.5.0
with: with:
go-version-file: go.mod go-version-file: go.mod
cache: true cache: true
@@ -68,7 +68,7 @@ jobs:
run: | run: |
set -euo pipefail 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-)" 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: sqlite_nocgo:
needs: detect-changes needs: detect-changes
@@ -78,7 +78,6 @@ jobs:
# We don't need more than this since it has to wait for the other tests. # We don't need more than this since it has to wait for the other tests.
shard: [ shard: [
1/4, 2/4, 3/4, 4/4, 1/4, 2/4, 3/4, 4/4,
profiled,
] ]
fail-fast: false fail-fast: false
@@ -92,79 +91,17 @@ jobs:
with: with:
persist-credentials: false persist-credentials: false
- name: Setup Go - name: Setup Go
uses: actions/setup-go@v6.0.0 uses: actions/setup-go@v5.5.0
with: with:
go-version-file: go.mod go-version-file: go.mod
cache: true cache: true
- name: Run tests - name: Run tests
if: matrix.shard != 'profiled'
env: env:
SHARD: ${{ matrix.shard }} SHARD: ${{ matrix.shard }}
CGO_ENABLED: 0
SKIP_PACKAGES: |-
pkg/tests/apis/folder
pkg/tests/apis/dashboard
run: | run: |
set -euo pipefail set -euo pipefail
# Build regex pattern like: pkg1$|pkg2$|pkg3$ readarray -t PACKAGES <<< "$(./scripts/ci/backend-tests/pkgs-with-tests-named.sh -b TestIntegration | ./scripts/ci/backend-tests/shard.sh -N"$SHARD" -d-)"
SKIP_PATTERN=$(echo "$SKIP_PACKAGES" | sed '/^$/d' | sed 's|.*|&$|' | paste -sd '|' -) CGO_ENABLED=0 go test -tags=sqlite -timeout=8m -run '^TestIntegration' "${PACKAGES[@]}"
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[@]}"
- name: Run profiled tests
id: run-profiled-tests
if: matrix.shard == 'profiled'
env:
CGO_ENABLED: 0
PROFILED_PACKAGES: |-
pkg/tests/apis/folder
pkg/tests/apis/dashboard
run: |
set -euo pipefail
# Build regex pattern line: pkg1$|pkg2$|pkg3$
PROFILE_PATTERN=$(echo "$PROFILED_PACKAGES" | sed '/^$/d' | sed 's|.*|&$|' | paste -sd '|' -)
readarray -t PACKAGES <<< "$(./scripts/ci/backend-tests/pkgs-with-tests-named.sh -b TestIntegration | grep -E "($PROFILE_PATTERN)")"
if [ ${#PACKAGES[@]} -eq 0 ]; then
echo "⚠️ No profiled packages found"
exit 0
fi
mkdir -p profiles
EXIT_CODE=0
# Run each profiled package sequentially
for full_pkg in "${PACKAGES[@]}"; do
# Build valid file name
pkg_name=$(basename "$full_pkg" | tr '/' '_' | tr '.' '_')
echo "📦 Running $full_pkg"
set +e
go test -tags=sqlite -timeout=12m -run '^TestIntegration' \
-outputdir=profiles \
-cpuprofile="cpu_${pkg_name}.prof" \
-memprofile="mem_${pkg_name}.prof" \
-trace="trace_${pkg_name}.out" \
"$full_pkg" 2>&1 | tee "profiles/test_${pkg_name}.log"
TEST_EXIT=$?
set -e
if [ $TEST_EXIT -ne 0 ]; then
echo "❌ $full_pkg failed with exit code $TEST_EXIT"
EXIT_CODE=1
else
echo "✅ $full_pkg passed"
fi
done
# Set output for artifact upload
if [ $EXIT_CODE -ne 0 ]; then
echo "upload_artifacts=true" >> "$GITHUB_OUTPUT"
else
echo "upload_artifacts=false" >> "$GITHUB_OUTPUT"
fi
exit $EXIT_CODE
- name: Output test profiles and traces
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v4
if: matrix.shard == 'profiled' && !cancelled() && steps.run-profiled-tests.outputs.upload_artifacts == 'true'
with:
name: integration-test-profiles-sqlite-nocgo-${{ github.run_number }}
path: profiles/
retention-days: 7
if-no-files-found: ignore
mysql: mysql:
needs: detect-changes needs: detect-changes
if: needs.detect-changes.outputs.changed == 'true' if: needs.detect-changes.outputs.changed == 'true'
@@ -202,7 +139,7 @@ jobs:
with: with:
persist-credentials: false persist-credentials: false
- name: Setup Go - name: Setup Go
uses: actions/setup-go@v6.0.0 uses: actions/setup-go@v5.5.0
with: with:
go-version-file: go.mod go-version-file: go.mod
cache: true cache: true
@@ -251,7 +188,7 @@ jobs:
with: with:
persist-credentials: false persist-credentials: false
- name: Setup Go - name: Setup Go
uses: actions/setup-go@v6.0.0 uses: actions/setup-go@v5.5.0
with: with:
go-version-file: go.mod go-version-file: go.mod
cache: true cache: true
+1 -1
View File
@@ -44,7 +44,7 @@ jobs:
permissions: permissions:
id-token: write id-token: write
steps: steps:
- uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093
with: with:
name: ${{ inputs.name }} name: ${{ inputs.name }}
pattern: ${{ inputs.pattern }} pattern: ${{ inputs.pattern }}
+1 -1
View File
@@ -27,7 +27,7 @@ jobs:
persist-credentials: false persist-credentials: false
- name: "Setup Go" - name: "Setup Go"
uses: "actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00" uses: "actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5"
with: with:
go-version-file: go.mod go-version-file: go.mod
+1 -1
View File
@@ -30,7 +30,7 @@ jobs:
persist-credentials: false persist-credentials: false
- name: "Setup Go" - name: "Setup Go"
uses: "actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00" uses: "actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5"
with: with:
go-version-file: go.mod go-version-file: go.mod
+13 -13
View File
@@ -156,16 +156,16 @@ jobs:
artifacts: targz:grafana:linux/arm/v6,deb:grafana:linux/arm/v6 artifacts: targz:grafana:linux/arm/v6,deb:grafana:linux/arm/v6
verify: true verify: true
- name: windows-amd64 - name: windows-amd64
artifacts: targz:grafana:windows/amd64:nocgo,zip:grafana:windows/amd64:nocgo,msi:grafana:windows/amd64:nocgo artifacts: targz:grafana:windows/amd64,zip:grafana:windows/amd64,msi:grafana:windows/amd64
verify: true verify: true
- name: windows-arm64 - name: windows-arm64
artifacts: targz:grafana:windows/arm64:nocgo,zip:grafana:windows/arm64:nocgo artifacts: targz:grafana:windows/arm64,zip:grafana:windows/arm64
verify: true verify: true
- name: darwin-amd64 - name: darwin-amd64
artifacts: targz:grafana:darwin/amd64:nocgo artifacts: targz:grafana:darwin/amd64
verify: true verify: true
- name: darwin-arm64 - name: darwin-arm64
artifacts: targz:grafana:darwin/arm64:nocgo artifacts: targz:grafana:darwin/arm64
verify: true verify: true
steps: steps:
- uses: grafana/shared-workflows/actions/dockerhub-login@dockerhub-login/v1.0.2 - uses: grafana/shared-workflows/actions/dockerhub-login@dockerhub-login/v1.0.2
@@ -187,12 +187,12 @@ jobs:
output: artifacts-${{ matrix.name }}.txt output: artifacts-${{ matrix.name }}.txt
verify: ${{ matrix.verify }} verify: ${{ matrix.verify }}
build-id: ${{ github.run_id }} build-id: ${{ github.run_id }}
- uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
with: with:
name: artifacts-list-${{ matrix.name }} name: artifacts-list-${{ matrix.name }}
path: ${{ steps.build.outputs.file }} path: ${{ steps.build.outputs.file }}
retention-days: 1 retention-days: 1
- uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
with: with:
name: artifacts-${{ matrix.name }} name: artifacts-${{ matrix.name }}
path: ${{ steps.build.outputs.dist-dir }} path: ${{ steps.build.outputs.dist-dir }}
@@ -224,27 +224,27 @@ jobs:
- build - build
steps: steps:
- uses: grafana/shared-workflows/actions/dockerhub-login@dockerhub-login/v1.0.2 - uses: grafana/shared-workflows/actions/dockerhub-login@dockerhub-login/v1.0.2
- uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093
with: with:
name: artifacts-list-linux-amd64 name: artifacts-list-linux-amd64
path: . path: .
- uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093
with: with:
name: artifacts-list-linux-arm64 name: artifacts-list-linux-arm64
path: . path: .
- uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093
with: with:
name: artifacts-list-linux-armv7 name: artifacts-list-linux-armv7
path: . path: .
- uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093
with: with:
name: artifacts-linux-amd64 name: artifacts-linux-amd64
path: dist path: dist
- uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093
with: with:
name: artifacts-linux-arm64 name: artifacts-linux-arm64
path: dist path: dist
- uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093
with: with:
name: artifacts-linux-armv7 name: artifacts-linux-armv7
path: dist path: dist
@@ -333,7 +333,7 @@ jobs:
body-includes: GitHub Actions Build body-includes: GitHub Actions Build
token: ${{ steps.generate_token.outputs.token }} token: ${{ steps.generate_token.outputs.token }}
- name: Create or update comment - name: Create or update comment
uses: peter-evans/create-or-update-comment@e8674b075228eee787fea43ef493e45ece1004c9 # v4 uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4
with: with:
token: ${{ steps.generate_token.outputs.token }} token: ${{ steps.generate_token.outputs.token }}
comment-id: ${{ steps.fc.outputs.comment-id }} comment-id: ${{ steps.fc.outputs.comment-id }}
+7 -2
View File
@@ -60,7 +60,7 @@ jobs:
echo "github.ref: $GITHUB_REF" echo "github.ref: $GITHUB_REF"
- name: Checkout workflow ref - name: Checkout workflow ref
uses: actions/checkout@v5 uses: actions/checkout@v4
with: with:
persist-credentials: false persist-credentials: false
fetch-depth: 100 fetch-depth: 100
@@ -86,7 +86,7 @@ jobs:
shell: bash shell: bash
- name: Checkout build commit - name: Checkout build commit
uses: actions/checkout@v5 uses: actions/checkout@v4
with: with:
persist-credentials: false persist-credentials: false
ref: ${{ inputs.grafana_commit }} ref: ${{ inputs.grafana_commit }}
@@ -123,6 +123,11 @@ jobs:
- name: Validate packages - name: Validate packages
run: ./scripts/validate-npm-packages.sh run: ./scripts/validate-npm-packages.sh
- name: Debug OIDC Claims
uses: github/actions-oidc-debugger@2e9ba5d3f4bebaad1f91a2cede055115738b7ae8
with:
audience: '${{ github.server_url }}/${{ github.repository_owner }}'
- name: Publish packages - name: Publish packages
env: env:
NPM_TAG: ${{ steps.npm-tag.outputs.NPM_TAG }} NPM_TAG: ${{ steps.npm-tag.outputs.NPM_TAG }}
+2 -2
View File
@@ -133,10 +133,10 @@ jobs:
path: .grafana-main path: .grafana-main
- name: Setup nodejs environment - name: Setup nodejs environment
uses: actions/setup-node@v6 uses: actions/setup-node@v4
with: with:
node-version-file: .nvmrc node-version-file: .nvmrc
- uses: actions/setup-go@v6.0.0 - uses: actions/setup-go@v5.5.0
with: with:
go-version-file: go.mod go-version-file: go.mod
- name: Configure git user - name: Configure git user
@@ -29,12 +29,12 @@ jobs:
with: with:
persist-credentials: false persist-credentials: false
- name: Pin Go version to mod file - name: Pin Go version to mod file
uses: actions/setup-go@v6.0.0 uses: actions/setup-go@v5.5.0
with: with:
go-version-file: 'go.mod' go-version-file: 'go.mod'
cache: true cache: true
- run: go version - run: go version
- uses: actions/setup-node@v6 - uses: actions/setup-node@v4
with: with:
node-version-file: '.nvmrc' node-version-file: '.nvmrc'
cache: 'yarn' cache: 'yarn'
+2 -2
View File
@@ -22,11 +22,11 @@ jobs:
with: with:
persist-credentials: false persist-credentials: false
- name: Pin Go version to mod file - name: Pin Go version to mod file
uses: actions/setup-go@v6.0.0 uses: actions/setup-go@v5.5.0
with: with:
go-version-file: 'go.mod' go-version-file: 'go.mod'
- run: go version - run: go version
- uses: actions/setup-node@v6 - uses: actions/setup-node@v4
with: with:
node-version-file: '.nvmrc' node-version-file: '.nvmrc'
cache: 'yarn' cache: 'yarn'
+1 -1
View File
@@ -11,7 +11,7 @@ jobs:
stale: stale:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/stale@v10 - uses: actions/stale@v9
with: with:
repo-token: ${{ secrets.GITHUB_TOKEN }} repo-token: ${{ secrets.GITHUB_TOKEN }}
operations-per-run: 750 operations-per-run: 750
+4 -4
View File
@@ -34,12 +34,12 @@ jobs:
id-token: write id-token: write
needs: detect-changes needs: detect-changes
if: needs.detect-changes.outputs.changed == 'true' if: needs.detect-changes.outputs.changed == 'true'
name: "Run Storybook a11y tests (light theme)" name: "Run Storybook a11y tests"
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v5
with: with:
persist-credentials: false persist-credentials: false
- uses: actions/setup-node@v6 - uses: actions/setup-node@v5
with: with:
node-version-file: '.nvmrc' node-version-file: '.nvmrc'
package-manager-cache: false # too large for GH's cache limits :-( package-manager-cache: false # too large for GH's cache limits :-(
@@ -64,12 +64,12 @@ jobs:
id-token: write id-token: write
needs: detect-changes needs: detect-changes
if: needs.detect-changes.outputs.changed == 'true' if: needs.detect-changes.outputs.changed == 'true'
name: "Run Storybook a11y tests (dark theme)" name: "Run Storybook a11y tests"
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v5
with: with:
persist-credentials: false persist-credentials: false
- uses: actions/setup-node@v6 - uses: actions/setup-node@v5
with: with:
node-version-file: '.nvmrc' node-version-file: '.nvmrc'
package-manager-cache: false # too large for GH's cache limits :-( package-manager-cache: false # too large for GH's cache limits :-(
+1 -1
View File
@@ -49,7 +49,7 @@ jobs:
with: with:
persist-credentials: false persist-credentials: false
- name: Setup Go - name: Setup Go
uses: actions/setup-go@v6.0.0 uses: actions/setup-go@v5.5.0
with: with:
go-version-file: go.mod go-version-file: go.mod
- name: Setup Enterprise - name: Setup Enterprise
+2 -2
View File
@@ -20,7 +20,7 @@ jobs:
with: with:
persist-credentials: false persist-credentials: false
- name: Install Trivy - name: Install Trivy
uses: aquasecurity/setup-trivy@e6c2c5e321ed9123bda567646e2f96565e34abe1 uses: aquasecurity/setup-trivy@9ea583eb67910444b1f64abf338bd2e105a0a93d
with: with:
version: v0.56.2 version: v0.56.2
cache: true cache: true
@@ -64,7 +64,7 @@ jobs:
. .
if: always() && github.repository == 'grafana/grafana' if: always() && github.repository == 'grafana/grafana'
- name: Upload Trivy scan results to GitHub Security tab - name: Upload Trivy scan results to GitHub Security tab
uses: github/codeql-action/upload-sarif@v4 uses: github/codeql-action/upload-sarif@v3
with: with:
sarif_file: 'trivy-results.sarif' sarif_file: 'trivy-results.sarif'
if: always() && github.repository == 'grafana/grafana' if: always() && github.repository == 'grafana/grafana'
+1 -1
View File
@@ -31,6 +31,6 @@ jobs:
persist-credentials: false persist-credentials: false
fetch-depth: ${{ steps.fetch_depth.outputs.fetch_depth }} fetch-depth: ${{ steps.fetch_depth.outputs.fetch_depth }}
- name: Trufflehog - name: Trufflehog
uses: trufflesecurity/trufflehog@b84c3d14d189e16da175e2c27fa8136603783ffc # v3.90.12 uses: trufflesecurity/trufflehog@e88e7d019eb84ca64f6b768c82eb6bf1a6271401 # v3.90.9
with: with:
extra_args: --results=verified extra_args: --results=verified
+1 -1
View File
@@ -17,6 +17,6 @@ jobs:
bundle-schema-types: bundle-schema-types:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- uses: grafana/plugin-actions/bundle-schema-types@main - uses: grafana/plugin-actions/bundle-schema-types@main
+1 -1
View File
@@ -21,7 +21,7 @@ jobs:
persist-credentials: false persist-credentials: false
- name: "Setup Go" - name: "Setup Go"
uses: "actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00" uses: "actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5"
with: with:
go-version-file: go.mod go-version-file: go.mod
+1 -4
View File
@@ -250,12 +250,9 @@ public/mockServiceWorker.js
/e2e-playwright/test-plugins/*/dist /e2e-playwright/test-plugins/*/dist
/apps/provisioning/cmd/job-controller/bin/ /apps/provisioning/cmd/job-controller/bin/
# Ignore unified storage kv store files # Ignore unified storage kv store files
/grafana-kv-data /grafana-kv-data
# Ignore debug output from test library
/pkg/storage/secret/metadata/testdata/rapid/TestStateMachine/
/codeowners-manifest/ /codeowners-manifest/
# Ignore grafana/hippocampus local cache folder # Ignore grafana/hippocampus local cache folder
+1 -1
View File
@@ -83,7 +83,7 @@ linters:
deny: deny:
- pkg: github.com/grafana/grafana/pkg - pkg: github.com/grafana/grafana/pkg
desc: apps/playlist is not allowed to import grafana core desc: apps/playlist is not allowed to import grafana core
apps-secret: apps-secret:
list-mode: lax list-mode: lax
files: files:
- ./apps/secret/* - ./apps/secret/*
+1 -1
View File
@@ -1 +1 @@
v24.11.0 v22.16.0
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -25,6 +25,6 @@ plugins:
path: .yarn/plugins/@yarnpkg/plugin-licenses.cjs path: .yarn/plugins/@yarnpkg/plugin-licenses.cjs
spec: "https://raw.githubusercontent.com/mhassan1/yarn-plugin-licenses/v0.15.0/bundles/@yarnpkg/plugin-licenses.js" 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.9.4.cjs
enableScripts: false enableScripts: false
-89
View File
@@ -1,92 +1,3 @@
<!-- 12.2.1 START -->
# 12.2.1 (2025-10-21)
### Features and enhancements
- **Go:** Update to 1.25.2 + golangci-lint v2.5.0 + golang.org/x/net v0.45.0 [#112156](https://github.com/grafana/grafana/pull/112156), [@macabu](https://github.com/macabu)
- **Go:** Update to 1.25.3 [#112361](https://github.com/grafana/grafana/pull/112361), [@macabu](https://github.com/macabu)
### Bug fixes
- **Auth:** Fix render user OAuth passthrough [#112092](https://github.com/grafana/grafana/pull/112092), [@mgyongyosi](https://github.com/mgyongyosi)
- **Dashboards:** Fix missing Ctrl+O keyboard shortcut for crosshair toggle [#111402](https://github.com/grafana/grafana/pull/111402), [@ivanortegaalba](https://github.com/ivanortegaalba)
- **Fix:** Fix redirection after login when Grafana is served from subpath [#111069](https://github.com/grafana/grafana/pull/111069), [@mgyongyosi](https://github.com/mgyongyosi)
- **FlameGraph:** Ensure total is only counted once for recursive function calls [#111606](https://github.com/grafana/grafana/pull/111606), [@simonswine](https://github.com/simonswine)
- **LDAP Authentication:** Fix URL to propagate username context as parameter [#111849](https://github.com/grafana/grafana/pull/111849), [@bradleypettit](https://github.com/bradleypettit)
- **Plugins:** Dependencies do not inherit parent URL for preinstall [#111769](https://github.com/grafana/grafana/pull/111769), [@wbrowne](https://github.com/wbrowne)
- **Table:** Backport the Safari 26 fixes to 12.2.1 [#111906](https://github.com/grafana/grafana/pull/111906), [@fastfrwrd](https://github.com/fastfrwrd)
<!-- 12.2.1 END -->
<!-- 12.1.3 START -->
# 12.1.3 (2025-10-21)
### Features and enhancements
- **Go:** Update to 1.25.2 + golangci-lint v2.5.0 + golang.org/x/net v0.45.0 [#112159](https://github.com/grafana/grafana/pull/112159), [@macabu](https://github.com/macabu)
- **Go:** Update to 1.25.3 [#112362](https://github.com/grafana/grafana/pull/112362), [@macabu](https://github.com/macabu)
- **Table:** Avoid thrown error due to internal React issue [#111945](https://github.com/grafana/grafana/pull/111945), [@fastfrwrd](https://github.com/fastfrwrd)
### Bug fixes
- **Auth:** Fix render user OAuth passthrough [#112097](https://github.com/grafana/grafana/pull/112097), [@mgyongyosi](https://github.com/mgyongyosi)
- **FlameGraph:** Ensure total is only counted once for recursive function calls [#111605](https://github.com/grafana/grafana/pull/111605), [@simonswine](https://github.com/simonswine)
- **LDAP Authentication:** Fix URL to propagate username context as parameter [#111848](https://github.com/grafana/grafana/pull/111848), [@bradleypettit](https://github.com/bradleypettit)
- **Plugins:** Dependencies do not inherit parent URL for preinstall [#111767](https://github.com/grafana/grafana/pull/111767), [@wbrowne](https://github.com/wbrowne)
<!-- 12.1.3 END -->
<!-- 12.0.6 START -->
# 12.0.6 (2025-10-21)
### Features and enhancements
- **Go:** Update to 1.25.2 + golangci-lint v2.5.0 + golang.org/x/net v0.45.0 [#112161](https://github.com/grafana/grafana/pull/112161), [@macabu](https://github.com/macabu)
- **Go:** Update to 1.25.3 [#112364](https://github.com/grafana/grafana/pull/112364), [@macabu](https://github.com/macabu)
### Bug fixes
- **Auth:** Fix render user OAuth passthrough [#112096](https://github.com/grafana/grafana/pull/112096), [@mgyongyosi](https://github.com/mgyongyosi)
- **FlameGraph:** Ensure total is only counted once for recursive function calls [#111604](https://github.com/grafana/grafana/pull/111604), [@simonswine](https://github.com/simonswine)
- **LDAP Authentication:** Fix URL to propagate username context as parameter [#111847](https://github.com/grafana/grafana/pull/111847), [@bradleypettit](https://github.com/bradleypettit)
- **Plugins:** Dependencies do not inherit parent URL for preinstall [#111766](https://github.com/grafana/grafana/pull/111766), [@wbrowne](https://github.com/wbrowne)
<!-- 12.0.6 END -->
<!-- 11.6.7 START -->
# 11.6.7 (2025-10-21)
### Features and enhancements
- **Analytics:** Apply proper batching to Loki exports and add configurable settings (Enterprise)
- **Go:** Update to 1.25.2 + golangci-lint v2.5.0 + golang.org/x/net v0.45.0 [#112162](https://github.com/grafana/grafana/pull/112162), [@grambbledook](https://github.com/grambbledook)
- **Go:** Update to 1.25.3 [#112365](https://github.com/grafana/grafana/pull/112365), [@macabu](https://github.com/macabu)
### Bug fixes
- **Auth:** Fix render user OAuth passthrough [#112094](https://github.com/grafana/grafana/pull/112094), [@mgyongyosi](https://github.com/mgyongyosi)
- **LDAP Authentication:** Fix URL to propagate username context as parameter [#111846](https://github.com/grafana/grafana/pull/111846), [@bradleypettit](https://github.com/bradleypettit)
- **Plugins:** Dependencies do not inherit parent URL for preinstall [#111801](https://github.com/grafana/grafana/pull/111801), [@wbrowne](https://github.com/wbrowne)
- **URLParams:** Stringify true values as key=true always (fixes issues with variables with true value) [#112045](https://github.com/grafana/grafana/pull/112045), [@torkelo](https://github.com/torkelo)
<!-- 11.6.7 END -->
<!-- 11.5.10 START -->
# 11.5.10 (2025-10-21)
### Features and enhancements
- **Go:** Update to 1.25.2 + golangci-lint v2.5.0 + golang.org/x/net v0.45.0 [#112163](https://github.com/grafana/grafana/pull/112163), [@macabu](https://github.com/macabu)
- **Go:** Update to 1.25.3 [#112366](https://github.com/grafana/grafana/pull/112366), [@macabu](https://github.com/macabu)
### Bug fixes
- **Auth:** Fix render user OAuth passthrough [#112093](https://github.com/grafana/grafana/pull/112093), [@mgyongyosi](https://github.com/mgyongyosi)
- **LDAP Authentication:** Fix URL to propagate username context as parameter [#111845](https://github.com/grafana/grafana/pull/111845), [@bradleypettit](https://github.com/bradleypettit)
- **Plugins:** Dependencies do not inherit parent URL for preinstall [#111802](https://github.com/grafana/grafana/pull/111802), [@wbrowne](https://github.com/wbrowne)
<!-- 11.5.10 END -->
<!-- 12.2.0 START --> <!-- 12.2.0 START -->
# 12.2.0 (2025-09-23) # 12.2.0 (2025-09-23)
+33 -66
View File
@@ -2,84 +2,51 @@
Thank you for your interest in contributing to Grafana! We welcome all people who want to contribute in a healthy and constructive manner within our community. To help us create a safe and positive community experience for all, we require all participants to adhere to the [Code of Conduct](CODE_OF_CONDUCT.md). Thank you for your interest in contributing to Grafana! We welcome all people who want to contribute in a healthy and constructive manner within our community. To help us create a safe and positive community experience for all, we require all participants to adhere to the [Code of Conduct](CODE_OF_CONDUCT.md).
This document is a guide to help you through the process of contributing to Grafana. Be sure to check out the [Grafana Champions program](https://grafana.com/community/champions/?src=github&camp=community-cross-platform-engagement) as you start to contribute. It's designed to recognize and empower individuals who are actively contributing to the growth and success of the Grafana ecosystem. This document is a guide to help you through the process of contributing to Grafana. Be sure to check out the [Grafana Champions program](https://grafana.com/community/champions/?src=github&camp=community-cross-platform-engagement) as you start to contribute- its designed to recognize and empower individuals who are actively contributing to the growth and success of the Grafana ecosystem.
> **Help us improve!** We'd love to hear about your contributor experience. Take a moment to share your feedback in our [Open Source Contributor Experience Survey](https://gra.fan/ome). Your input helps us make contributing to Grafana better for everyone. Whether you're a new contributer or a seasoned veteran we hope these resources help you connect with the community:
Whether you're a new contributor or a seasoned veteran, we hope these resources help you connect with the community. Interact and be heard:
#### Interact and be heard - Forums: Do you have a problem, question, or curiosity? Visit our [forums](https://gra.fan/fromgithubtoforums) for a reservoir of knowledge- submit your own questions and answers!
- Meetups: Craving in-person connections without the long journeys? [Join your local Grafana & Friends meetup group](https://gra.fan/githubtomeetup)!
- **Forums:** Do you have a problem, question, or curiosity? Visit our [forums](https://gra.fan/fromgithubtoforums) for a reservoir of knowledge, submit your own questions and answers! - Community Slack: Eager for real-time connections with fellow users? Begin a conversation on [Slack](https://gra.fan/githubtoslack).
- **Meetups:** Craving in-person connections without the long journeys? [Join your local Grafana & Friends meetup group](https://gra.fan/githubtomeetup)! Learn:
- **Community Slack:** Eager for real-time connections with fellow users? Begin a conversation on [Slack](https://gra.fan/githubtoslack). - YouTube: From getting started to exploring newer projects like Pyroscope and Beyla, the [Grafana YouTube channel](https://gra.fan/githubtoyoutube) has what you need to get started!
- Meetups: Join a [group near you](https://gra.fan/githubtomeetup) to learn from local experts and ask questions in real time.
#### Learn Share your story:
- Meetups and blogs: Wed love to feature your OSS Grafana Labs use case or story at an upcoming Grafana & Friends meetup or on the Grafana blog! Submit your idea [here](https://gra.fan/githubtocca) and well connect with you on next steps if accepted.
- **YouTube:** From getting started to exploring newer projects like Pyroscope and Beyla, the [Grafana YouTube channel](https://gra.fan/githubtoyoutube) has what you need to get started!
- **Meetups:** Join a [group near you](https://gra.fan/githubtomeetup) to learn from local experts and ask questions in real time.
#### Make technical contributions
- You can make technical contributions with or without code. Scroll down to see how!
#### Share your story
- **Meetups and blogs:** Wed love to feature your OSS Grafana Labs use case or story at an upcoming Grafana & Friends meetup or on the Grafana blog! Submit your idea [here](https://gra.fan/githubtocca), and well connect with you on next steps if accepted.
## Choose the right channel
Use the right place to ask questions, report problems, and propose changes.
- **[GitHub issues](https://github.com/grafana/grafana/issues) and [pull requests](https://github.com/grafana/grafana/pulls)**: Use for reproducible bugs in core Grafana and maintained plugins, small and actionable feature requests, and code or docs changes via pull requests. Avoid general “how do I” questions. For security issues, follow the [security policy](https://github.com/grafana/grafana/security/policy).
- **Grafana community forums**: Use for questions, troubleshooting, best practices, plugin development Q&A, and early idea discussion. Forums create a searchable public knowledge base that helps others with the same problems and questions. Start here if you are unsure: [Grafana community forums](https://community.grafana.com/).
- **Grafana Community Slack**: Use for quick, time-sensitive chats and networking. Do not rely on Slack for complex troubleshooting or decisions. Share outcomes back to a forum topic or GitHub issue/PR to keep a public record: [Grafana Community Slack](https://slack.grafana.com).
- **Not sure where to start?** Start with a forum topic. Maintainers and community members will redirect you if a GitHub issue or pull request is more appropriate.
## Make technical contributions ## Make technical contributions
We welcome your technical contributions! You can contribute in several ways: We welcome your technical contributions! Here are some examples:
### Contribute Code to Grafana - Contribute to the Grafana codebase- check out these [help-wanted issues](<(https://github.com/grafana/grafana/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22)>)
- Develop community [plugins](https://grafana.com/developers/plugin-tools)
- Report [bugs](https://github.com/grafana/grafana/issues/new?template=0-bug-report.yaml)
- [Triage issues](https://github.com/grafana/grafana/blob/4414b92e93440cc9ed0f281989ee71dc16216a15/contribute/triage-issues.md)
- Report [security vulnerabilities](https://github.com/grafana/grafana/security/policy)
- Submit a [feature request](https://github.com/grafana/grafana/issues/new?template=1-feature_requests.md)
- Write [technical documentation](https://github.com/grafana/grafana/blob/4414b92e93440cc9ed0f281989ee71dc16216a15/contribute/documentation/README.md)
**What you will need:** **Please note:** We do not currently accept contributions for translations. Please do not submit pull requests translating grafana.json files - they will be rejected. We do accept contributions to mark up phrases for translation. See [Internationalization](contribute/internationalization.md).
- Follow our [developer guide](contribute/developer-guide.md) to set up your environment. ### Your first contribution
- Adhere to our [frontend](contribute/style-guides/frontend.md) and [backend](contribute/backend/style-guide.md) style guides.
- Write or update tests ([testing guide](contribute/style-guides/testing.md)).
**Step-by-step:** Unsure where to begin contributing to Grafana? Start by browsing issues labeled `beginner friendly` or `help wanted`.
1. Browse all [issues](https://github.com/grafana/grafana/issues) to find something to work on. You can also filter by [help wanted](https://github.com/grafana/grafana/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22). - [Beginner-friendly](https://github.com/grafana/grafana/issues?q=is%3Aopen+is%3Aissue+label%3A%22beginner+friendly%22) issues are generally straightforward to complete.
1. Prepare a clear, descriptive pull request ([how-to guide](contribute/create-pull-request.md)). - [Help wanted](https://github.com/grafana/grafana/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22) issues are problems we would like the community to help us with regardless of complexity.
1. Ensure you include and run the appropriate tests as part of your pull request.
1. Commit and push your changes. If you encounter merge conflicts, you may rebase your branch onto the main branch.
### Develop a Plugin If you're looking to make a code change, see how to set up your environment for [local development](contribute/developer-guide.md).
Grafana plugins let you extend the platform with new data sources, panels, and more. This is a great way to share your ideas and make a real impact on the Grafana ecosystem. When you're ready to contribute, it's time to [create a pull request](/contribute/create-pull-request.md).
**Step-by-step:** ### Develop a plugin
1. Read the [plugin development guide](https://grafana.com/developers/plugin-tools) to choose your plugin type and set up your environment. Developing a Grafana plugin is a fantastic way to share your unique ideas with the community, extend the platforms capabilities, and make a real impact on how people visualize and understand their data. Check out our guide to creating [plugins](https://grafana.com/developers/plugin-tools)
2. Scaffold your plugin using the recommended tools.
3. Develop and test your plugin locally.
4. Follow best practices for code style, testing, and documentation.
5. Publish your plugin or submit it for review as described in the guide.
### Contribute without code ### Report bugs
You can help even if you don't write code:
- Report a bug with the [bug report template](https://github.com/grafana/grafana/issues/new?template=0-bug-report.yaml) and include steps to reproduce.
- Submit a [feature request](https://github.com/grafana/grafana/issues/new?template=1-feature_requests.md) to propose improvements.
- Improve our docs with the [documentation contribution guide](https://github.com/grafana/grafana/blob/main/contribute/documentation).
- Help with [issue triage](https://github.com/grafana/grafana/blob/main/contribute/triage-issues.md) by reviewing, labeling, and clarifying open issues.
- Report security vulnerabilities following our [security policy](https://github.com/grafana/grafana/security/policy).
**Please note:** We do not currently accept contributions for translations. Please do not submit pull requests translating `grafana.json` files - they will be rejected. We do accept contributions to mark up phrases for translation. See [Internationalization](contribute/internationalization.md).
#### Reporting issues
Before submitting a new issue, try to make sure someone hasn't already reported the problem. Look through the [existing issues](https://github.com/grafana/grafana/issues) for similar issues. Before submitting a new issue, try to make sure someone hasn't already reported the problem. Look through the [existing issues](https://github.com/grafana/grafana/issues) for similar issues.
@@ -92,11 +59,11 @@ For data visualization issues:
- Query results from the inspect drawer (data tab & query inspector) - Query results from the inspect drawer (data tab & query inspector)
- Panel settings can be extracted in the panel inspect drawer JSON tab - Panel settings can be extracted in the panel inspect drawer JSON tab
For dashboard related issues: For a dashboard related issues:
- Dashboard JSON can be found in the dashboard settings JSON model view. You can [send the panel JSON model](https://grafana.com/docs/grafana/latest/troubleshooting/send-panel-to-grafana-support/) to Grafana Labs Technical Support and request help with troubleshooting your issue. - Dashboard JSON can be found in the dashboard settings JSON model view
For authentication and alerting, Grafana server logs are useful. For authentication and alerting Grafana server logs are useful.
### Triage issues ### Triage issues
@@ -108,7 +75,7 @@ Read more about the ways you can [Triage issues](/contribute/triage-issues.md).
If you believe you've found a security vulnerability, please read our [security policy](https://github.com/grafana/grafana/security/policy) for more details on reporting. If you believe you've found a security vulnerability, please read our [security policy](https://github.com/grafana/grafana/security/policy) for more details on reporting.
### Suggest features ### Suggest enhancements
If you have an idea of how to improve Grafana, submit a [feature request](https://github.com/grafana/grafana/issues/new?template=1-feature_requests.md). If you have an idea of how to improve Grafana, submit a [feature request](https://github.com/grafana/grafana/issues/new?template=1-feature_requests.md).
+1 -4
View File
@@ -17,7 +17,7 @@ ARG JS_SRC=js-builder
FROM alpine:3.22.2 AS alpine-base FROM alpine:3.22.2 AS alpine-base
FROM ubuntu:22.04 AS ubuntu-base FROM ubuntu:22.04 AS ubuntu-base
FROM golang:1.25.3-alpine AS go-builder-base FROM golang:1.25.3-alpine AS go-builder-base
FROM --platform=${JS_PLATFORM} node:24-alpine AS js-builder-base FROM --platform=${JS_PLATFORM} node:22-alpine AS js-builder-base
# Javascript build stage # Javascript build stage
FROM --platform=${JS_PLATFORM} ${JS_IMAGE} AS js-builder FROM --platform=${JS_PLATFORM} ${JS_IMAGE} AS js-builder
ARG JS_NODE_ENV=production ARG JS_NODE_ENV=production
@@ -95,14 +95,12 @@ COPY pkg/aggregator pkg/aggregator
COPY apps/playlist apps/playlist COPY apps/playlist apps/playlist
COPY apps/plugins apps/plugins COPY apps/plugins apps/plugins
COPY apps/shorturl apps/shorturl COPY apps/shorturl apps/shorturl
COPY apps/annotation apps/annotation
COPY apps/correlations apps/correlations COPY apps/correlations apps/correlations
COPY apps/preferences apps/preferences COPY apps/preferences apps/preferences
COPY apps/provisioning apps/provisioning COPY apps/provisioning apps/provisioning
COPY apps/secret apps/secret COPY apps/secret apps/secret
COPY apps/scope apps/scope COPY apps/scope apps/scope
COPY apps/investigations apps/investigations COPY apps/investigations apps/investigations
COPY apps/logsdrilldown apps/logsdrilldown
COPY apps/advisor apps/advisor COPY apps/advisor apps/advisor
COPY apps/dashboard apps/dashboard COPY apps/dashboard apps/dashboard
COPY apps/folder apps/folder COPY apps/folder apps/folder
@@ -115,7 +113,6 @@ COPY apps/alerting/notifications apps/alerting/notifications
COPY apps/alerting/rules apps/alerting/rules COPY apps/alerting/rules apps/alerting/rules
COPY pkg/codegen pkg/codegen COPY pkg/codegen pkg/codegen
COPY pkg/plugins/codegen pkg/plugins/codegen COPY pkg/plugins/codegen pkg/plugins/codegen
COPY apps/example apps/example
RUN go mod download RUN go mod download
+4 -4
View File
@@ -135,14 +135,14 @@ i18n-extract-enterprise:
@echo "Skipping i18n extract for Enterprise: not enabled" @echo "Skipping i18n extract for Enterprise: not enabled"
else else
i18n-extract-enterprise: i18n-extract-enterprise:
@echo "Extracting i18n strings for Enterprise" @echo "Extracting i18n strings for Enterprise"
cd public/locales/enterprise && yarn run i18next-cli extract --sync-primary yarn run i18next --config public/locales/i18next-parser-enterprise.config.cjs
endif endif
.PHONY: i18n-extract .PHONY: i18n-extract
i18n-extract: i18n-extract-enterprise i18n-extract: i18n-extract-enterprise
@echo "Extracting i18n strings for OSS" @echo "Extracting i18n strings for OSS"
yarn run i18next-cli extract --sync-primary yarn run i18next --config public/locales/i18next-parser.config.cjs
@echo "Extracting i18n strings for packages" @echo "Extracting i18n strings for packages"
yarn run packages:i18n-extract yarn run packages:i18n-extract
@echo "Extracting i18n strings for plugins" @echo "Extracting i18n strings for plugins"
@@ -178,7 +178,7 @@ gen-apps: do-gen-apps gofmt ## Generate code for Grafana App SDK apps and run go
@if [ -n "$$CODEGEN_VERIFY" ]; then \ @if [ -n "$$CODEGEN_VERIFY" ]; then \
echo "Verifying generated code is up to date..."; \ echo "Verifying generated code is up to date..."; \
if ! git diff --quiet; then \ if ! git diff --quiet; then \
echo "Error: Generated code is not up to date. Please run 'make gen-apps', 'make gen-cue', and 'make gen-jsonnet' to regenerate."; \ echo "Error: Generated apps code is not up to date. Please run 'make gen-apps' to regenerate."; \
git diff --name-only; \ git diff --name-only; \
exit 1; \ exit 1; \
fi; \ fi; \
+1 -2
View File
@@ -4,6 +4,7 @@
The open-source platform for monitoring and observability The open-source platform for monitoring and observability
[![License](https://img.shields.io/github/license/grafana/grafana)](LICENSE) [![License](https://img.shields.io/github/license/grafana/grafana)](LICENSE)
[![Drone](https://drone.grafana.net/api/badges/grafana/grafana/status.svg)](https://drone.grafana.net/grafana/grafana)
[![Go Report Card](https://goreportcard.com/badge/github.com/grafana/grafana)](https://goreportcard.com/report/github.com/grafana/grafana) [![Go Report Card](https://goreportcard.com/badge/github.com/grafana/grafana)](https://goreportcard.com/report/github.com/grafana/grafana)
Grafana allows you to query, visualize, alert on and understand your metrics no matter where they are stored. Create, explore, and share dashboards with your team and foster a data-driven culture: Grafana allows you to query, visualize, alert on and understand your metrics no matter where they are stored. Create, explore, and share dashboards with your team and foster a data-driven culture:
@@ -35,8 +36,6 @@ If you're interested in contributing to the Grafana project:
- Explore our [beginner-friendly issues](https://github.com/grafana/grafana/issues?q=is%3Aopen+is%3Aissue+label%3A%22beginner+friendly%22). - Explore our [beginner-friendly issues](https://github.com/grafana/grafana/issues?q=is%3Aopen+is%3Aissue+label%3A%22beginner+friendly%22).
- Look through our [style guide and Storybook](https://developers.grafana.com/ui/latest/index.html). - Look through our [style guide and Storybook](https://developers.grafana.com/ui/latest/index.html).
> Share your contributor experience in our [feedback survey](https://gra.fan/ome) to help us improve.
## Get involved ## Get involved
- Follow [@grafana on X (formerly Twitter)](https://x.com/grafana/). - Follow [@grafana on X (formerly Twitter)](https://x.com/grafana/).
+2 -31
View File
@@ -1,34 +1,5 @@
include ../sdk.mk include ../sdk.mk
.PHONY: etcd .PHONY: generate
etcd:
@docker run -d --name etcd --env ALLOW_NONE_AUTHENTICATION=yes -p 22379:2379 bitnamilegacy/etcd:latest
.PHONY: generate # Run Grafana App SDK code generation
generate: install-app-sdk update-app-sdk generate: install-app-sdk update-app-sdk
@$(APP_SDK_BIN) generate \ @$(APP_SDK_BIN) generate -g ./pkg/apis --grouping=group --postprocess --defencoding=none --useoldmanifestkinds
--source=./kinds/ \
--gogenpath=./pkg/apis \
--grouping=group \
--defencoding=none
.PHONY: run
run:
@go run ./pkg/standalone/server.go --etcd-servers=http://127.0.0.1:22379 --secure-port 7445
.PHONY: create-checks
create-checks:
@echo "Creating plugin check..."
@curl -k -X POST https://localhost:7445/apis/advisor.grafana.app/v0alpha1/namespaces/stacks-1/checks \
-H "Content-Type: application/json" \
-d '{"kind":"Check","apiVersion":"advisor.grafana.app/v0alpha1","spec":{"data":{}},"metadata":{"generateName":"check-","labels":{"advisor.grafana.app/type":"plugin"},"namespace":"stacks-1"},"status":{"report":{"count":0,"failures":[]}}}' \
&& echo "Plugin check created successfully"
@echo "Creating datasource check..."
@curl -k -X POST https://localhost:7445/apis/advisor.grafana.app/v0alpha1/namespaces/stacks-1/checks \
-H "Content-Type: application/json" \
-d '{"kind":"Check","apiVersion":"advisor.grafana.app/v0alpha1","spec":{"data":{}},"metadata":{"generateName":"check-","labels":{"advisor.grafana.app/type":"datasource"},"namespace":"stacks-1"},"status":{"report":{"count":0,"failures":[]}}}' \
&& echo "Datasource check created successfully"
delete-checks:
@curl -k -X DELETE https://localhost:7445/apis/advisor.grafana.app/v0alpha1/namespaces/stacks-1/checks \
&& echo "All checks deleted successfully"
-25
View File
@@ -152,28 +152,3 @@ Check [`security_config_step.go`](./pkg/app/checks/configchecks/security_config_
## Testing ## Testing
Create tests for your check and its steps to ensure they work as expected. Test both successful and failure scenarios. 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
```
+115 -154
View File
@@ -4,78 +4,55 @@ go 1.25.3
require ( require (
github.com/Masterminds/semver/v3 v3.4.0 github.com/Masterminds/semver/v3 v3.4.0
github.com/google/go-cmp v0.7.0
github.com/google/go-github/v70 v70.0.0 github.com/google/go-github/v70 v70.0.0
github.com/grafana/authlib/types v0.0.0-20250926065801-df98203cff37 github.com/grafana/authlib/types v0.0.0-20250710201142-9542f2f28d43
github.com/grafana/grafana v0.0.0-00010101000000-000000000000 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.40.2
github.com/grafana/grafana-app-sdk/logging v0.48.1 github.com/grafana/grafana-app-sdk/logging v0.40.2
github.com/grafana/grafana-plugin-sdk-go v0.281.0 github.com/grafana/grafana-plugin-sdk-go v0.278.0
github.com/grafana/grafana/pkg/apimachinery v0.0.0 github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250804150913-990f1c69ecc2
github.com/stretchr/testify v1.11.1 github.com/stretchr/testify v1.10.0
k8s.io/apimachinery v0.34.1 k8s.io/apimachinery v0.33.3
k8s.io/apiserver v0.34.1 k8s.io/apiserver v0.33.3
k8s.io/client-go v0.34.1 k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff
k8s.io/component-base v0.34.1
k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912
) )
// transitive dependencies that need replaced // transitive dependencies that need replaced
// TODO: stop depending on grafana core // TODO: stop depending on grafana core
replace github.com/grafana/grafana => ../.. replace github.com/grafana/grafana => ../..
replace github.com/grafana/grafana/apps/provisioning => ../provisioning replace github.com/prometheus/alertmanager => github.com/grafana/prometheus-alertmanager v0.25.1-0.20250620093340-be61a673dee6
replace github.com/grafana/grafana/pkg/apimachinery => ../../pkg/apimachinery
replace github.com/grafana/grafana/pkg/apiserver => ../../pkg/apiserver
replace github.com/grafana/grafana/apps/dashboard => ../dashboard
replace github.com/grafana/grafana/pkg/aggregator => ../../pkg/aggregator
replace github.com/grafana/grafana/apps/folder => ../folder
replace github.com/grafana/grafana/apps/secret => ../secret
replace github.com/grafana/grafana/apps/iam => ../iam
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 ( require (
cel.dev/expr v0.24.0 // indirect
cloud.google.com/go/compute/metadata v0.7.0 // indirect cloud.google.com/go/compute/metadata v0.7.0 // indirect
dario.cat/mergo v1.0.2 // indirect dario.cat/mergo v1.0.2 // indirect
filippo.io/edwards25519 v1.1.0 // indirect filippo.io/edwards25519 v1.1.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.19.1 // indirect github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.1 // indirect
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.12.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.10.1 // indirect
github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.2 // indirect github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.1 // indirect
github.com/Azure/go-ntlmssp v0.0.0-20220621081337-cb9428e4ac1e // indirect github.com/Azure/go-ntlmssp v0.0.0-20220621081337-cb9428e4ac1e // indirect
github.com/AzureAD/microsoft-authentication-library-for-go v1.5.0 // indirect github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2 // indirect
github.com/BurntSushi/toml v1.5.0 // indirect github.com/BurntSushi/toml v1.5.0 // indirect
github.com/Masterminds/goutils v1.1.1 // indirect github.com/Masterminds/goutils v1.1.1 // indirect
github.com/Masterminds/semver v1.5.0 // indirect github.com/Masterminds/semver v1.5.0 // indirect
github.com/Masterminds/sprig/v3 v3.3.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/ProtonMail/go-crypto v1.1.6 // indirect
github.com/VividCortex/mysqlerr v0.0.0-20170204212430-6c6b55f8796f // indirect github.com/VividCortex/mysqlerr v0.0.0-20170204212430-6c6b55f8796f // indirect
github.com/alecthomas/units v0.0.0-20240927000941-0f3dac36c52b // indirect github.com/alecthomas/units v0.0.0-20240927000941-0f3dac36c52b // indirect
github.com/antlr4-go/antlr/v4 v4.13.1 // indirect github.com/antlr4-go/antlr/v4 v4.13.1 // indirect
github.com/apache/arrow-go/v18 v18.4.1 // indirect github.com/apache/arrow-go/v18 v18.3.0 // indirect
github.com/armon/go-metrics v0.4.1 // indirect github.com/armon/go-metrics v0.4.1 // indirect
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
github.com/at-wat/mqtt-go v0.19.4 // indirect github.com/at-wat/mqtt-go v0.19.4 // indirect
github.com/aws/aws-sdk-go v1.55.7 // indirect github.com/aws/aws-sdk-go v1.55.7 // indirect
github.com/aws/aws-sdk-go-v2 v1.39.1 // indirect github.com/aws/aws-sdk-go-v2 v1.36.5 // indirect
github.com/aws/aws-sdk-go-v2/credentials v1.18.14 // indirect github.com/aws/aws-sdk-go-v2/credentials v1.17.70 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.8 // indirect github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.36 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.8 // indirect github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.36 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.1 // indirect github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.4 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.8 // indirect github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.17 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.38.5 // indirect github.com/aws/aws-sdk-go-v2/service/sts v1.34.0 // indirect
github.com/aws/smithy-go v1.23.1 // indirect github.com/aws/smithy-go v1.22.4 // indirect
github.com/barkimedes/go-deepcopy v0.0.0-20220514131651-17c30cfc62df // indirect github.com/barkimedes/go-deepcopy v0.0.0-20220514131651-17c30cfc62df // indirect
github.com/benbjohnson/clock v1.3.5 // indirect github.com/benbjohnson/clock v1.3.5 // indirect
github.com/beorn7/perks v1.0.1 // indirect github.com/beorn7/perks v1.0.1 // indirect
@@ -85,12 +62,13 @@ require (
github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874 // indirect github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874 // indirect
github.com/bwmarrin/snowflake v0.3.0 // indirect github.com/bwmarrin/snowflake v0.3.0 // indirect
github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect
github.com/cenkalti/backoff/v5 v5.0.3 // indirect github.com/cenkalti/backoff/v5 v5.0.2 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/cheekybits/genny v1.0.0 // indirect github.com/cheekybits/genny v1.0.0 // indirect
github.com/chromedp/cdproto v0.0.0-20250429231605-6ed5b53462d4 // indirect
github.com/cloudflare/circl v1.6.1 // 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/coreos/go-systemd/v22 v22.5.0 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.6 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/diegoholiveira/jsonlogic/v3 v3.7.4 // indirect github.com/diegoholiveira/jsonlogic/v3 v3.7.4 // indirect
@@ -100,110 +78,102 @@ require (
github.com/dolthub/go-icu-regex v0.0.0-20250327004329-6799764f2dad // indirect github.com/dolthub/go-icu-regex v0.0.0-20250327004329-6799764f2dad // indirect
github.com/dolthub/go-mysql-server v0.19.1-0.20250410182021-5632d67cd46e // indirect github.com/dolthub/go-mysql-server v0.19.1-0.20250410182021-5632d67cd46e // indirect
github.com/dolthub/jsonpath v0.0.2-0.20240227200619-19675ab05c71 // indirect github.com/dolthub/jsonpath v0.0.2-0.20240227200619-19675ab05c71 // indirect
github.com/dolthub/vitess v0.0.0-20250930230441-70c2c6a98e33 // indirect github.com/dolthub/vitess v0.0.0-20250410090211-143e6b272ad4 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect github.com/dustin/go-humanize v1.0.1 // indirect
github.com/emicklei/go-restful/v3 v3.13.0 // indirect github.com/elazarl/goproxy v1.7.2 // indirect
github.com/emicklei/go-restful/v3 v3.12.1 // indirect
github.com/evanphx/json-patch v5.6.0+incompatible // indirect
github.com/fatih/color v1.18.0 // indirect github.com/fatih/color v1.18.0 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/fsnotify/fsnotify v1.9.0 // indirect github.com/fxamacker/cbor/v2 v2.7.0 // indirect
github.com/fxamacker/cbor/v2 v2.9.0 // indirect
github.com/gchaincl/sqlhooks v1.3.0 // indirect github.com/gchaincl/sqlhooks v1.3.0 // indirect
github.com/getkin/kin-openapi v0.133.0 // indirect github.com/getkin/kin-openapi v0.132.0 // indirect
github.com/go-asn1-ber/asn1-ber v1.5.4 // indirect github.com/go-asn1-ber/asn1-ber v1.5.4 // indirect
github.com/go-jose/go-jose/v4 v4.1.2 // indirect github.com/go-jose/go-jose/v3 v3.0.4 // indirect
github.com/go-kit/log v0.2.1 // indirect github.com/go-kit/log v0.2.1 // indirect
github.com/go-ldap/ldap/v3 v3.4.4 // indirect github.com/go-ldap/ldap/v3 v3.4.4 // indirect
github.com/go-logfmt/logfmt v0.6.1 // indirect github.com/go-logfmt/logfmt v0.6.0 // indirect
github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/logr v1.4.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-openapi/analysis v0.24.0 // indirect github.com/go-openapi/analysis v0.23.0 // indirect
github.com/go-openapi/errors v0.22.3 // indirect github.com/go-openapi/errors v0.22.0 // indirect
github.com/go-openapi/jsonpointer v0.22.1 // indirect github.com/go-openapi/jsonpointer v0.21.0 // indirect
github.com/go-openapi/jsonreference v0.21.2 // indirect github.com/go-openapi/jsonreference v0.21.0 // indirect
github.com/go-openapi/loads v0.23.1 // indirect github.com/go-openapi/loads v0.22.0 // indirect
github.com/go-openapi/runtime v0.28.0 // indirect github.com/go-openapi/runtime v0.28.0 // indirect
github.com/go-openapi/spec v0.22.0 // indirect github.com/go-openapi/spec v0.21.0 // indirect
github.com/go-openapi/strfmt v0.24.0 // indirect github.com/go-openapi/strfmt v0.23.0 // indirect
github.com/go-openapi/swag v0.23.0 // indirect github.com/go-openapi/swag v0.23.0 // indirect
github.com/go-openapi/swag/conv v0.25.1 // indirect github.com/go-openapi/validate v0.24.0 // indirect
github.com/go-openapi/swag/fileutils v0.25.1 // indirect github.com/go-redis/redis/v8 v8.11.5 // indirect
github.com/go-openapi/swag/jsonname v0.25.1 // indirect
github.com/go-openapi/swag/jsonutils v0.25.1 // indirect
github.com/go-openapi/swag/loading v0.25.1 // indirect
github.com/go-openapi/swag/mangling v0.25.1 // indirect
github.com/go-openapi/swag/stringutils v0.25.1 // indirect
github.com/go-openapi/swag/typeutils v0.25.1 // indirect
github.com/go-openapi/swag/yamlutils v0.25.1 // indirect
github.com/go-openapi/validate v0.25.0 // indirect
github.com/go-sql-driver/mysql v1.9.3 // indirect github.com/go-sql-driver/mysql v1.9.3 // indirect
github.com/go-stack/stack v1.8.1 // indirect github.com/go-stack/stack v1.8.1 // indirect
github.com/go-viper/mapstructure/v2 v2.4.0 // indirect
github.com/gobwas/glob v0.2.3 // indirect github.com/gobwas/glob v0.2.3 // indirect
github.com/goccy/go-json v0.10.5 // indirect github.com/goccy/go-json v0.10.5 // indirect
github.com/gofrs/uuid v4.4.0+incompatible // indirect github.com/gofrs/uuid v4.4.0+incompatible // indirect
github.com/gogo/googleapis v1.4.1 // indirect github.com/gogo/googleapis v1.4.1 // indirect
github.com/gogo/protobuf v1.3.2 // indirect github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang-jwt/jwt/v4 v4.5.2 // indirect github.com/golang-jwt/jwt/v4 v4.5.2 // indirect
github.com/golang-jwt/jwt/v5 v5.3.0 // indirect github.com/golang-jwt/jwt/v5 v5.2.3 // indirect
github.com/golang-migrate/migrate/v4 v4.7.0 // indirect github.com/golang-migrate/migrate/v4 v4.7.0 // indirect
github.com/golang/mock v1.7.0-rc.1 // indirect
github.com/golang/protobuf v1.5.4 // indirect github.com/golang/protobuf v1.5.4 // indirect
github.com/google/btree v1.1.3 // 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/flatbuffers v25.2.10+incompatible // indirect
github.com/google/gnostic-models v0.7.0 // indirect github.com/google/gnostic-models v0.6.9 // indirect
github.com/google/go-cmp v0.7.0 // indirect
github.com/google/go-querystring v1.1.0 // indirect github.com/google/go-querystring v1.1.0 // indirect
github.com/google/uuid v1.6.0 // indirect github.com/google/uuid v1.6.0 // indirect
github.com/google/wire v0.7.0 // indirect github.com/google/wire v0.6.0 // indirect
github.com/grafana/alerting v0.0.0-20251009192429-9427c24835ae // indirect github.com/gorilla/mux v1.8.1 // indirect
github.com/grafana/authlib v0.0.0-20250930082137-a40e2c2b094f // indirect github.com/grafana/alerting v0.0.0-20250729175202-b4b881b7b263 // indirect
github.com/grafana/authlib v0.0.0-20250710201142-9542f2f28d43 // indirect
github.com/grafana/dataplane/sdata v0.0.9 // indirect github.com/grafana/dataplane/sdata v0.0.9 // indirect
github.com/grafana/dskit v0.0.0-20250908063411-6b6da59b5cc4 // indirect github.com/grafana/dskit v0.0.0-20250611075409-46f51e1ce914 // indirect
github.com/grafana/grafana-aws-sdk v1.3.0 // indirect github.com/grafana/grafana-aws-sdk v1.1.0 // indirect
github.com/grafana/grafana-azure-sdk-go/v2 v2.3.1 // indirect github.com/grafana/grafana-azure-sdk-go/v2 v2.2.0 // indirect
github.com/grafana/grafana/apps/plugins v0.0.0 // indirect github.com/grafana/grafana/apps/provisioning v0.0.0-20250804150913-990f1c69ecc2 // indirect
github.com/grafana/grafana/apps/provisioning v0.0.0 // indirect github.com/grafana/grafana/pkg/apiserver v0.0.0-20250804150913-990f1c69ecc2 // indirect
github.com/grafana/grafana/pkg/apiserver v0.0.0 // indirect
github.com/grafana/otel-profiling-go v0.5.1 // indirect github.com/grafana/otel-profiling-go v0.5.1 // indirect
github.com/grafana/pyroscope-go/godeltaprof v0.1.9 // indirect github.com/grafana/pyroscope-go/godeltaprof v0.1.8 // indirect
github.com/grafana/sqlds/v4 v4.2.7 // indirect github.com/grafana/sqlds/v4 v4.2.4 // indirect
github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.1.0 // 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-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.1 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-hclog v1.6.3 // indirect github.com/hashicorp/go-hclog v1.6.3 // indirect
github.com/hashicorp/go-immutable-radix v1.3.1 // indirect github.com/hashicorp/go-immutable-radix v1.3.1 // indirect
github.com/hashicorp/go-metrics v0.5.4 // indirect github.com/hashicorp/go-metrics v0.5.4 // indirect
github.com/hashicorp/go-msgpack/v2 v2.1.2 // indirect github.com/hashicorp/go-msgpack/v2 v2.1.2 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/hashicorp/go-plugin v1.7.0 // indirect github.com/hashicorp/go-plugin v1.6.3 // indirect
github.com/hashicorp/go-sockaddr v1.0.7 // indirect github.com/hashicorp/go-sockaddr v1.0.7 // indirect
github.com/hashicorp/golang-lru v1.0.2 // indirect github.com/hashicorp/golang-lru v1.0.2 // indirect
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
github.com/hashicorp/memberlist v0.5.2 // indirect github.com/hashicorp/memberlist v0.5.2 // indirect
github.com/hashicorp/yamux v0.1.2 // indirect github.com/hashicorp/yamux v0.1.1 // indirect
github.com/huandu/xstrings v1.5.0 // 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/jaegertracing/jaeger-idl v0.5.0 // indirect
github.com/jessevdk/go-flags v1.6.1 // indirect github.com/jessevdk/go-flags v1.6.1 // indirect
github.com/jmespath-community/go-jmespath v1.1.1 // indirect github.com/jmespath-community/go-jmespath v1.1.1 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/jmoiron/sqlx v1.4.0 // indirect github.com/jmoiron/sqlx v1.3.5 // indirect
github.com/josharian/intern v1.0.0 // indirect github.com/josharian/intern v1.0.0 // indirect
github.com/jpillora/backoff v1.0.0 // indirect github.com/jpillora/backoff v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect github.com/json-iterator/go v1.1.12 // indirect
github.com/jszwedko/go-datemath v0.1.1-0.20230526204004-640a500621d6 // indirect github.com/jszwedko/go-datemath v0.1.1-0.20230526204004-640a500621d6 // indirect
github.com/klauspost/compress v1.18.0 // indirect github.com/klauspost/compress v1.18.0 // indirect
github.com/klauspost/cpuid/v2 v2.3.0 // indirect github.com/klauspost/cpuid/v2 v2.2.10 // indirect
github.com/kylelemons/godebug v1.1.0 // indirect github.com/kylelemons/godebug v1.1.0 // indirect
github.com/lestrrat-go/strftime v1.0.4 // indirect github.com/lestrrat-go/strftime v1.0.4 // indirect
github.com/lib/pq v1.10.9 // indirect github.com/lib/pq v1.10.9 // indirect
github.com/magefile/mage v1.15.0 // indirect
github.com/mailru/easyjson v0.9.0 // indirect github.com/mailru/easyjson v0.9.0 // indirect
github.com/mattetti/filebuffer v1.0.1 // indirect github.com/mattetti/filebuffer v1.0.1 // indirect
github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.16 // indirect github.com/mattn/go-runewidth v0.0.16 // indirect
github.com/mattn/go-sqlite3 v1.14.32 // indirect github.com/mattn/go-sqlite3 v1.14.22 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
github.com/mdlayher/socket v0.4.1 // indirect github.com/mdlayher/socket v0.4.1 // indirect
github.com/mdlayher/vsock v1.2.1 // indirect github.com/mdlayher/vsock v1.2.1 // indirect
@@ -218,7 +188,7 @@ require (
github.com/mithrandie/go-text v1.6.0 // indirect github.com/mithrandie/go-text v1.6.0 // indirect
github.com/mithrandie/ternary v1.1.1 // indirect github.com/mithrandie/ternary v1.1.1 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // indirect github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // indirect
@@ -229,9 +199,9 @@ require (
github.com/oklog/run v1.1.0 // indirect github.com/oklog/run v1.1.0 // indirect
github.com/oklog/ulid v1.3.1 // indirect github.com/oklog/ulid v1.3.1 // indirect
github.com/olekukonko/tablewriter v0.0.5 // indirect github.com/olekukonko/tablewriter v0.0.5 // indirect
github.com/open-feature/go-sdk v1.16.0 // indirect github.com/open-feature/go-sdk v1.14.1 // indirect
github.com/open-feature/go-sdk-contrib/providers/go-feature-flag v0.2.6 // indirect github.com/open-feature/go-sdk-contrib/providers/go-feature-flag v0.2.3 // indirect
github.com/open-feature/go-sdk-contrib/providers/ofrep v0.1.6 // indirect github.com/open-feature/go-sdk-contrib/providers/ofrep v0.1.5 // indirect
github.com/patrickmn/go-cache v2.1.0+incompatible // indirect github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
github.com/perimeterx/marshmallow v1.1.5 // indirect github.com/perimeterx/marshmallow v1.1.5 // indirect
github.com/pierrec/lz4/v4 v4.1.22 // indirect github.com/pierrec/lz4/v4 v4.1.22 // indirect
@@ -239,43 +209,41 @@ require (
github.com/pkg/errors v0.9.1 // indirect github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/prometheus/alertmanager v0.28.0 // indirect github.com/prometheus/alertmanager v0.28.0 // indirect
github.com/prometheus/client_golang v1.23.2 // indirect github.com/prometheus/client_golang v1.22.0 // indirect
github.com/prometheus/client_model v0.6.2 // indirect github.com/prometheus/client_model v0.6.2 // indirect
github.com/prometheus/common v0.67.1 // indirect github.com/prometheus/common v0.65.0 // indirect
github.com/prometheus/common/sigv4 v0.1.0 // indirect github.com/prometheus/common/sigv4 v0.1.0 // indirect
github.com/prometheus/exporter-toolkit v0.14.0 // indirect github.com/prometheus/exporter-toolkit v0.14.0 // indirect
github.com/prometheus/procfs v0.16.1 // indirect github.com/prometheus/procfs v0.16.1 // indirect
github.com/puzpuzpuz/xsync/v2 v2.5.1 // indirect github.com/puzpuzpuz/xsync/v2 v2.5.1 // indirect
github.com/redis/go-redis/v9 v9.14.0 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/rivo/uniseg v0.4.7 // indirect github.com/rivo/uniseg v0.4.7 // indirect
github.com/rs/cors v1.11.1 // indirect github.com/rs/cors v1.11.1 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 // indirect github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 // indirect
github.com/shopspring/decimal v1.4.0 // indirect github.com/shopspring/decimal v1.4.0 // indirect
github.com/shurcooL/httpfs v0.0.0-20230704072500-f1e31cf0ba5c // indirect github.com/shurcooL/httpfs v0.0.0-20230704072500-f1e31cf0ba5c // indirect
github.com/shurcooL/vfsgen v0.0.0-20230704071429-0000e147ea92 // indirect github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect github.com/sirupsen/logrus v1.9.3 // indirect
github.com/spf13/cast v1.10.0 // indirect github.com/spf13/cast v1.7.1 // indirect
github.com/spf13/cobra v1.10.1 // indirect github.com/spf13/pflag v1.0.7 // 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/stretchr/objx v0.5.2 // indirect
github.com/tetratelabs/wazero v1.8.2 // indirect github.com/tetratelabs/wazero v1.8.2 // indirect
github.com/thomaspoignant/go-feature-flag v1.42.0 // indirect github.com/thomaspoignant/go-feature-flag v1.42.0 // indirect
github.com/tjhop/slog-gokit v0.1.5 // indirect github.com/tjhop/slog-gokit v0.1.3 // indirect
github.com/woodsbury/decimal128 v1.3.0 // indirect github.com/unknwon/bra v0.0.0-20200517080246-1e3013ecaff8 // indirect
github.com/unknwon/com v1.0.1 // indirect
github.com/unknwon/log v0.0.0-20200308114134-929b1006e34a // indirect
github.com/urfave/cli v1.22.16 // indirect
github.com/x448/float16 v0.8.4 // indirect github.com/x448/float16 v0.8.4 // indirect
github.com/zeebo/xxh3 v1.0.2 // indirect github.com/zeebo/xxh3 v1.0.2 // indirect
go.etcd.io/etcd/api/v3 v3.6.4 // indirect go.mongodb.org/mongo-driver v1.17.3 // 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/auto/sdk v1.1.0 // indirect
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.63.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.61.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0 // indirect
go.opentelemetry.io/contrib/propagators/jaeger v1.38.0 // indirect go.opentelemetry.io/contrib/propagators/jaeger v1.36.0 // indirect
go.opentelemetry.io/contrib/samplers/jaegerremote v0.32.0 // indirect go.opentelemetry.io/contrib/samplers/jaegerremote v0.30.0 // indirect
go.opentelemetry.io/otel v1.38.0 // indirect go.opentelemetry.io/otel v1.38.0 // indirect
go.opentelemetry.io/otel/exporters/jaeger v1.17.0 // indirect go.opentelemetry.io/otel/exporters/jaeger v1.17.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 // indirect
@@ -284,55 +252,48 @@ require (
go.opentelemetry.io/otel/metric v1.38.0 // indirect go.opentelemetry.io/otel/metric v1.38.0 // indirect
go.opentelemetry.io/otel/sdk v1.38.0 // indirect go.opentelemetry.io/otel/sdk v1.38.0 // indirect
go.opentelemetry.io/otel/trace v1.38.0 // indirect go.opentelemetry.io/otel/trace v1.38.0 // indirect
go.opentelemetry.io/proto/otlp v1.7.1 // indirect go.opentelemetry.io/proto/otlp v1.7.0 // indirect
go.uber.org/atomic v1.11.0 // indirect go.uber.org/atomic v1.11.0 // indirect
go.uber.org/mock v0.6.0 // indirect go.yaml.in/yaml/v2 v2.4.2 // indirect
go.uber.org/multierr v1.11.0 // indirect golang.org/x/crypto v0.40.0 // indirect
go.uber.org/zap v1.27.0 // indirect golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6 // indirect
go.yaml.in/yaml/v2 v2.4.3 // indirect golang.org/x/mod v0.26.0 // indirect
go.yaml.in/yaml/v3 v3.0.4 // indirect golang.org/x/net v0.42.0 // indirect
golang.org/x/crypto v0.43.0 // indirect golang.org/x/oauth2 v0.30.0 // indirect
golang.org/x/exp v0.0.0-20251002181428-27f1f14c8bb9 // indirect golang.org/x/sync v0.16.0 // indirect
golang.org/x/mod v0.29.0 // indirect golang.org/x/sys v0.34.0 // indirect
golang.org/x/net v0.46.0 // indirect golang.org/x/term v0.33.0 // indirect
golang.org/x/oauth2 v0.32.0 // indirect golang.org/x/text v0.27.0 // indirect
golang.org/x/sync v0.17.0 // indirect golang.org/x/time v0.11.0 // indirect
golang.org/x/sys v0.37.0 // indirect golang.org/x/tools v0.35.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/time v0.14.0 // indirect
golang.org/x/tools v0.38.0 // indirect
golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect
gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect
gonum.org/v1/gonum v0.16.0 // indirect gonum.org/v1/gonum v0.16.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20250908214217-97024824d090 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20251002232023-7c0ddcbb5797 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 // indirect
google.golang.org/grpc v1.76.0 // indirect google.golang.org/grpc v1.74.2 // indirect
google.golang.org/protobuf v1.36.10 // indirect google.golang.org/protobuf v1.36.6 // indirect
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect gopkg.in/fsnotify/fsnotify.v1 v1.4.7 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/mail.v2 v2.3.1 // 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/src-d/go-errors.v1 v1.0.0 // indirect
gopkg.in/telebot.v3 v3.3.8 // indirect gopkg.in/telebot.v3 v3.2.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/api v0.34.1 // indirect k8s.io/api v0.33.3 // indirect
k8s.io/apiextensions-apiserver v0.34.1 // indirect k8s.io/apiextensions-apiserver v0.33.3 // indirect
k8s.io/client-go v0.33.3 // indirect
k8s.io/component-base v0.33.3 // indirect
k8s.io/klog/v2 v2.130.1 // indirect k8s.io/klog/v2 v2.130.1 // indirect
k8s.io/kms v0.34.1 // indirect k8s.io/utils v0.0.0-20241210054802-24370beab758 // indirect
k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 // indirect modernc.org/libc v1.65.0 // indirect
modernc.org/libc v1.66.10 // indirect
modernc.org/mathutil v1.7.1 // indirect modernc.org/mathutil v1.7.1 // indirect
modernc.org/memory v1.11.0 // indirect modernc.org/memory v1.10.0 // indirect
modernc.org/sqlite v1.39.1 // indirect modernc.org/sqlite v1.38.0 // 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/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect
sigs.k8s.io/randfill v1.0.0 // indirect sigs.k8s.io/randfill v1.0.0 // indirect
sigs.k8s.io/structured-merge-diff/v6 v6.3.0 // indirect sigs.k8s.io/yaml v1.5.0 // indirect
sigs.k8s.io/yaml v1.6.0 // indirect xorm.io/builder v0.3.6 // indirect
xorm.io/builder v0.3.13 // indirect
) )
+409 -412
View File
File diff suppressed because it is too large Load Diff
+46 -38
View File
@@ -1,49 +1,57 @@
package advisor package advisor
checkv0alpha1: { check: {
kind: "Check" kind: "Check"
plural: "checks" pluralName: "Checks"
scope: "Namespaced" current: "v0alpha1"
validation: { validation: {
operations: [ operations: [
"CREATE", "CREATE",
"UPDATE", "UPDATE",
] ]
} }
schema: { versions: {
#Data: { "v0alpha1": {
// Generic data input that a check can receive codegen: {
data?: [string]: string ts: {enabled: false}
} go: {enabled: true}
#ErrorLink: { }
// URL to a page with more information about the error schema: {
url: string #Data: {
// Human readable error message // Generic data input that a check can receive
message: string data?: [string]: string
} }
#ReportFailure: { #ErrorLink: {
// Severity of the failure // URL to a page with more information about the error
severity: "high" | "low" url: string
// Step ID that the failure is associated with // Human readable error message
stepID: string message: string
// Human readable identifier of the item that failed }
item: string #ReportFailure: {
// ID of the item that failed // Severity of the failure
itemID: string severity: "high" | "low"
// Links to actions that can be taken to resolve the failure // Step ID that the failure is associated with
links: [...#ErrorLink] stepID: string
// More information about the failure, not meant to be displayed to the user. Used for LLM suggestions. // Human readable identifier of the item that failed
moreInfo?: string item: string
} // ID of the item that failed
#Report: { itemID: string
// Number of elements analyzed // Links to actions that can be taken to resolve the failure
count: int links: [...#ErrorLink]
// List of failures // More information about the failure, not meant to be displayed to the user. Used for LLM suggestions.
failures: [...#ReportFailure] moreInfo?: string
} }
spec: #Data #Report: {
status: { // Number of elements analyzed
report: #Report count: int
// List of failures
failures: [...#ReportFailure]
}
spec: #Data
status: {
report: #Report
}
}
} }
} }
} }
+22 -14
View File
@@ -1,19 +1,27 @@
package advisor package advisor
checktypev0alpha1: { checktype: {
kind: "CheckType" kind: "CheckType"
plural: "checktypes" pluralName: "CheckTypes"
scope: "Namespaced" current: "v0alpha1"
schema: { versions: {
#Step: { "v0alpha1": {
title: string codegen: {
description: string ts: {enabled: false}
stepID: string go: {enabled: true}
resolution: string }
} schema: {
spec: { #Step: {
name: string title: string
steps: [...#Step] description: string
stepID: string
resolution: string
}
spec: {
name: string
steps: [...#Step]
}
}
} }
} }
} }
+6 -14
View File
@@ -1,18 +1,10 @@
package advisor package advisor
manifest: { manifest: {
appName: "advisor" appName: "advisor"
groupOverride: "advisor.grafana.app" groupOverride: "advisor.grafana.app"
versions: { kinds: [
"v0alpha1": { check,
codegen: { checktype,
ts: {enabled: false} ]
go: {enabled: true}
}
kinds: [
checkv0alpha1,
checktypev0alpha1,
]
}
}
} }
@@ -1,99 +0,0 @@
package v0alpha1
import (
"context"
"github.com/grafana/grafana-app-sdk/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
type CheckClient struct {
client *resource.TypedClient[*Check, *CheckList]
}
func NewCheckClient(client resource.Client) *CheckClient {
return &CheckClient{
client: resource.NewTypedClient[*Check, *CheckList](client, CheckKind()),
}
}
func NewCheckClientFromGenerator(generator resource.ClientGenerator) (*CheckClient, error) {
c, err := generator.ClientFor(CheckKind())
if err != nil {
return nil, err
}
return NewCheckClient(c), nil
}
func (c *CheckClient) Get(ctx context.Context, identifier resource.Identifier) (*Check, error) {
return c.client.Get(ctx, identifier)
}
func (c *CheckClient) List(ctx context.Context, namespace string, opts resource.ListOptions) (*CheckList, error) {
return c.client.List(ctx, namespace, opts)
}
func (c *CheckClient) ListAll(ctx context.Context, namespace string, opts resource.ListOptions) (*CheckList, error) {
resp, err := c.client.List(ctx, namespace, resource.ListOptions{
ResourceVersion: opts.ResourceVersion,
Limit: opts.Limit,
LabelFilters: opts.LabelFilters,
FieldSelectors: opts.FieldSelectors,
})
if err != nil {
return nil, err
}
for resp.GetContinue() != "" {
page, err := c.client.List(ctx, namespace, resource.ListOptions{
Continue: resp.GetContinue(),
ResourceVersion: opts.ResourceVersion,
Limit: opts.Limit,
LabelFilters: opts.LabelFilters,
FieldSelectors: opts.FieldSelectors,
})
if err != nil {
return nil, err
}
resp.SetContinue(page.GetContinue())
resp.SetResourceVersion(page.GetResourceVersion())
resp.SetItems(append(resp.GetItems(), page.GetItems()...))
}
return resp, nil
}
func (c *CheckClient) Create(ctx context.Context, obj *Check, opts resource.CreateOptions) (*Check, error) {
// Make sure apiVersion and kind are set
obj.APIVersion = GroupVersion.Identifier()
obj.Kind = CheckKind().Kind()
return c.client.Create(ctx, obj, opts)
}
func (c *CheckClient) Update(ctx context.Context, obj *Check, opts resource.UpdateOptions) (*Check, error) {
return c.client.Update(ctx, obj, opts)
}
func (c *CheckClient) Patch(ctx context.Context, identifier resource.Identifier, req resource.PatchRequest, opts resource.PatchOptions) (*Check, error) {
return c.client.Patch(ctx, identifier, req, opts)
}
func (c *CheckClient) UpdateStatus(ctx context.Context, identifier resource.Identifier, newStatus CheckStatus, opts resource.UpdateOptions) (*Check, error) {
return c.client.Update(ctx, &Check{
TypeMeta: metav1.TypeMeta{
Kind: CheckKind().Kind(),
APIVersion: GroupVersion.Identifier(),
},
ObjectMeta: metav1.ObjectMeta{
ResourceVersion: opts.ResourceVersion,
Namespace: identifier.Namespace,
Name: identifier.Name,
},
Status: newStatus,
}, resource.UpdateOptions{
Subresource: "status",
ResourceVersion: opts.ResourceVersion,
})
}
func (c *CheckClient) Delete(ctx context.Context, identifier resource.Identifier, opts resource.DeleteOptions) error {
return c.client.Delete(ctx, identifier, opts)
}
@@ -1,99 +0,0 @@
package v0alpha1
import (
"context"
"github.com/grafana/grafana-app-sdk/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
type CheckTypeClient struct {
client *resource.TypedClient[*CheckType, *CheckTypeList]
}
func NewCheckTypeClient(client resource.Client) *CheckTypeClient {
return &CheckTypeClient{
client: resource.NewTypedClient[*CheckType, *CheckTypeList](client, CheckTypeKind()),
}
}
func NewCheckTypeClientFromGenerator(generator resource.ClientGenerator) (*CheckTypeClient, error) {
c, err := generator.ClientFor(CheckTypeKind())
if err != nil {
return nil, err
}
return NewCheckTypeClient(c), nil
}
func (c *CheckTypeClient) Get(ctx context.Context, identifier resource.Identifier) (*CheckType, error) {
return c.client.Get(ctx, identifier)
}
func (c *CheckTypeClient) List(ctx context.Context, namespace string, opts resource.ListOptions) (*CheckTypeList, error) {
return c.client.List(ctx, namespace, opts)
}
func (c *CheckTypeClient) ListAll(ctx context.Context, namespace string, opts resource.ListOptions) (*CheckTypeList, error) {
resp, err := c.client.List(ctx, namespace, resource.ListOptions{
ResourceVersion: opts.ResourceVersion,
Limit: opts.Limit,
LabelFilters: opts.LabelFilters,
FieldSelectors: opts.FieldSelectors,
})
if err != nil {
return nil, err
}
for resp.GetContinue() != "" {
page, err := c.client.List(ctx, namespace, resource.ListOptions{
Continue: resp.GetContinue(),
ResourceVersion: opts.ResourceVersion,
Limit: opts.Limit,
LabelFilters: opts.LabelFilters,
FieldSelectors: opts.FieldSelectors,
})
if err != nil {
return nil, err
}
resp.SetContinue(page.GetContinue())
resp.SetResourceVersion(page.GetResourceVersion())
resp.SetItems(append(resp.GetItems(), page.GetItems()...))
}
return resp, nil
}
func (c *CheckTypeClient) Create(ctx context.Context, obj *CheckType, opts resource.CreateOptions) (*CheckType, error) {
// Make sure apiVersion and kind are set
obj.APIVersion = GroupVersion.Identifier()
obj.Kind = CheckTypeKind().Kind()
return c.client.Create(ctx, obj, opts)
}
func (c *CheckTypeClient) Update(ctx context.Context, obj *CheckType, opts resource.UpdateOptions) (*CheckType, error) {
return c.client.Update(ctx, obj, opts)
}
func (c *CheckTypeClient) Patch(ctx context.Context, identifier resource.Identifier, req resource.PatchRequest, opts resource.PatchOptions) (*CheckType, error) {
return c.client.Patch(ctx, identifier, req, opts)
}
func (c *CheckTypeClient) UpdateStatus(ctx context.Context, identifier resource.Identifier, newStatus CheckTypeStatus, opts resource.UpdateOptions) (*CheckType, error) {
return c.client.Update(ctx, &CheckType{
TypeMeta: metav1.TypeMeta{
Kind: CheckTypeKind().Kind(),
APIVersion: GroupVersion.Identifier(),
},
ObjectMeta: metav1.ObjectMeta{
ResourceVersion: opts.ResourceVersion,
Namespace: identifier.Namespace,
Name: identifier.Name,
},
Status: newStatus,
}, resource.UpdateOptions{
Subresource: "status",
ResourceVersion: opts.ResourceVersion,
})
}
func (c *CheckTypeClient) Delete(ctx context.Context, identifier resource.Identifier, opts resource.DeleteOptions) error {
return c.client.Delete(ctx, identifier, opts)
}
+4 -53
View File
@@ -12,26 +12,22 @@ import (
"github.com/grafana/grafana-app-sdk/app" "github.com/grafana/grafana-app-sdk/app"
"github.com/grafana/grafana-app-sdk/resource" "github.com/grafana/grafana-app-sdk/resource"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/kube-openapi/pkg/spec3"
"k8s.io/kube-openapi/pkg/validation/spec"
v0alpha1 "github.com/grafana/grafana/apps/advisor/pkg/apis/advisor/v0alpha1" v0alpha1 "github.com/grafana/grafana/apps/advisor/pkg/apis/advisor/v0alpha1"
) )
var ( var (
rawSchemaCheckv0alpha1 = []byte(`{"Check":{"properties":{"spec":{"$ref":"#/components/schemas/spec"},"status":{"$ref":"#/components/schemas/status"}},"required":["spec"]},"ErrorLink":{"additionalProperties":false,"properties":{"message":{"description":"Human readable error message","type":"string"},"url":{"description":"URL to a page with more information about the error","type":"string"}},"required":["url","message"],"type":"object"},"OperatorState":{"additionalProperties":false,"properties":{"descriptiveState":{"description":"descriptiveState is an optional more descriptive state field which has no requirements on format","type":"string"},"details":{"additionalProperties":{"additionalProperties":{},"type":"object"},"description":"details contains any extra information that is operator-specific","type":"object"},"lastEvaluation":{"description":"lastEvaluation is the ResourceVersion last evaluated","type":"string"},"state":{"description":"state describes the state of the lastEvaluation.\nIt is limited to three possible states for machine evaluation.","enum":["success","in_progress","failed"],"type":"string"}},"required":["lastEvaluation","state"],"type":"object"},"Report":{"additionalProperties":false,"properties":{"count":{"description":"Number of elements analyzed","type":"integer"},"failures":{"description":"List of failures","items":{"$ref":"#/components/schemas/ReportFailure"},"type":"array"}},"required":["count","failures"],"type":"object"},"ReportFailure":{"additionalProperties":false,"properties":{"item":{"description":"Human readable identifier of the item that failed","type":"string"},"itemID":{"description":"ID of the item that failed","type":"string"},"links":{"description":"Links to actions that can be taken to resolve the failure","items":{"$ref":"#/components/schemas/ErrorLink"},"type":"array"},"moreInfo":{"description":"More information about the failure, not meant to be displayed to the user. Used for LLM suggestions.","type":"string"},"severity":{"description":"Severity of the failure","enum":["high","low"],"type":"string"},"stepID":{"description":"Step ID that the failure is associated with","type":"string"}},"required":["severity","stepID","item","itemID","links"],"type":"object"},"spec":{"additionalProperties":false,"properties":{"data":{"additionalProperties":{"type":"string"},"description":"Generic data input that a check can receive","type":"object"}},"type":"object"},"status":{"additionalProperties":false,"properties":{"additionalFields":{"additionalProperties":{"additionalProperties":{},"type":"object"},"description":"additionalFields is reserved for future use","type":"object"},"operatorStates":{"additionalProperties":{"$ref":"#/components/schemas/OperatorState"},"description":"operatorStates is a map of operator ID to operator state evaluations.\nAny operator which consumes this kind SHOULD add its state evaluation information to this field.","type":"object"},"report":{"$ref":"#/components/schemas/Report"}},"required":["report"],"type":"object"}}`) rawSchemaCheckv0alpha1 = []byte(`{"spec":{"properties":{"data":{"additionalProperties":{"type":"string"},"description":"Generic data input that a check can receive","type":"object"}},"type":"object"},"status":{"properties":{"additionalFields":{"description":"additionalFields is reserved for future use","type":"object","x-kubernetes-preserve-unknown-fields":true},"operatorStates":{"additionalProperties":{"properties":{"descriptiveState":{"description":"descriptiveState is an optional more descriptive state field which has no requirements on format","type":"string"},"details":{"description":"details contains any extra information that is operator-specific","type":"object","x-kubernetes-preserve-unknown-fields":true},"lastEvaluation":{"description":"lastEvaluation is the ResourceVersion last evaluated","type":"string"},"state":{"description":"state describes the state of the lastEvaluation.\nIt is limited to three possible states for machine evaluation.","enum":["success","in_progress","failed"],"type":"string"}},"required":["lastEvaluation","state"],"type":"object"},"description":"operatorStates is a map of operator ID to operator state evaluations.\nAny operator which consumes this kind SHOULD add its state evaluation information to this field.","type":"object"},"report":{"properties":{"count":{"description":"Number of elements analyzed","type":"integer"},"failures":{"description":"List of failures","items":{"properties":{"item":{"description":"Human readable identifier of the item that failed","type":"string"},"itemID":{"description":"ID of the item that failed","type":"string"},"links":{"description":"Links to actions that can be taken to resolve the failure","items":{"properties":{"message":{"description":"Human readable error message","type":"string"},"url":{"description":"URL to a page with more information about the error","type":"string"}},"required":["url","message"],"type":"object"},"type":"array"},"moreInfo":{"description":"More information about the failure, not meant to be displayed to the user. Used for LLM suggestions.","type":"string"},"severity":{"description":"Severity of the failure","enum":["high","low"],"type":"string"},"stepID":{"description":"Step ID that the failure is associated with","type":"string"}},"required":["severity","stepID","item","itemID","links"],"type":"object"},"type":"array"}},"required":["count","failures"],"type":"object"}},"required":["report"],"type":"object"}}`)
versionSchemaCheckv0alpha1 app.VersionSchema versionSchemaCheckv0alpha1 app.VersionSchema
_ = json.Unmarshal(rawSchemaCheckv0alpha1, &versionSchemaCheckv0alpha1) _ = json.Unmarshal(rawSchemaCheckv0alpha1, &versionSchemaCheckv0alpha1)
rawSchemaCheckTypev0alpha1 = []byte(`{"CheckType":{"properties":{"spec":{"$ref":"#/components/schemas/spec"},"status":{"$ref":"#/components/schemas/status"}},"required":["spec"]},"OperatorState":{"additionalProperties":false,"properties":{"descriptiveState":{"description":"descriptiveState is an optional more descriptive state field which has no requirements on format","type":"string"},"details":{"additionalProperties":{"additionalProperties":{},"type":"object"},"description":"details contains any extra information that is operator-specific","type":"object"},"lastEvaluation":{"description":"lastEvaluation is the ResourceVersion last evaluated","type":"string"},"state":{"description":"state describes the state of the lastEvaluation.\nIt is limited to three possible states for machine evaluation.","enum":["success","in_progress","failed"],"type":"string"}},"required":["lastEvaluation","state"],"type":"object"},"Step":{"additionalProperties":false,"properties":{"description":{"type":"string"},"resolution":{"type":"string"},"stepID":{"type":"string"},"title":{"type":"string"}},"required":["title","description","stepID","resolution"],"type":"object"},"spec":{"additionalProperties":false,"properties":{"name":{"type":"string"},"steps":{"items":{"$ref":"#/components/schemas/Step"},"type":"array"}},"required":["name","steps"],"type":"object"},"status":{"additionalProperties":false,"properties":{"additionalFields":{"additionalProperties":{"additionalProperties":{},"type":"object"},"description":"additionalFields is reserved for future use","type":"object"},"operatorStates":{"additionalProperties":{"$ref":"#/components/schemas/OperatorState"},"description":"operatorStates is a map of operator ID to operator state evaluations.\nAny operator which consumes this kind SHOULD add its state evaluation information to this field.","type":"object"}},"type":"object"}}`) rawSchemaCheckTypev0alpha1 = []byte(`{"spec":{"properties":{"name":{"type":"string"},"steps":{"items":{"properties":{"description":{"type":"string"},"resolution":{"type":"string"},"stepID":{"type":"string"},"title":{"type":"string"}},"required":["title","description","stepID","resolution"],"type":"object"},"type":"array"}},"required":["name","steps"],"type":"object"},"status":{"properties":{"additionalFields":{"description":"additionalFields is reserved for future use","type":"object","x-kubernetes-preserve-unknown-fields":true},"operatorStates":{"additionalProperties":{"properties":{"descriptiveState":{"description":"descriptiveState is an optional more descriptive state field which has no requirements on format","type":"string"},"details":{"description":"details contains any extra information that is operator-specific","type":"object","x-kubernetes-preserve-unknown-fields":true},"lastEvaluation":{"description":"lastEvaluation is the ResourceVersion last evaluated","type":"string"},"state":{"description":"state describes the state of the lastEvaluation.\nIt is limited to three possible states for machine evaluation.","enum":["success","in_progress","failed"],"type":"string"}},"required":["lastEvaluation","state"],"type":"object"},"description":"operatorStates is a map of operator ID to operator state evaluations.\nAny operator which consumes this kind SHOULD add its state evaluation information to this field.","type":"object"}},"type":"object"}}`)
versionSchemaCheckTypev0alpha1 app.VersionSchema versionSchemaCheckTypev0alpha1 app.VersionSchema
_ = json.Unmarshal(rawSchemaCheckTypev0alpha1, &versionSchemaCheckTypev0alpha1) _ = json.Unmarshal(rawSchemaCheckTypev0alpha1, &versionSchemaCheckTypev0alpha1)
) )
var appManifestData = app.ManifestData{ var appManifestData = app.ManifestData{
AppName: "advisor", AppName: "advisor",
Group: "advisor.grafana.app", Group: "advisor.grafana.app",
PreferredVersion: "v0alpha1",
Versions: []app.ManifestVersion{ Versions: []app.ManifestVersion{
{ {
Name: "v0alpha1", Name: "v0alpha1",
@@ -61,11 +57,6 @@ var appManifestData = app.ManifestData{
Schema: &versionSchemaCheckTypev0alpha1, Schema: &versionSchemaCheckTypev0alpha1,
}, },
}, },
Routes: app.ManifestVersionRoutes{
Namespaced: map[string]spec3.PathProps{},
Cluster: map[string]spec3.PathProps{},
Schemas: map[string]spec.Schema{},
},
}, },
}, },
} }
@@ -95,7 +86,6 @@ var customRouteToGoResponseType = map[string]any{}
// ManifestCustomRouteResponsesAssociator returns the associated response go type for a given kind, version, custom route path, and method, if one exists. // ManifestCustomRouteResponsesAssociator returns the associated response go type for a given kind, version, custom route path, and method, if one exists.
// kind may be empty for custom routes which are not kind subroutes. Leading slashes are removed from subroute paths. // kind may be empty for custom routes which are not kind subroutes. Leading slashes are removed from subroute paths.
// If there is no association for the provided kind, version, custom route path, and method, exists will return false. // If there is no association for the provided kind, version, custom route path, and method, exists will return false.
// Resource routes (those without a kind) should prefix their route with "<namespace>/" if the route is namespaced (otherwise the route is assumed to be cluster-scope)
func ManifestCustomRouteResponsesAssociator(kind, version, path, verb string) (goType any, exists bool) { func ManifestCustomRouteResponsesAssociator(kind, version, path, verb string) (goType any, exists bool) {
if len(path) > 0 && path[0] == '/' { if len(path) > 0 && path[0] == '/' {
path = path[1:] path = path[1:]
@@ -103,42 +93,3 @@ func ManifestCustomRouteResponsesAssociator(kind, version, path, verb string) (g
goType, exists = customRouteToGoResponseType[fmt.Sprintf("%s|%s|%s|%s", version, kind, path, strings.ToUpper(verb))] goType, exists = customRouteToGoResponseType[fmt.Sprintf("%s|%s|%s|%s", version, kind, path, strings.ToUpper(verb))]
return goType, exists return goType, exists
} }
var customRouteToGoParamsType = map[string]runtime.Object{}
func ManifestCustomRouteQueryAssociator(kind, version, path, verb string) (goType runtime.Object, exists bool) {
if len(path) > 0 && path[0] == '/' {
path = path[1:]
}
goType, exists = customRouteToGoParamsType[fmt.Sprintf("%s|%s|%s|%s", version, kind, path, strings.ToUpper(verb))]
return goType, exists
}
var customRouteToGoRequestBodyType = map[string]any{}
func ManifestCustomRouteRequestBodyAssociator(kind, version, path, verb string) (goType any, exists bool) {
if len(path) > 0 && path[0] == '/' {
path = path[1:]
}
goType, exists = customRouteToGoRequestBodyType[fmt.Sprintf("%s|%s|%s|%s", version, kind, path, strings.ToUpper(verb))]
return goType, exists
}
type GoTypeAssociator struct{}
func NewGoTypeAssociator() *GoTypeAssociator {
return &GoTypeAssociator{}
}
func (g *GoTypeAssociator) KindToGoType(kind, version string) (goType resource.Kind, exists bool) {
return ManifestGoTypeAssociator(kind, version)
}
func (g *GoTypeAssociator) CustomRouteReturnGoType(kind, version, path, verb string) (goType any, exists bool) {
return ManifestCustomRouteResponsesAssociator(kind, version, path, verb)
}
func (g *GoTypeAssociator) CustomRouteQueryGoType(kind, version, path, verb string) (goType runtime.Object, exists bool) {
return ManifestCustomRouteQueryAssociator(kind, version, path, verb)
}
func (g *GoTypeAssociator) CustomRouteRequestBodyGoType(kind, version, path, verb string) (goType any, exists bool) {
return ManifestCustomRouteRequestBodyAssociator(kind, version, path, verb)
}
+6 -6
View File
@@ -69,12 +69,12 @@ func New(cfg app.Config) (app.App, error) {
go func() { go func() {
logger := log.WithContext(ctx).With("check", check.ID()) logger := log.WithContext(ctx).With("check", check.ID())
logger.Debug("Processing check", "namespace", req.Object.GetNamespace()) logger.Debug("Processing check", "namespace", req.Object.GetNamespace())
orgID, err := getOrgIDFromNamespace(req.Object.GetNamespace()) requester, err := identity.GetRequester(ctx)
if err != nil { if err != nil {
logger.Error("Error getting org ID from namespace", "error", err) logger.Error("Error getting requester", "error", err)
return return
} }
ctx = identity.WithServiceIdentityContext(context.WithoutCancel(ctx), orgID) ctx = identity.WithServiceIdentityContext(context.WithoutCancel(ctx), requester.GetOrgID())
err = processCheck(ctx, logger, client, typesClient, req.Object, check) err = processCheck(ctx, logger, client, typesClient, req.Object, check)
if err != nil { if err != nil {
logger.Error("Error processing check", "error", err) logger.Error("Error processing check", "error", err)
@@ -85,12 +85,12 @@ func New(cfg app.Config) (app.App, error) {
go func() { go func() {
logger := log.WithContext(ctx).With("check", check.ID()) logger := log.WithContext(ctx).With("check", check.ID())
logger.Debug("Updating check", "namespace", req.Object.GetNamespace(), "name", req.Object.GetName()) logger.Debug("Updating check", "namespace", req.Object.GetNamespace(), "name", req.Object.GetName())
orgID, err := getOrgIDFromNamespace(req.Object.GetNamespace()) requester, err := identity.GetRequester(ctx)
if err != nil { if err != nil {
logger.Error("Error getting org ID from namespace", "error", err) logger.Error("Error getting requester", "error", err)
return return
} }
ctx = identity.WithServiceIdentityContext(context.WithoutCancel(ctx), orgID) ctx = identity.WithServiceIdentityContext(context.WithoutCancel(ctx), requester.GetOrgID())
err = processCheckRetry(ctx, logger, client, typesClient, req.Object, check) err = processCheckRetry(ctx, logger, client, typesClient, req.Object, check)
if err != nil { if err != nil {
logger.Error("Error processing check retry", "error", err) logger.Error("Error processing check retry", "error", err)
@@ -10,7 +10,6 @@ import (
"github.com/grafana/grafana/pkg/plugins" "github.com/grafana/grafana/pkg/plugins"
"github.com/grafana/grafana/pkg/plugins/repo" "github.com/grafana/grafana/pkg/plugins/repo"
"github.com/grafana/grafana/pkg/services/datasources" "github.com/grafana/grafana/pkg/services/datasources"
"github.com/grafana/grafana/pkg/services/org"
"github.com/grafana/grafana/pkg/services/pluginsintegration/managedplugins" "github.com/grafana/grafana/pkg/services/pluginsintegration/managedplugins"
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginchecker" "github.com/grafana/grafana/pkg/services/pluginsintegration/pluginchecker"
"github.com/grafana/grafana/pkg/services/pluginsintegration/plugincontext" "github.com/grafana/grafana/pkg/services/pluginsintegration/plugincontext"
@@ -92,5 +91,4 @@ type AdvisorAppConfig struct {
CheckRegistry CheckService CheckRegistry CheckService
PluginConfig map[string]string PluginConfig map[string]string
StackID string StackID string
OrgService org.Service
} }
@@ -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
}
@@ -3,8 +3,6 @@ package datasourcecheck
import ( import (
"context" "context"
"errors" "errors"
sysruntime "runtime"
"sync"
"github.com/grafana/grafana-plugin-sdk-go/backend" "github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana/apps/advisor/pkg/app/checks" "github.com/grafana/grafana/apps/advisor/pkg/app/checks"
@@ -20,47 +18,37 @@ const (
HealthCheckStepID = "health-check" HealthCheckStepID = "health-check"
UIDValidationStepID = "uid-validation" UIDValidationStepID = "uid-validation"
MissingPluginStepID = "missing-plugin" MissingPluginStepID = "missing-plugin"
PromDepAuthStepID = "prom-dep-auth"
) )
type check struct { type check struct {
DatasourceSvc datasources.DataSourceService DatasourceSvc datasources.DataSourceService
PluginStore pluginstore.Store PluginStore pluginstore.Store
PluginContextProvider PluginContextProvider PluginContextProvider pluginContextProvider
PluginClient plugins.Client PluginClient plugins.Client
PluginRepo repo.Service PluginRepo repo.Service
GrafanaVersion string GrafanaVersion string
pluginCanBeInstalledCache map[string]bool
pluginExistsCacheMu sync.RWMutex
} }
func New( func New(
datasourceSvc datasources.DataSourceService, datasourceSvc datasources.DataSourceService,
pluginStore pluginstore.Store, pluginStore pluginstore.Store,
pluginContextProvider PluginContextProvider, pluginContextProvider pluginContextProvider,
pluginClient plugins.Client, pluginClient plugins.Client,
pluginRepo repo.Service, pluginRepo repo.Service,
grafanaVersion string, grafanaVersion string,
) checks.Check { ) checks.Check {
return &check{ return &check{
DatasourceSvc: datasourceSvc, DatasourceSvc: datasourceSvc,
PluginStore: pluginStore, PluginStore: pluginStore,
PluginContextProvider: pluginContextProvider, PluginContextProvider: pluginContextProvider,
PluginClient: pluginClient, PluginClient: pluginClient,
PluginRepo: pluginRepo, PluginRepo: pluginRepo,
GrafanaVersion: grafanaVersion, GrafanaVersion: grafanaVersion,
pluginCanBeInstalledCache: make(map[string]bool),
} }
} }
func (c *check) Items(ctx context.Context) ([]any, error) { func (c *check) Items(ctx context.Context) ([]any, error) {
requester, err := identity.GetRequester(ctx) dss, err := c.DatasourceSvc.GetAllDataSources(ctx, &datasources.GetAllDataSourcesQuery{})
if err != nil {
return nil, err
}
dss, err := c.DatasourceSvc.GetDataSources(ctx, &datasources.GetDataSourcesQuery{
OrgID: requester.GetOrgID(),
})
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -99,7 +87,6 @@ func (c *check) Name() string {
} }
func (c *check) Init(ctx context.Context) error { func (c *check) Init(ctx context.Context) error {
c.pluginCanBeInstalledCache = make(map[string]bool)
return nil return nil
} }
@@ -115,59 +102,9 @@ func (c *check) Steps() []checks.Step {
PluginRepo: c.PluginRepo, PluginRepo: c.PluginRepo,
GrafanaVersion: c.GrafanaVersion, GrafanaVersion: c.GrafanaVersion,
}, },
&promDepAuthStep{
canBeInstalled: c.canBeInstalled,
},
} }
} }
// canBeInstalled checks if a plugin is already installed or if it's available in the plugin repository. type pluginContextProvider interface {
// Returns true if:
// - The plugin is NOT installed AND it IS available in the repository (can be installed)
// Returns false if:
// - The plugin is already installed, OR
// - The plugin is NOT available in the repository (nothing to install)
func (c *check) canBeInstalled(ctx context.Context, pluginType string) (bool, error) {
// Check cache first with read lock for performance
c.pluginExistsCacheMu.RLock()
if canBeInstalled, found := c.pluginCanBeInstalledCache[pluginType]; found {
c.pluginExistsCacheMu.RUnlock()
return canBeInstalled, nil
}
c.pluginExistsCacheMu.RUnlock()
// Cache miss - acquire write lock and check again (double-checked locking pattern)
c.pluginExistsCacheMu.Lock()
defer c.pluginExistsCacheMu.Unlock()
// Another goroutine may have populated the cache while we waited for the lock
if canBeInstalled, found := c.pluginCanBeInstalledCache[pluginType]; found {
return canBeInstalled, nil
}
// Check if plugin is already installed
if _, isInstalled := c.PluginStore.Plugin(ctx, pluginType); isInstalled {
c.pluginCanBeInstalledCache[pluginType] = false
return false, nil
}
// Plugin is not installed - check if it's available in the repository
availablePlugins, err := c.PluginRepo.GetPluginsInfo(ctx, repo.GetPluginsInfoOptions{
IncludeDeprecated: true,
Plugins: []string{pluginType},
}, repo.NewCompatOpts(c.GrafanaVersion, sysruntime.GOOS, sysruntime.GOARCH))
if err != nil {
// On error, assume plugin is installed/unavailable to avoid showing incorrect install links
return false, err
}
// Plugin is not installed but IS available - return false to show install link
// Plugin is not installed and NOT available in repo - return true (nothing to install)
isAvailableInRepo := len(availablePlugins) > 0
c.pluginCanBeInstalledCache[pluginType] = !isAvailableInRepo
return isAvailableInRepo, nil
}
type PluginContextProvider interface {
GetWithDataSource(ctx context.Context, pluginID string, user identity.Requester, ds *datasources.DataSource) (backend.PluginContext, error) GetWithDataSource(ctx context.Context, pluginID string, user identity.Requester, ds *datasources.DataSource) (backend.PluginContext, error)
} }
@@ -8,7 +8,6 @@ import (
"github.com/grafana/grafana-plugin-sdk-go/backend" "github.com/grafana/grafana-plugin-sdk-go/backend"
advisor "github.com/grafana/grafana/apps/advisor/pkg/apis/advisor/v0alpha1" advisor "github.com/grafana/grafana/apps/advisor/pkg/apis/advisor/v0alpha1"
"github.com/grafana/grafana/pkg/apimachinery/identity" "github.com/grafana/grafana/pkg/apimachinery/identity"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/plugins" "github.com/grafana/grafana/pkg/plugins"
"github.com/grafana/grafana/pkg/plugins/repo" "github.com/grafana/grafana/pkg/plugins/repo"
"github.com/grafana/grafana/pkg/services/datasources" "github.com/grafana/grafana/pkg/services/datasources"
@@ -231,101 +230,6 @@ func TestCheck_Run(t *testing.T) {
assert.Equal(t, MissingPluginStepID, failures[0].StepID) assert.Equal(t, MissingPluginStepID, failures[0].StepID)
assert.Len(t, failures[0].Links, 1) assert.Len(t, failures[0].Links, 1)
}) })
t.Run("should return failure when prometheus datasource uses SigV4 auth", func(t *testing.T) {
jsonData := simplejson.New()
jsonData.Set("sigV4Auth", true)
datasources := []*datasources.DataSource{
{UID: "valid-uid-1", Type: "prometheus", Name: "Prometheus", JsonData: jsonData},
}
mockDatasourceSvc := &MockDatasourceSvc{dss: datasources}
mockPluginContextProvider := &MockPluginContextProvider{pCtx: backend.PluginContext{}}
mockPluginClient := &MockPluginClient{res: &backend.CheckHealthResult{Status: backend.HealthStatusOk}}
mockPluginRepo := &MockPluginRepo{plugins: []repo.PluginInfo{
{ID: 1, Slug: "prometheus", Status: "active"},
{ID: 2, Slug: "grafana-amazonprometheus-datasource", Status: "active"},
}}
mockPluginStore := &MockPluginStore{exists: true}
check := &check{
DatasourceSvc: mockDatasourceSvc,
PluginContextProvider: mockPluginContextProvider,
PluginClient: mockPluginClient,
PluginRepo: mockPluginRepo,
PluginStore: mockPluginStore,
GrafanaVersion: "11.0.0",
}
failures, err := runChecks(check)
assert.NoError(t, err)
assert.Len(t, failures, 1)
assert.Equal(t, PromDepAuthStepID, failures[0].StepID)
assert.Contains(t, failures[0].Links, advisor.CheckErrorLink{
Message: "View SigV4 docs",
Url: "https://grafana.com/docs/grafana-cloud/connect-externally-hosted/data-sources/prometheus/configure/aws-authentication/",
})
})
t.Run("should return failure when prometheus datasource uses Azure auth", func(t *testing.T) {
jsonData := simplejson.New()
jsonData.Set("azureCredentials", map[string]interface{}{"authType": "msi"})
datasources := []*datasources.DataSource{
{UID: "valid-uid-1", Type: "prometheus", Name: "Prometheus", JsonData: jsonData},
}
mockDatasourceSvc := &MockDatasourceSvc{dss: datasources}
mockPluginContextProvider := &MockPluginContextProvider{pCtx: backend.PluginContext{}}
mockPluginClient := &MockPluginClient{res: &backend.CheckHealthResult{Status: backend.HealthStatusOk}}
mockPluginRepo := &MockPluginRepo{plugins: []repo.PluginInfo{
{ID: 1, Slug: "prometheus", Status: "active"},
{ID: 2, Slug: "grafana-azureprometheus-datasource", Status: "active"},
}}
mockPluginStore := &MockPluginStore{exists: true}
check := &check{
DatasourceSvc: mockDatasourceSvc,
PluginContextProvider: mockPluginContextProvider,
PluginClient: mockPluginClient,
PluginRepo: mockPluginRepo,
PluginStore: mockPluginStore,
GrafanaVersion: "11.0.0",
}
failures, err := runChecks(check)
assert.NoError(t, err)
assert.Len(t, failures, 1)
assert.Equal(t, PromDepAuthStepID, failures[0].StepID)
assert.Contains(t, failures[0].Links, advisor.CheckErrorLink{
Message: "View Azure auth docs",
Url: "https://grafana.com/docs/grafana-cloud/connect-externally-hosted/data-sources/prometheus/configure/azure-authentication/",
})
})
t.Run("should not return failure when prometheus datasource does not use deprecated auth", func(t *testing.T) {
jsonData := simplejson.New()
datasources := []*datasources.DataSource{
{UID: "valid-uid-1", Type: "prometheus", Name: "Prometheus", JsonData: jsonData},
}
mockDatasourceSvc := &MockDatasourceSvc{dss: datasources}
mockPluginContextProvider := &MockPluginContextProvider{pCtx: backend.PluginContext{}}
mockPluginClient := &MockPluginClient{res: &backend.CheckHealthResult{Status: backend.HealthStatusOk}}
mockPluginRepo := &MockPluginRepo{plugins: []repo.PluginInfo{
{ID: 1, Slug: "prometheus", Status: "active"},
}}
mockPluginStore := &MockPluginStore{exists: true}
check := &check{
DatasourceSvc: mockDatasourceSvc,
PluginContextProvider: mockPluginContextProvider,
PluginClient: mockPluginClient,
PluginRepo: mockPluginRepo,
PluginStore: mockPluginStore,
GrafanaVersion: "11.0.0",
}
failures, err := runChecks(check)
assert.NoError(t, err)
assert.Empty(t, failures)
})
} }
func TestCheck_Item(t *testing.T) { func TestCheck_Item(t *testing.T) {
@@ -347,7 +251,7 @@ type MockDatasourceSvc struct {
dss []*datasources.DataSource dss []*datasources.DataSource
} }
func (m *MockDatasourceSvc) GetDataSources(context.Context, *datasources.GetDataSourcesQuery) ([]*datasources.DataSource, error) { func (m *MockDatasourceSvc) GetAllDataSources(context.Context, *datasources.GetAllDataSourcesQuery) ([]*datasources.DataSource, error) {
return m.dss, nil return m.dss, nil
} }
@@ -15,7 +15,7 @@ import (
) )
type healthCheckStep struct { type healthCheckStep struct {
PluginContextProvider PluginContextProvider PluginContextProvider pluginContextProvider
PluginClient plugins.Client PluginClient plugins.Client
} }
@@ -1,147 +0,0 @@
package datasourcecheck
import (
"context"
"fmt"
"github.com/grafana/grafana-app-sdk/logging"
advisor "github.com/grafana/grafana/apps/advisor/pkg/apis/advisor/v0alpha1"
"github.com/grafana/grafana/apps/advisor/pkg/app/checks"
"github.com/grafana/grafana/pkg/services/datasources"
)
type promDepAuthStep struct {
canBeInstalled func(ctx context.Context, pluginType string) (bool, error)
}
func (s *promDepAuthStep) Title() string {
return "Prometheus deprecated authentication check"
}
func (s *promDepAuthStep) Description() string {
return "Check if Prometheus data sources are using deprecated authentication methods (Azure auth and SigV4)"
}
func (s *promDepAuthStep) Resolution() string {
return fmt.Sprintf("Enable the feature toggle for 'prometheusTypeMigration'. If this feature toggle is already enabled, make sure that 'Azure Monitor Managed Service for Prometheus' and/or 'Amazon Managed Service for Prometheus' plugins are installed. If the data source is provisioned, edit data source type in the provisioning file to use '%s' or '%s'.", datasources.DS_AMAZON_PROMETHEUS, datasources.DS_AZURE_PROMETHEUS)
}
func (s *promDepAuthStep) ID() string {
return PromDepAuthStepID
}
func (s *promDepAuthStep) Run(ctx context.Context, log logging.Logger, obj *advisor.CheckSpec, item any) ([]advisor.CheckReportFailure, error) {
dataSource, ok := item.(*datasources.DataSource)
if !ok {
return nil, fmt.Errorf("invalid item type %T", item)
}
if dataSource.Type != datasources.DS_PROMETHEUS {
return nil, nil
}
if dataSource.JsonData == nil {
return nil, nil
}
awsAuthLinks, err := s.checkUsingAWSAuth(ctx, dataSource)
if err != nil {
return nil, err
}
azureAuthLinks, err := s.checkUsingAzureAuth(ctx, dataSource)
if err != nil {
return nil, err
}
errorLinks := append(awsAuthLinks, azureAuthLinks...)
if len(errorLinks) == 0 {
return nil, nil
}
return []advisor.CheckReportFailure{checks.NewCheckReportFailureWithMoreInfo(
advisor.CheckReportFailureSeverityHigh,
s.ID(),
dataSource.Name,
dataSource.UID,
errorLinks,
fmt.Sprintf("Datasource %s (UID: %s) is of type %s but it's using a deprecated authentication method so it should be migrated", dataSource.Name, dataSource.UID, dataSource.Type),
)}, nil
}
func (s *promDepAuthStep) checkUsingAWSAuth(ctx context.Context, dataSource *datasources.DataSource) ([]advisor.CheckErrorLink, error) {
var errorLinks []advisor.CheckErrorLink
if sigV4Auth, found := dataSource.JsonData.CheckGet("sigV4Auth"); found {
if enabled, err := sigV4Auth.Bool(); err != nil || !enabled {
// Disabled or not a valid boolean
return nil, nil
}
readOnlyLink := checkReadOnly(dataSource)
if readOnlyLink != nil {
errorLinks = append(errorLinks, *readOnlyLink)
}
errorLinks = append(errorLinks,
advisor.CheckErrorLink{
Message: "View SigV4 docs",
Url: "https://grafana.com/docs/grafana-cloud/connect-externally-hosted/data-sources/prometheus/configure/aws-authentication/",
})
pluginLink := s.linkDataSource(ctx, datasources.DS_AMAZON_PROMETHEUS, "Amazon Managed Service for Prometheus")
if pluginLink != nil {
errorLinks = append(errorLinks, *pluginLink)
}
}
return errorLinks, nil
}
func (s *promDepAuthStep) checkUsingAzureAuth(ctx context.Context, dataSource *datasources.DataSource) ([]advisor.CheckErrorLink, error) {
var errorLinks []advisor.CheckErrorLink
if azureAuth, found := dataSource.JsonData.CheckGet("azureCredentials"); found {
if _, err := azureAuth.Value(); err != nil {
// azureAuth does not have a value
return nil, nil
}
readOnlyLink := checkReadOnly(dataSource)
if readOnlyLink != nil {
errorLinks = append(errorLinks, *readOnlyLink)
}
errorLinks = append(errorLinks,
advisor.CheckErrorLink{
Message: "View Azure auth docs",
Url: "https://grafana.com/docs/grafana-cloud/connect-externally-hosted/data-sources/prometheus/configure/azure-authentication/",
})
pluginLink := s.linkDataSource(ctx, datasources.DS_AZURE_PROMETHEUS, "Azure Monitor Managed Service for Prometheus")
if pluginLink != nil {
errorLinks = append(errorLinks, *pluginLink)
}
}
return errorLinks, nil
}
func checkReadOnly(dataSource *datasources.DataSource) *advisor.CheckErrorLink {
if readOnly, found := dataSource.JsonData.CheckGet("readonly"); found {
if enabled, err := readOnly.Bool(); err != nil || !enabled {
// Disabled or not a valid boolean
return nil
}
return &advisor.CheckErrorLink{
Message: "Change provisioning file",
Url: "https://grafana.com/docs/grafana/latest/administration/provisioning/#data-sources",
}
}
return nil
}
func (s *promDepAuthStep) linkDataSource(ctx context.Context, pluginType string, pluginName string) *advisor.CheckErrorLink {
canBeInstalled, err := s.canBeInstalled(ctx, pluginType)
if err != nil {
return nil
}
if canBeInstalled {
// Plugin is available in the repo
return &advisor.CheckErrorLink{
Message: fmt.Sprintf("Install %s", pluginName),
Url: fmt.Sprintf("/plugins/%s", pluginType),
}
}
return nil
}
+9 -20
View File
@@ -9,7 +9,7 @@ import (
"github.com/grafana/authlib/types" "github.com/grafana/authlib/types"
"github.com/grafana/grafana-app-sdk/resource" "github.com/grafana/grafana-app-sdk/resource"
advisor "github.com/grafana/grafana/apps/advisor/pkg/apis/advisor/v0alpha1" advisor "github.com/grafana/grafana/apps/advisor/pkg/apis/advisor/v0alpha1"
"github.com/grafana/grafana/pkg/services/org" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
) )
const ( const (
@@ -57,26 +57,15 @@ func NewCheckReportFailureWithMoreInfo(
} }
} }
func GetNamespaces(ctx context.Context, stackID string, orgService org.Service) ([]string, error) { func GetNamespace(stackID string) (string, error) {
var namespaces []string if stackID == "" {
if stackID != "" { return metav1.NamespaceDefault, nil
// Single namespace for cloud stack
stackId, err := strconv.ParseInt(stackID, 10, 64)
if err != nil {
return nil, fmt.Errorf("invalid stack id: %s", stackID)
}
namespaces = []string{types.CloudNamespaceFormatter(stackId)}
} else {
// Multiple namespaces for each org
orgs, err := orgService.Search(ctx, &org.SearchOrgsQuery{})
if err != nil {
return nil, fmt.Errorf("failed to fetch orgs: %w", err)
}
for _, o := range orgs {
namespaces = append(namespaces, types.OrgNamespaceFormatter(o.ID))
}
} }
return namespaces, nil stackId, err := strconv.ParseInt(stackID, 10, 64)
if err != nil {
return "", fmt.Errorf("invalid stack id: %s", stackID)
}
return types.CloudNamespaceFormatter(stackId), nil
} }
func GetStatusAnnotation(obj resource.Object) string { func GetStatusAnnotation(obj resource.Object) string {
+10 -40
View File
@@ -1,61 +1,40 @@
package checks package checks
import ( import (
"context"
"testing" "testing"
"github.com/grafana/grafana/pkg/services/org"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
) )
func TestGetNamespaces(t *testing.T) { func TestGetNamespace(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
stackID string input string
orgs []string expected string
expected []string
expectedErr string expectedErr string
}{ }{
{ {
name: "empty stack ID", name: "empty stack ID",
stackID: "", input: "",
orgs: []string{"default"}, expected: metav1.NamespaceDefault,
expected: []string{metav1.NamespaceDefault},
}, },
{ {
name: "valid stack ID", name: "valid stack ID",
stackID: "1234567890", input: "1234567890",
orgs: []string{"default"}, expected: "stacks-1234567890",
expected: []string{"stacks-1234567890"},
}, },
{ {
name: "invalid stack ID", name: "invalid stack ID",
stackID: "invalid", input: "invalid",
orgs: []string{"default"}, expected: "",
expected: nil,
expectedErr: "invalid stack id: invalid", expectedErr: "invalid stack id: invalid",
}, },
{
name: "multiple orgs and no stack ID",
stackID: "",
orgs: []string{"default", "org-2"},
expected: []string{"default", "org-2"},
},
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
fakeOrgService := &mockOrgService{ result, err := GetNamespace(tt.input)
SearchFunc: func(ctx context.Context, query *org.SearchOrgsQuery) ([]*org.OrgDTO, error) {
orgs := make([]*org.OrgDTO, len(tt.orgs))
for i, o := range tt.orgs {
orgs[i] = &org.OrgDTO{ID: int64(i + 1), Name: o}
}
return orgs, nil
},
}
result, err := GetNamespaces(context.Background(), tt.stackID, fakeOrgService)
if tt.expectedErr != "" { if tt.expectedErr != "" {
assert.EqualError(t, err, tt.expectedErr) assert.EqualError(t, err, tt.expectedErr)
} else { } else {
@@ -65,12 +44,3 @@ func TestGetNamespaces(t *testing.T) {
}) })
} }
} }
type mockOrgService struct {
org.Service
SearchFunc func(ctx context.Context, query *org.SearchOrgsQuery) ([]*org.OrgDTO, error)
}
func (m *mockOrgService) Search(ctx context.Context, query *org.SearchOrgsQuery) ([]*org.OrgDTO, error) {
return m.SearchFunc(ctx, query)
}
@@ -16,7 +16,6 @@ import (
advisorv0alpha1 "github.com/grafana/grafana/apps/advisor/pkg/apis/advisor/v0alpha1" advisorv0alpha1 "github.com/grafana/grafana/apps/advisor/pkg/apis/advisor/v0alpha1"
"github.com/grafana/grafana/apps/advisor/pkg/app/checkregistry" "github.com/grafana/grafana/apps/advisor/pkg/app/checkregistry"
"github.com/grafana/grafana/apps/advisor/pkg/app/checks" "github.com/grafana/grafana/apps/advisor/pkg/app/checks"
"github.com/grafana/grafana/pkg/services/org"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
) )
@@ -24,23 +23,21 @@ const defaultEvaluationInterval = 7 * 24 * time.Hour // 7 days
const defaultMaxHistory = 10 const defaultMaxHistory = 10
var ( var (
waitInterval = 5 * time.Second waitInterval = 5 * time.Second
waitMaxRetries = 3 waitMaxRetries = 3
evalIntervalRandomVariation = 1 * time.Hour
) )
// Runner is a "runnable" app used to be able to expose and API endpoint // Runner is a "runnable" app used to be able to expose and API endpoint
// with the existing checks types. This does not need to be a CRUD resource, but it is // with the existing checks types. This does not need to be a CRUD resource, but it is
// the only way existing at the moment to expose the check types. // the only way existing at the moment to expose the check types.
type Runner struct { type Runner struct {
checkRegistry checkregistry.CheckService checkRegistry checkregistry.CheckService
checksClient resource.Client client resource.Client
typesClient resource.Client typesClient resource.Client
defaultEvalInterval time.Duration evaluationInterval time.Duration
maxHistory int maxHistory int
log logging.Logger namespace string
orgService org.Service log logging.Logger
stackID string
} }
// NewRunner creates a new Runner. // NewRunner creates a new Runner.
@@ -51,7 +48,6 @@ func New(cfg app.Config, log logging.Logger) (app.Runnable, error) {
return nil, fmt.Errorf("invalid config type") return nil, fmt.Errorf("invalid config type")
} }
checkRegistry := specificConfig.CheckRegistry checkRegistry := specificConfig.CheckRegistry
orgService := specificConfig.OrgService
evalInterval, err := getEvaluationInterval(specificConfig.PluginConfig) evalInterval, err := getEvaluationInterval(specificConfig.PluginConfig)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -60,6 +56,10 @@ func New(cfg app.Config, log logging.Logger) (app.Runnable, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
namespace, err := checks.GetNamespace(specificConfig.StackID)
if err != nil {
return nil, err
}
// Prepare storage client // Prepare storage client
clientGenerator := k8s.NewClientRegistry(cfg.KubeConfig, k8s.ClientConfig{}) clientGenerator := k8s.NewClientRegistry(cfg.KubeConfig, k8s.ClientConfig{})
@@ -73,14 +73,13 @@ func New(cfg app.Config, log logging.Logger) (app.Runnable, error) {
} }
return &Runner{ return &Runner{
checkRegistry: checkRegistry, checkRegistry: checkRegistry,
checksClient: client, client: client,
typesClient: typesClient, typesClient: typesClient,
defaultEvalInterval: evalInterval, evaluationInterval: evalInterval,
maxHistory: maxHistory, maxHistory: maxHistory,
log: log.With("runner", "advisor.checkscheduler"), namespace: namespace,
orgService: orgService, log: log.With("runner", "advisor.checkscheduler"),
stackID: specificConfig.StackID,
}, nil }, nil
} }
@@ -89,91 +88,58 @@ func (r *Runner) Run(ctx context.Context) error {
// We still need the context to eventually be cancelled to exit this function // 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 // but we don't want the requests to fail because of it
ctxWithoutCancel := context.WithoutCancel(ctx) ctxWithoutCancel := context.WithoutCancel(ctx)
lastCreated, err := r.checkLastCreated(ctxWithoutCancel, logger)
// Determine namespaces based on StackID or OrgID
namespaces, err := checks.GetNamespaces(ctxWithoutCancel, r.stackID, r.orgService)
if err != nil {
return fmt.Errorf("failed to get namespaces: %w", err)
}
logger.Debug("Scheduling checks", "namespaces", len(namespaces))
// Get the last created time for this specific namespace
lastCreatedMap, err := r.checkLastCreated(ctx, logger, namespaces)
if err != nil { if err != nil {
logger.Error("Error getting last check creation time", "error", err) logger.Error("Error getting last check creation time", "error", err)
return err // Wait for interval to create the next scheduled check
} lastCreated = time.Now()
} else {
// If there are checks already created, run an initial cleanup // do an initial creation if necessary
for _, namespace := range namespaces { if lastCreated.IsZero() {
logger = logger.With("namespace", namespace) err = r.createChecks(ctxWithoutCancel, logger)
lastCreated := lastCreatedMap[namespace] if err != nil {
logger.Error("Error creating new check reports", "error", err)
if !lastCreated.IsZero() { } else {
err = r.cleanupChecks(ctx, logger, namespace) lastCreated = time.Now()
}
} else {
// Run an initial cleanup to remove old checks
err = r.cleanupChecks(ctxWithoutCancel, logger)
if err != nil { if err != nil {
logger.Error("Error cleaning up old check reports", "error", err) logger.Error("Error cleaning up old check reports", "error", err)
return err
}
err = r.markUnprocessedChecks(ctx, logger, namespace)
if err != nil {
logger.Error("Error marking unprocessed checks", "error", err)
return err
} }
} }
} }
nextEvalTime := r.getNextEvalTime(r.defaultEvalInterval, lastCreatedMap) nextSendInterval := getNextSendInterval(lastCreated, r.evaluationInterval)
ticker := time.NewTicker(nextEvalTime) ticker := time.NewTicker(nextSendInterval)
defer ticker.Stop() defer ticker.Stop()
for { for {
select { select {
case <-ticker.C: case <-ticker.C:
// Get the current last created time for this namespace err = r.createChecks(ctxWithoutCancel, logger)
lastCreatedMap, err := r.checkLastCreated(ctx, logger, namespaces)
if err != nil { if err != nil {
logger.Error("Error getting last check creation time", "error", err) logger.Error("Error creating new check reports", "error", err)
return err
} }
for _, namespace := range namespaces { err = r.cleanupChecks(ctxWithoutCancel, logger)
logger = logger.With("namespace", namespace) if err != nil {
lastCreated := lastCreatedMap[namespace] logger.Error("Error cleaning up old check reports", "error", err)
// If there are checks already created and they are older than the evaluation interval
// then we can automatically create more
if !lastCreated.IsZero() && lastCreated.Before(time.Now().Add(-r.defaultEvalInterval)) {
err = r.createChecks(ctx, logger, namespace)
if err != nil {
logger.Error("Error creating new check reports", "error", err)
return err
}
// Clean up old checks to avoid going over the limit
err = r.cleanupChecks(ctx, logger, namespace)
if err != nil {
logger.Error("Error cleaning up old check reports", "error", err)
return err
}
// Update the last created time with the new created checks
lastCreatedMap[namespace] = time.Now()
}
} }
// Reset the ticker to the next send interval if nextSendInterval != r.evaluationInterval {
nextEvalTime = r.getNextEvalTime(r.defaultEvalInterval, lastCreatedMap) nextSendInterval = r.evaluationInterval
ticker.Reset(nextEvalTime) }
ticker.Reset(nextSendInterval)
case <-ctx.Done(): case <-ctx.Done():
return ctx.Err() return ctx.Err()
} }
} }
} }
func (r *Runner) listChecks(ctx context.Context, logger logging.Logger, namespace string) ([]resource.Object, error) { func (r *Runner) listChecks(ctx context.Context, logger logging.Logger) ([]resource.Object, error) {
list, err := r.checksClient.List(ctx, namespace, resource.ListOptions{ list, err := r.client.List(ctx, r.namespace, resource.ListOptions{
Limit: 1000, // Avoid pagination for normal uses cases, which is a costly operation Limit: 1000, // Avoid pagination for normal uses cases, which is a costly operation
}) })
if err != nil { if err != nil {
@@ -183,7 +149,7 @@ func (r *Runner) listChecks(ctx context.Context, logger logging.Logger, namespac
checks := list.GetItems() checks := list.GetItems()
for list.GetContinue() != "" { for list.GetContinue() != "" {
logger.Debug("List has continue token, listing next page", "continue", list.GetContinue()) logger.Debug("List has continue token, listing next page", "continue", list.GetContinue())
list, err = r.checksClient.List(ctx, namespace, resource.ListOptions{Continue: list.GetContinue(), Limit: 1000}) list, err = r.client.List(ctx, r.namespace, resource.ListOptions{Continue: list.GetContinue(), Limit: 1000})
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -192,48 +158,38 @@ func (r *Runner) listChecks(ctx context.Context, logger logging.Logger, namespac
return checks, nil return checks, nil
} }
// checkLastCreated returns the creation time of the last check created for a specific namespace. // checkLastCreated returns the creation time of the last check created
// This assumes that the checks are created in batches so a batch will have a similar creation time. // regardless of its ID. This assumes that the checks are created in batches
// so a batch will have a similar creation time.
// In case it finds an unprocessed check from a previous run, it will set it to error. // In case it finds an unprocessed check from a previous run, it will set it to error.
func (r *Runner) checkLastCreated(ctx context.Context, log logging.Logger, namespaces []string) (map[string]time.Time, error) { func (r *Runner) checkLastCreated(ctx context.Context, log logging.Logger) (time.Time, error) {
lastCreated := map[string]time.Time{} checkList, err := r.listChecks(ctx, log)
for _, namespace := range namespaces { if err != nil {
checkList, err := r.listChecks(ctx, log, namespace) return time.Time{}, err
if err != nil { }
return nil, err lastCreated := time.Time{}
for _, item := range checkList {
itemCreated := item.GetCreationTimestamp().Time
if itemCreated.After(lastCreated) {
lastCreated = itemCreated
} }
for _, item := range checkList {
itemCreated := item.GetCreationTimestamp().Time // If the check is unprocessed, set it to error
if itemCreated.After(lastCreated[namespace]) { if checks.GetStatusAnnotation(item) == "" {
lastCreated[namespace] = itemCreated log.Info("Check is unprocessed, marking as error", "check", item.GetStaticMetadata().Identifier())
err := checks.SetStatusAnnotation(ctx, r.client, item, checks.StatusAnnotationError)
if err != nil {
log.Error("Error setting check status to error", "error", err)
} }
} }
} }
return lastCreated, nil return lastCreated, nil
} }
func (r *Runner) markUnprocessedChecks(ctx context.Context, log logging.Logger, namespace string) error {
checkList, err := r.listChecks(ctx, log, namespace)
if err != nil {
return err
}
for _, item := range checkList {
if checks.GetStatusAnnotation(item) == "" {
log.Info("Check is unprocessed, marking as error", "check", item.GetStaticMetadata().Identifier())
err := checks.SetStatusAnnotation(ctx, r.checksClient, item, checks.StatusAnnotationError)
if err != nil {
log.Error("Error setting check status to error", "error", err)
return err
}
}
}
return nil
}
// createChecks creates a new check for each check type in the registry. // createChecks creates a new check for each check type in the registry.
func (r *Runner) createChecks(ctx context.Context, logger logging.Logger, namespace string) error { func (r *Runner) createChecks(ctx context.Context, logger logging.Logger) error {
// List existing CheckType objects // List existing CheckType objects
list, err := r.typesClient.List(ctx, namespace, resource.ListOptions{}) list, err := r.typesClient.List(ctx, r.namespace, resource.ListOptions{})
if err != nil { if err != nil {
return fmt.Errorf("error listing check types: %w", err) return fmt.Errorf("error listing check types: %w", err)
} }
@@ -243,7 +199,7 @@ func (r *Runner) createChecks(ctx context.Context, logger logging.Logger, namesp
for !allChecksRegistered && retryCount < waitMaxRetries { for !allChecksRegistered && retryCount < waitMaxRetries {
logger.Info("Waiting for all check types to be registered", "retryCount", retryCount, "waitInterval", waitInterval) logger.Info("Waiting for all check types to be registered", "retryCount", retryCount, "waitInterval", waitInterval)
time.Sleep(waitInterval) time.Sleep(waitInterval)
list, err = r.typesClient.List(ctx, namespace, resource.ListOptions{}) list, err = r.typesClient.List(ctx, r.namespace, resource.ListOptions{})
if err != nil { if err != nil {
return fmt.Errorf("error listing check types: %w", err) return fmt.Errorf("error listing check types: %w", err)
} }
@@ -261,7 +217,7 @@ func (r *Runner) createChecks(ctx context.Context, logger logging.Logger, namesp
obj := &advisorv0alpha1.Check{ obj := &advisorv0alpha1.Check{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
GenerateName: "check-", GenerateName: "check-",
Namespace: namespace, Namespace: r.namespace,
Labels: map[string]string{ Labels: map[string]string{
checks.TypeLabel: checkType.Spec.Name, checks.TypeLabel: checkType.Spec.Name,
}, },
@@ -269,7 +225,7 @@ func (r *Runner) createChecks(ctx context.Context, logger logging.Logger, namesp
Spec: advisorv0alpha1.CheckSpec{}, Spec: advisorv0alpha1.CheckSpec{},
} }
id := obj.GetStaticMetadata().Identifier() id := obj.GetStaticMetadata().Identifier()
_, err := r.checksClient.Create(ctx, id, obj, resource.CreateOptions{}) _, err := r.client.Create(ctx, id, obj, resource.CreateOptions{})
if err != nil { if err != nil {
return fmt.Errorf("error creating check: %w", err) return fmt.Errorf("error creating check: %w", err)
} }
@@ -278,13 +234,13 @@ func (r *Runner) createChecks(ctx context.Context, logger logging.Logger, namesp
} }
// cleanupChecks deletes the olders checks if the number of checks exceeds the limit. // cleanupChecks deletes the olders checks if the number of checks exceeds the limit.
func (r *Runner) cleanupChecks(ctx context.Context, logger logging.Logger, namespace string) error { func (r *Runner) cleanupChecks(ctx context.Context, logger logging.Logger) error {
checkList, err := r.listChecks(ctx, logger, namespace) checkList, err := r.listChecks(ctx, logger)
if err != nil { if err != nil {
return err return err
} }
logger.Debug("Cleaning up checks", "namespace", namespace, "numChecks", len(checkList)) logger.Debug("Cleaning up checks", "numChecks", len(checkList))
// organize checks by type // organize checks by type
checksByType := map[string][]resource.Object{} checksByType := map[string][]resource.Object{}
@@ -312,7 +268,7 @@ func (r *Runner) cleanupChecks(ctx context.Context, logger logging.Logger, names
for i := 0; i < len(checks)-r.maxHistory; i++ { for i := 0; i < len(checks)-r.maxHistory; i++ {
check := checks[i] check := checks[i]
id := check.GetStaticMetadata().Identifier() id := check.GetStaticMetadata().Identifier()
err := r.checksClient.Delete(ctx, id, resource.DeleteOptions{}) err := r.client.Delete(ctx, id, resource.DeleteOptions{})
if err != nil { if err != nil {
return fmt.Errorf("error deleting check: %w", err) return fmt.Errorf("error deleting check: %w", err)
} }
@@ -337,28 +293,15 @@ func getEvaluationInterval(pluginConfig map[string]string) (time.Duration, error
return evaluationInterval, nil return evaluationInterval, nil
} }
func (r *Runner) getNextEvalTime(defaultEvaluationInterval time.Duration, lastCreated map[string]time.Time) time.Duration { func getNextSendInterval(lastCreated time.Time, evaluationInterval time.Duration) time.Duration {
nextEvalTime := defaultEvaluationInterval nextSendInterval := time.Until(lastCreated.Add(evaluationInterval))
// Add random variation of one hour
// Get the oldest last created time randomVariation := time.Duration(rand.Int63n(time.Hour.Nanoseconds()))
baseTime := time.Now() nextSendInterval += randomVariation
for _, lastNamespacedCreated := range lastCreated { if nextSendInterval < time.Minute {
if !lastNamespacedCreated.IsZero() && lastNamespacedCreated.Before(baseTime) { nextSendInterval = 1 * time.Minute
baseTime = lastNamespacedCreated
}
} }
return nextSendInterval
// Calculate the next evaluation time and add random variation
nextEvalTime = time.Until(baseTime.Add(nextEvalTime))
randomVariation := time.Duration(rand.Int63n(evalIntervalRandomVariation.Nanoseconds()))
nextEvalTime += randomVariation
// Ensure we always return a positive duration to avoid ticker panics
if nextEvalTime <= 0 {
nextEvalTime = 1 * time.Millisecond
}
return nextEvalTime
} }
func getMaxHistory(pluginConfig map[string]string) (int, error) { func getMaxHistory(pluginConfig map[string]string) (int, error) {
@@ -4,50 +4,26 @@ import (
"context" "context"
"errors" "errors"
"fmt" "fmt"
"math/rand/v2"
"testing" "testing"
"time" "time"
"github.com/grafana/grafana-app-sdk/logging" "github.com/grafana/grafana-app-sdk/logging"
"github.com/grafana/grafana-app-sdk/resource" "github.com/grafana/grafana-app-sdk/resource"
advisorv0alpha1 "github.com/grafana/grafana/apps/advisor/pkg/apis/advisor/v0alpha1" advisorv0alpha1 "github.com/grafana/grafana/apps/advisor/pkg/apis/advisor/v0alpha1"
"github.com/grafana/grafana/apps/advisor/pkg/app/checkregistry"
"github.com/grafana/grafana/apps/advisor/pkg/app/checks" "github.com/grafana/grafana/apps/advisor/pkg/app/checks"
"github.com/grafana/grafana/pkg/services/org"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
) )
func init() {
waitInterval = 1 * time.Millisecond
evalIntervalRandomVariation = 1 * time.Millisecond
}
// TestRunner_Run tests the main Run function with various scenarios
func TestRunner_Run(t *testing.T) { func TestRunner_Run(t *testing.T) {
t.Run("handles context cancellation gracefully", func(t *testing.T) { t.Run("does not crash when error on list", func(t *testing.T) {
runner := createTestRunner(&MockClient{}, &MockClient{})
ctx, cancel := context.WithCancel(context.Background())
cancel() // Cancel immediately
err := runner.Run(ctx)
assert.ErrorAs(t, err, &context.Canceled)
})
t.Run("handles timeout gracefully", func(t *testing.T) {
runner := createTestRunner(&MockClient{}, &MockClient{})
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Millisecond)
defer cancel()
err := runner.Run(ctx)
assert.ErrorAs(t, err, &context.DeadlineExceeded)
})
t.Run("handles check list error gracefully", func(t *testing.T) {
mockClient := &MockClient{ mockClient := &MockClient{
listFunc: func(ctx context.Context, namespace string, options resource.ListOptions) (resource.ListObject, error) { listFunc: func(ctx context.Context, namespace string, options resource.ListOptions) (resource.ListObject, error) {
return nil, errors.New("list checks error") return nil, errors.New("list error")
},
createFunc: func(ctx context.Context, id resource.Identifier, obj resource.Object, opts resource.CreateOptions) (resource.Object, error) {
return &advisorv0alpha1.Check{}, nil
}, },
} }
@@ -57,289 +33,352 @@ func TestRunner_Run(t *testing.T) {
}, },
} }
runner := createTestRunner(mockClient, mockTypesClient) runner := &Runner{
err := runner.Run(context.Background()) client: mockClient,
assert.ErrorContains(t, err, "list checks error") typesClient: mockTypesClient,
log: &logging.NoOpLogger{},
evaluationInterval: 1 * time.Hour,
}
ctx, cancel := context.WithCancel(context.Background())
cancel()
err := runner.Run(ctx)
assert.ErrorAs(t, err, &context.Canceled)
}) })
} }
// TestRunner_Run_CheckCreation tests check creation scenarios func TestRunner_checkLastCreated_ErrorOnList(t *testing.T) {
func TestRunner_Run_CheckCreation(t *testing.T) { mockClient := &MockClient{
t.Run("does not create checks on first run when no previous checks exist", func(t *testing.T) { listFunc: func(ctx context.Context, namespace string, options resource.ListOptions) (resource.ListObject, error) {
checksCreated := []string{} return nil, errors.New("list error")
},
}
mockClient := &MockClient{ runner := &Runner{
listFunc: func(ctx context.Context, namespace string, options resource.ListOptions) (resource.ListObject, error) { client: mockClient,
// Return empty list - no previous checks log: &logging.NoOpLogger{},
return &advisorv0alpha1.CheckList{Items: []advisorv0alpha1.Check{}}, nil }
},
createFunc: func(ctx context.Context, id resource.Identifier, obj resource.Object, opts resource.CreateOptions) (resource.Object, error) {
checksCreated = append(checksCreated, id.Name)
return obj, nil
},
}
mockTypesClient := &MockClient{ lastCreated, err := runner.checkLastCreated(context.Background(), &logging.NoOpLogger{})
listFunc: func(ctx context.Context, namespace string, options resource.ListOptions) (resource.ListObject, error) { assert.Error(t, err)
return &advisorv0alpha1.CheckTypeList{ assert.True(t, lastCreated.IsZero())
Items: []advisorv0alpha1.CheckType{ }
{
ObjectMeta: metav1.ObjectMeta{ func TestRunner_checkLastCreated_UnprocessedCheck(t *testing.T) {
Name: "test-check", patchOperation := resource.PatchOperation{}
}, identifier := resource.Identifier{}
Spec: advisorv0alpha1.CheckTypeSpec{
Name: "test-check", mockClient := &MockClient{
}, listFunc: func(ctx context.Context, namespace string, options resource.ListOptions) (resource.ListObject, error) {
return &advisorv0alpha1.CheckList{
Items: []advisorv0alpha1.Check{
{
ObjectMeta: metav1.ObjectMeta{
Name: "check-1",
}, },
}, },
}, nil },
}, }, nil
} },
patchFunc: func(ctx context.Context, id resource.Identifier, patch resource.PatchRequest, options resource.PatchOptions, into resource.Object) error {
patchOperation = patch.Operations[0]
identifier = id
return nil
},
}
// Create a mock check service with one check to match the check type runner := &Runner{
mockCheckService := &MockCheckService{checks: []checks.Check{&mockCheck{id: "test-check"}}} client: mockClient,
runner := createTestRunnerWithRegistry(mockClient, mockTypesClient, mockCheckService) log: &logging.NoOpLogger{},
}
err := runAndTimeout(runner) lastCreated, err := runner.checkLastCreated(context.Background(), &logging.NoOpLogger{})
assert.ErrorAs(t, err, &context.DeadlineExceeded) assert.NoError(t, err)
// Should not create checks on first run when no previous checks exist assert.True(t, lastCreated.IsZero())
assert.Empty(t, checksCreated, "Should not create checks on first run when no previous checks exist") assert.Equal(t, "check-1", identifier.Name)
}) assert.Equal(t, "/metadata/annotations", patchOperation.Path)
expectedAnnotations := map[string]string{
checks.StatusAnnotation: "error",
}
assert.Equal(t, expectedAnnotations, patchOperation.Value)
}
t.Run("creates checks when evaluation interval has passed", func(t *testing.T) { func TestRunner_checkLastCreated_PaginatedResponse(t *testing.T) {
checksCreated := []string{} // Create checks with different creation times
past := time.Now().Add(-1 * time.Hour)
now := time.Now()
mockClient := &MockClient{ mockClient := &MockClient{
listFunc: func(ctx context.Context, namespace string, options resource.ListOptions) (resource.ListObject, error) { listFunc: func(ctx context.Context, namespace string, options resource.ListOptions) (resource.ListObject, error) {
// Return a check that was created long ago (past the evaluation interval) if options.Continue == "" {
// First page - return oldest and middle checks with continue token
return &advisorv0alpha1.CheckList{ return &advisorv0alpha1.CheckList{
ListMeta: metav1.ListMeta{
Continue: "continue-token-123",
},
Items: []advisorv0alpha1.Check{ Items: []advisorv0alpha1.Check{
{ {
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: "old-check", Name: "check-1",
CreationTimestamp: metav1.NewTime(time.Now().Add(-15 * 24 * time.Hour)), // 15 days ago CreationTimestamp: metav1.NewTime(past),
Annotations: map[string]string{ Annotations: map[string]string{
checks.StatusAnnotation: checks.StatusAnnotationProcessed, checks.StatusAnnotation: "completed",
},
},
},
{
ObjectMeta: metav1.ObjectMeta{
Name: "check-2",
CreationTimestamp: metav1.NewTime(past),
Annotations: map[string]string{
checks.StatusAnnotation: "completed",
}, },
}, },
}, },
}, },
}, nil }, nil
}, }
createFunc: func(ctx context.Context, id resource.Identifier, obj resource.Object, opts resource.CreateOptions) (resource.Object, error) { // Second page - verify continue token is passed and return newest check
checksCreated = append(checksCreated, id.Name) assert.Equal(t, "continue-token-123", options.Continue)
return obj, nil return &advisorv0alpha1.CheckList{
}, Items: []advisorv0alpha1.Check{
} {
ObjectMeta: metav1.ObjectMeta{
mockTypesClient := &MockClient{ Name: "check-3",
listFunc: func(ctx context.Context, namespace string, options resource.ListOptions) (resource.ListObject, error) { CreationTimestamp: metav1.NewTime(now),
return &advisorv0alpha1.CheckTypeList{ Annotations: map[string]string{
Items: []advisorv0alpha1.CheckType{ checks.StatusAnnotation: "completed",
{
ObjectMeta: metav1.ObjectMeta{
Name: "test-check",
},
Spec: advisorv0alpha1.CheckTypeSpec{
Name: "test-check",
}, },
}, },
}, },
}, nil },
}, }, nil
} },
// Create a mock check service with one check to match the check type
mockCheckService := &MockCheckService{checks: []checks.Check{&mockCheck{id: "test-check"}}}
runner := createTestRunnerWithRegistry(mockClient, mockTypesClient, mockCheckService)
err := runAndTimeout(runner)
assert.ErrorAs(t, err, &context.DeadlineExceeded)
// Should create checks when the evaluation interval has passed
assert.Greater(t, len(checksCreated), 0, "Should create checks when evaluation interval has passed")
})
}
// TestRunner_Run_CheckCleanup tests check cleanup scenarios
func TestRunner_Run_CheckCleanup(t *testing.T) {
t.Run("cleans up old checks when limit exceeded", func(t *testing.T) {
checksDeleted := []string{}
// Create checks that exceed the max history limit
items := make([]advisorv0alpha1.Check, 0, defaultMaxHistory+2)
for i := 0; i < defaultMaxHistory+2; i++ {
item := advisorv0alpha1.Check{}
item.SetName(fmt.Sprintf("check-%d", i))
item.SetLabels(map[string]string{
checks.TypeLabel: "test-type",
})
item.SetCreationTimestamp(metav1.NewTime(time.Now().Add(-time.Duration(i) * time.Hour)))
items = append(items, item)
}
mockClient := &MockClient{
listFunc: func(ctx context.Context, namespace string, options resource.ListOptions) (resource.ListObject, error) {
return &advisorv0alpha1.CheckList{Items: items}, nil
},
deleteFunc: func(ctx context.Context, id resource.Identifier, opts resource.DeleteOptions) error {
checksDeleted = append(checksDeleted, id.Name)
return nil
},
}
mockTypesClient := &MockClient{
listFunc: func(ctx context.Context, namespace string, options resource.ListOptions) (resource.ListObject, error) {
return &advisorv0alpha1.CheckTypeList{Items: []advisorv0alpha1.CheckType{}}, nil
},
}
runner := createTestRunner(mockClient, mockTypesClient)
err := runAndTimeout(runner)
assert.ErrorAs(t, err, &context.DeadlineExceeded)
// Should delete some checks due to cleanup
assert.Greater(t, len(checksDeleted), 0)
})
}
// TestRunner_Run_UnprocessedChecks tests handling of unprocessed checks
func TestRunner_Run_UnprocessedChecks(t *testing.T) {
t.Run("marks unprocessed checks as error", func(t *testing.T) {
patchOperations := []resource.PatchOperation{}
mockClient := &MockClient{
listFunc: func(ctx context.Context, namespace string, options resource.ListOptions) (resource.ListObject, error) {
return &advisorv0alpha1.CheckList{
Items: []advisorv0alpha1.Check{
{
ObjectMeta: metav1.ObjectMeta{
Name: "unprocessed-check",
CreationTimestamp: metav1.NewTime(time.Now().Add(-1 * time.Hour)),
// No status annotation - unprocessed
},
},
},
}, nil
},
patchFunc: func(ctx context.Context, id resource.Identifier, patch resource.PatchRequest, options resource.PatchOptions, into resource.Object) error {
patchOperations = append(patchOperations, patch.Operations...)
return nil
},
}
mockTypesClient := &MockClient{
listFunc: func(ctx context.Context, namespace string, options resource.ListOptions) (resource.ListObject, error) {
return &advisorv0alpha1.CheckTypeList{Items: []advisorv0alpha1.CheckType{}}, nil
},
}
runner := createTestRunner(mockClient, mockTypesClient)
err := runAndTimeout(runner)
assert.ErrorAs(t, err, &context.DeadlineExceeded)
// Should patch unprocessed check with error status
assert.Greater(t, len(patchOperations), 0)
})
}
// TestRunner_Run_Pagination tests pagination handling
func TestRunner_Run_Pagination(t *testing.T) {
t.Run("handles paginated check lists", func(t *testing.T) {
callCount := 0
mockClient := &MockClient{
listFunc: func(ctx context.Context, namespace string, options resource.ListOptions) (resource.ListObject, error) {
callCount++
if callCount == 1 {
return &advisorv0alpha1.CheckList{
ListMeta: metav1.ListMeta{Continue: "continue-token"},
Items: []advisorv0alpha1.Check{
{ObjectMeta: metav1.ObjectMeta{Name: "check-1"}},
},
}, nil
}
return &advisorv0alpha1.CheckList{
Items: []advisorv0alpha1.Check{
{ObjectMeta: metav1.ObjectMeta{Name: "check-2"}},
},
}, nil
},
}
mockTypesClient := &MockClient{
listFunc: func(ctx context.Context, namespace string, options resource.ListOptions) (resource.ListObject, error) {
return &advisorv0alpha1.CheckTypeList{Items: []advisorv0alpha1.CheckType{}}, nil
},
}
runner := createTestRunner(mockClient, mockTypesClient)
err := runAndTimeout(runner)
assert.ErrorAs(t, err, &context.DeadlineExceeded)
// Should handle pagination correctly
assert.GreaterOrEqual(t, callCount, 2)
})
}
// Helper functions
// runAndTimeout runs a runner with a short timeout for testing purposes.
// This is used to terminate the runner's infinite loop in tests that don't specifically test timeout behavior.
func runAndTimeout(runner *Runner) error {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Millisecond)
defer cancel()
return runner.Run(ctx)
}
// createTestRunner creates a test runner with mock clients
func createTestRunner(checkClient, typesClient *MockClient) *Runner {
return createTestRunnerWithRegistry(checkClient, typesClient, &MockCheckService{checks: []checks.Check{}})
}
// createTestRunnerWithRegistry creates a test runner with mock clients and custom registry
func createTestRunnerWithRegistry(checkClient, typesClient *MockClient, checkRegistry checkregistry.CheckService) *Runner {
// Ensure mock clients have default implementations
if checkClient.listFunc == nil {
checkClient.listFunc = func(ctx context.Context, namespace string, options resource.ListOptions) (resource.ListObject, error) {
return &advisorv0alpha1.CheckList{Items: []advisorv0alpha1.Check{}}, nil
}
} }
if checkClient.createFunc == nil {
checkClient.createFunc = func(ctx context.Context, id resource.Identifier, obj resource.Object, opts resource.CreateOptions) (resource.Object, error) { runner := &Runner{
return obj, nil client: mockClient,
} log: &logging.NoOpLogger{},
} }
if checkClient.deleteFunc == nil {
checkClient.deleteFunc = func(ctx context.Context, id resource.Identifier, opts resource.DeleteOptions) error { lastCreated, err := runner.checkLastCreated(context.Background(), &logging.NoOpLogger{})
assert.NoError(t, err)
assert.Equal(t, now.Truncate(time.Second), lastCreated.Truncate(time.Second))
}
func TestRunner_createChecks_ErrorOnCreate(t *testing.T) {
mockCheckService := &MockCheckService{checks: []checks.Check{&mockCheck{id: "check-1"}}}
mockClient := &MockClient{
createFunc: func(ctx context.Context, id resource.Identifier, obj resource.Object, opts resource.CreateOptions) (resource.Object, error) {
return nil, errors.New("create error")
},
}
mockTypesClient := &MockClient{
listFunc: func(ctx context.Context, namespace string, options resource.ListOptions) (resource.ListObject, error) {
checkType := &advisorv0alpha1.CheckType{}
checkType.Spec.Name = "check-1"
return &advisorv0alpha1.CheckTypeList{
Items: []advisorv0alpha1.CheckType{*checkType},
}, nil
},
}
runner := &Runner{
checkRegistry: mockCheckService,
client: mockClient,
typesClient: mockTypesClient,
log: &logging.NoOpLogger{},
}
err := runner.createChecks(context.Background(), &logging.NoOpLogger{})
assert.Error(t, err)
}
func TestRunner_createChecks_Success(t *testing.T) {
mockCheckService := &MockCheckService{checks: []checks.Check{&mockCheck{id: "check-1"}}}
mockClient := &MockClient{
createFunc: func(ctx context.Context, id resource.Identifier, obj resource.Object, opts resource.CreateOptions) (resource.Object, error) {
return &advisorv0alpha1.Check{}, nil
},
}
mockTypesClient := &MockClient{
listFunc: func(ctx context.Context, namespace string, options resource.ListOptions) (resource.ListObject, error) {
checkType := &advisorv0alpha1.CheckType{}
checkType.Spec.Name = "check-1"
return &advisorv0alpha1.CheckTypeList{
Items: []advisorv0alpha1.CheckType{*checkType},
}, nil
},
}
runner := &Runner{
checkRegistry: mockCheckService,
client: mockClient,
typesClient: mockTypesClient,
log: &logging.NoOpLogger{},
}
err := runner.createChecks(context.Background(), &logging.NoOpLogger{})
assert.NoError(t, err)
}
func TestRunner_cleanupChecks_ErrorOnList(t *testing.T) {
mockClient := &MockClient{
listFunc: func(ctx context.Context, namespace string, options resource.ListOptions) (resource.ListObject, error) {
return nil, errors.New("list error")
},
}
runner := &Runner{
client: mockClient,
log: &logging.NoOpLogger{},
}
err := runner.cleanupChecks(context.Background(), &logging.NoOpLogger{})
assert.Error(t, err)
}
func TestRunner_cleanupChecks_WithinMax(t *testing.T) {
mockClient := &MockClient{
listFunc: func(ctx context.Context, namespace string, options resource.ListOptions) (resource.ListObject, error) {
return &advisorv0alpha1.CheckList{
Items: []advisorv0alpha1.Check{{}, {}},
}, nil
},
deleteFunc: func(ctx context.Context, identifier resource.Identifier, options resource.DeleteOptions) error {
return fmt.Errorf("shouldn't be called")
},
}
runner := &Runner{
client: mockClient,
log: &logging.NoOpLogger{},
}
err := runner.cleanupChecks(context.Background(), &logging.NoOpLogger{})
assert.NoError(t, err)
}
func TestRunner_cleanupChecks_ErrorOnDelete(t *testing.T) {
mockClient := &MockClient{
listFunc: func(ctx context.Context, namespace string, options resource.ListOptions) (resource.ListObject, error) {
items := make([]advisorv0alpha1.Check, 0, defaultMaxHistory+1)
for i := 0; i < defaultMaxHistory+1; i++ {
item := advisorv0alpha1.Check{}
item.SetLabels(map[string]string{
checks.TypeLabel: "mock",
})
items = append(items, item)
}
return &advisorv0alpha1.CheckList{
Items: items,
}, nil
},
deleteFunc: func(ctx context.Context, identifier resource.Identifier, options resource.DeleteOptions) error {
return errors.New("delete error")
},
}
runner := &Runner{
client: mockClient,
maxHistory: defaultMaxHistory,
log: &logging.NoOpLogger{},
}
err := runner.cleanupChecks(context.Background(), &logging.NoOpLogger{})
assert.ErrorContains(t, err, "delete error")
}
func TestRunner_cleanupChecks_Success(t *testing.T) {
itemsDeleted := []string{}
items := make([]advisorv0alpha1.Check, 0, defaultMaxHistory+1)
for i := 0; i < defaultMaxHistory+1; i++ {
item := advisorv0alpha1.Check{}
item.SetName(fmt.Sprintf("check-%d", i))
item.SetLabels(map[string]string{
checks.TypeLabel: "mock",
})
item.SetCreationTimestamp(metav1.NewTime(time.Time{}.Add(time.Duration(i) * time.Hour)))
items = append(items, item)
}
// shuffle the items to ensure the oldest are deleted
rand.Shuffle(len(items), func(i, j int) { items[i], items[j] = items[j], items[i] })
mockClient := &MockClient{
listFunc: func(ctx context.Context, namespace string, options resource.ListOptions) (resource.ListObject, error) {
return &advisorv0alpha1.CheckList{
Items: items,
}, nil
},
deleteFunc: func(ctx context.Context, identifier resource.Identifier, options resource.DeleteOptions) error {
itemsDeleted = append(itemsDeleted, identifier.Name)
return nil return nil
} },
}
if checkClient.patchFunc == nil {
checkClient.patchFunc = func(ctx context.Context, id resource.Identifier, patch resource.PatchRequest, opts resource.PatchOptions, into resource.Object) error {
return nil
}
} }
if typesClient.listFunc == nil { runner := &Runner{
typesClient.listFunc = func(ctx context.Context, namespace string, options resource.ListOptions) (resource.ListObject, error) { client: mockClient,
// Return empty list to match the empty MockCheckService maxHistory: defaultMaxHistory,
return &advisorv0alpha1.CheckTypeList{Items: []advisorv0alpha1.CheckType{}}, nil log: &logging.NoOpLogger{},
}
}
return &Runner{
checkRegistry: checkRegistry,
checksClient: checkClient,
typesClient: typesClient,
defaultEvalInterval: 5 * time.Millisecond,
maxHistory: defaultMaxHistory,
log: &logging.NoOpLogger{},
orgService: &mockOrgService{orgs: []*org.OrgDTO{{ID: 1}}},
stackID: "",
} }
err := runner.cleanupChecks(context.Background(), &logging.NoOpLogger{})
assert.NoError(t, err)
assert.Equal(t, []string{"check-0"}, itemsDeleted)
} }
// Mock implementations func Test_getEvaluationInterval(t *testing.T) {
t.Run("default", func(t *testing.T) {
interval, err := getEvaluationInterval(map[string]string{})
assert.NoError(t, err)
assert.Equal(t, 7*24*time.Hour, interval)
})
t.Run("invalid", func(t *testing.T) {
interval, err := getEvaluationInterval(map[string]string{"evaluation_interval": "invalid"})
assert.Error(t, err)
assert.Zero(t, interval)
})
t.Run("custom", func(t *testing.T) {
interval, err := getEvaluationInterval(map[string]string{"evaluation_interval": "1h"})
assert.NoError(t, err)
assert.Equal(t, time.Hour, interval)
})
}
func Test_getMaxHistory(t *testing.T) {
t.Run("default", func(t *testing.T) {
history, err := getMaxHistory(map[string]string{})
assert.NoError(t, err)
assert.Equal(t, 10, history)
})
t.Run("invalid", func(t *testing.T) {
history, err := getMaxHistory(map[string]string{"max_history": "invalid"})
assert.Error(t, err)
assert.Zero(t, history)
})
t.Run("custom", func(t *testing.T) {
history, err := getMaxHistory(map[string]string{"max_history": "5"})
assert.NoError(t, err)
assert.Equal(t, 5, history)
})
}
func Test_getNextSendInterval(t *testing.T) {
lastCreated := time.Now().Add(-7 * 24 * time.Hour)
evaluationInterval := 7 * 24 * time.Hour
nextSendInterval := getNextSendInterval(lastCreated, evaluationInterval)
// The next send interval should be in < 1 hour
assert.True(t, nextSendInterval < time.Hour)
// Calculate the next send interval again and it should be different
nextSendInterval2 := getNextSendInterval(lastCreated, evaluationInterval)
assert.NotEqual(t, nextSendInterval, nextSendInterval2)
}
type MockClient struct { type MockClient struct {
resource.Client resource.Client
@@ -375,6 +414,7 @@ func (m *MockCheckService) Checks() []checks.Check {
type mockCheck struct { type mockCheck struct {
checks.Check checks.Check
id string id string
steps []checks.Step steps []checks.Step
} }
@@ -386,12 +426,3 @@ func (m *mockCheck) ID() string {
func (m *mockCheck) Steps() []checks.Step { func (m *mockCheck) Steps() []checks.Step {
return m.steps return m.steps
} }
type mockOrgService struct {
org.Service
orgs []*org.OrgDTO
}
func (m *mockOrgService) Search(ctx context.Context, query *org.SearchOrgsQuery) ([]*org.OrgDTO, error) {
return m.orgs, nil
}
@@ -16,7 +16,6 @@ import (
advisorv0alpha1 "github.com/grafana/grafana/apps/advisor/pkg/apis/advisor/v0alpha1" advisorv0alpha1 "github.com/grafana/grafana/apps/advisor/pkg/apis/advisor/v0alpha1"
"github.com/grafana/grafana/apps/advisor/pkg/app/checkregistry" "github.com/grafana/grafana/apps/advisor/pkg/app/checkregistry"
"github.com/grafana/grafana/apps/advisor/pkg/app/checks" "github.com/grafana/grafana/apps/advisor/pkg/app/checks"
"github.com/grafana/grafana/pkg/services/org"
"k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
) )
@@ -27,8 +26,7 @@ import (
type Runner struct { type Runner struct {
checkRegistry checkregistry.CheckService checkRegistry checkregistry.CheckService
client resource.Client client resource.Client
orgService org.Service namespace string
stackID string
log logging.Logger log logging.Logger
retryAttempts int retryAttempts int
retryDelay time.Duration retryDelay time.Duration
@@ -42,7 +40,10 @@ func New(cfg app.Config, log logging.Logger) (app.Runnable, error) {
return nil, fmt.Errorf("invalid config type") return nil, fmt.Errorf("invalid config type")
} }
checkRegistry := specificConfig.CheckRegistry checkRegistry := specificConfig.CheckRegistry
orgService := specificConfig.OrgService namespace, err := checks.GetNamespace(specificConfig.StackID)
if err != nil {
return nil, err
}
// Prepare storage client // Prepare storage client
clientGenerator := k8s.NewClientRegistry(cfg.KubeConfig, k8s.ClientConfig{}) clientGenerator := k8s.NewClientRegistry(cfg.KubeConfig, k8s.ClientConfig{})
@@ -54,8 +55,7 @@ func New(cfg app.Config, log logging.Logger) (app.Runnable, error) {
return &Runner{ return &Runner{
checkRegistry: checkRegistry, checkRegistry: checkRegistry,
client: client, client: client,
orgService: orgService, namespace: namespace,
stackID: specificConfig.StackID,
log: log.With("runner", "advisor.checktyperegisterer"), log: log.With("runner", "advisor.checktyperegisterer"),
retryAttempts: 5, retryAttempts: 5,
retryDelay: time.Second * 10, retryDelay: time.Second * 10,
@@ -64,47 +64,36 @@ func New(cfg app.Config, log logging.Logger) (app.Runnable, error) {
func (r *Runner) Run(ctx context.Context) error { func (r *Runner) Run(ctx context.Context) error {
logger := r.log.WithContext(ctx) logger := r.log.WithContext(ctx)
for _, t := range r.checkRegistry.Checks() {
// Determine namespaces based on StackID or OrgID steps := t.Steps()
namespaces, err := checks.GetNamespaces(ctx, r.stackID, r.orgService) stepTypes := make([]advisorv0alpha1.CheckTypeStep, len(steps))
if err != nil { for i, s := range steps {
return fmt.Errorf("failed to get namespaces: %w", err) stepTypes[i] = advisorv0alpha1.CheckTypeStep{
} Title: s.Title(),
logger.Debug("Registering check types", "namespaces", len(namespaces)) Description: s.Description(),
StepID: s.ID(),
// Register check types in each namespace Resolution: s.Resolution(),
for _, namespace := range namespaces {
for _, t := range r.checkRegistry.Checks() {
steps := t.Steps()
stepTypes := make([]advisorv0alpha1.CheckTypeStep, len(steps))
for i, s := range steps {
stepTypes[i] = advisorv0alpha1.CheckTypeStep{
Title: s.Title(),
Description: s.Description(),
StepID: s.ID(),
Resolution: s.Resolution(),
}
} }
obj := &advisorv0alpha1.CheckType{ }
ObjectMeta: metav1.ObjectMeta{ obj := &advisorv0alpha1.CheckType{
Name: t.ID(), ObjectMeta: metav1.ObjectMeta{
Namespace: namespace, Name: t.ID(),
Annotations: map[string]string{ Namespace: r.namespace,
checks.NameAnnotation: t.Name(), Annotations: map[string]string{
// Flag to indicate feature availability checks.NameAnnotation: t.Name(),
checks.RetryAnnotation: "1", // Flag to indicate feature availability
checks.IgnoreStepsAnnotation: "1", checks.RetryAnnotation: "1",
}, checks.IgnoreStepsAnnotation: "1",
}, },
Spec: advisorv0alpha1.CheckTypeSpec{ },
Name: t.ID(), Spec: advisorv0alpha1.CheckTypeSpec{
Steps: stepTypes, Name: t.ID(),
}, Steps: stepTypes,
} },
err := r.registerCheckType(ctx, logger, t.ID(), obj) }
if err != nil { err := r.registerCheckType(ctx, logger, t.ID(), obj)
return err if err != nil {
} return err
} }
} }
return nil return nil
@@ -10,7 +10,6 @@ import (
"github.com/grafana/grafana-app-sdk/resource" "github.com/grafana/grafana-app-sdk/resource"
advisorv0alpha1 "github.com/grafana/grafana/apps/advisor/pkg/apis/advisor/v0alpha1" advisorv0alpha1 "github.com/grafana/grafana/apps/advisor/pkg/apis/advisor/v0alpha1"
"github.com/grafana/grafana/apps/advisor/pkg/app/checks" "github.com/grafana/grafana/apps/advisor/pkg/app/checks"
"github.com/grafana/grafana/pkg/services/org"
k8sErrs "k8s.io/apimachinery/pkg/api/errors" k8sErrs "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/schema"
@@ -68,17 +67,14 @@ func TestCheckTypesRegisterer_Run(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
checks []checks.Check checks []checks.Check
stackID string
orgService org.Service
getFunc func(ctx context.Context, id resource.Identifier) (resource.Object, error) getFunc func(ctx context.Context, id resource.Identifier) (resource.Object, error)
createFunc func(ctx context.Context, id resource.Identifier, obj resource.Object, opts resource.CreateOptions) (resource.Object, error) createFunc func(ctx context.Context, id resource.Identifier, obj resource.Object, opts resource.CreateOptions) (resource.Object, error)
updateFunc func(ctx context.Context, id resource.Identifier, obj resource.Object, opts resource.UpdateOptions) (resource.Object, error) updateFunc func(ctx context.Context, id resource.Identifier, obj resource.Object, opts resource.UpdateOptions) (resource.Object, error)
expectedErr error expectedErr error
}{ }{
{ {
name: "successful create", name: "successful create",
checks: []checks.Check{newMockCheck}, checks: []checks.Check{newMockCheck},
stackID: "123",
getFunc: func(ctx context.Context, id resource.Identifier) (resource.Object, error) { getFunc: func(ctx context.Context, id resource.Identifier) (resource.Object, error) {
return nil, k8sErrs.NewNotFound(schema.GroupResource{}, id.Name) return nil, k8sErrs.NewNotFound(schema.GroupResource{}, id.Name)
}, },
@@ -89,9 +85,8 @@ func TestCheckTypesRegisterer_Run(t *testing.T) {
expectedErr: nil, expectedErr: nil,
}, },
{ {
name: "resource exists with different annotations, should update", name: "resource exists with different annotations, should update",
checks: []checks.Check{newMockCheck}, checks: []checks.Check{newMockCheck},
stackID: "123",
getFunc: func(ctx context.Context, id resource.Identifier) (resource.Object, error) { getFunc: func(ctx context.Context, id resource.Identifier) (resource.Object, error) {
return existingObjectDifferentAnnotations, nil return existingObjectDifferentAnnotations, nil
}, },
@@ -101,9 +96,8 @@ func TestCheckTypesRegisterer_Run(t *testing.T) {
expectedErr: nil, expectedErr: nil,
}, },
{ {
name: "resource exists with different steps, should update", name: "resource exists with different steps, should update",
checks: []checks.Check{newMockCheck}, checks: []checks.Check{newMockCheck},
stackID: "123",
getFunc: func(ctx context.Context, id resource.Identifier) (resource.Object, error) { getFunc: func(ctx context.Context, id resource.Identifier) (resource.Object, error) {
return existingObjectDifferentSteps, nil return existingObjectDifferentSteps, nil
}, },
@@ -113,9 +107,8 @@ func TestCheckTypesRegisterer_Run(t *testing.T) {
expectedErr: nil, expectedErr: nil,
}, },
{ {
name: "resource exists with same annotations and steps, should not update", name: "resource exists with same annotations and steps, should not update",
checks: []checks.Check{newMockCheck}, checks: []checks.Check{newMockCheck},
stackID: "123",
getFunc: func(ctx context.Context, id resource.Identifier) (resource.Object, error) { getFunc: func(ctx context.Context, id resource.Identifier) (resource.Object, error) {
return existingObjectSameContent, nil return existingObjectSameContent, nil
}, },
@@ -125,9 +118,8 @@ func TestCheckTypesRegisterer_Run(t *testing.T) {
expectedErr: nil, expectedErr: nil,
}, },
{ {
name: "resource exists, with custom annotations preserved", name: "resource exists, with custom annotations preserved",
checks: []checks.Check{newMockCheck}, checks: []checks.Check{newMockCheck},
stackID: "123",
getFunc: func(ctx context.Context, id resource.Identifier) (resource.Object, error) { getFunc: func(ctx context.Context, id resource.Identifier) (resource.Object, error) {
return existingObjectDifferentAnnotations, nil return existingObjectDifferentAnnotations, nil
}, },
@@ -140,9 +132,8 @@ func TestCheckTypesRegisterer_Run(t *testing.T) {
expectedErr: nil, expectedErr: nil,
}, },
{ {
name: "create error", name: "create error",
checks: []checks.Check{newMockCheck}, checks: []checks.Check{newMockCheck},
stackID: "123",
getFunc: func(ctx context.Context, id resource.Identifier) (resource.Object, error) { getFunc: func(ctx context.Context, id resource.Identifier) (resource.Object, error) {
return nil, k8sErrs.NewNotFound(schema.GroupResource{}, id.Name) return nil, k8sErrs.NewNotFound(schema.GroupResource{}, id.Name)
}, },
@@ -153,9 +144,8 @@ func TestCheckTypesRegisterer_Run(t *testing.T) {
expectedErr: errors.New("create error"), expectedErr: errors.New("create error"),
}, },
{ {
name: "update error", name: "update error",
checks: []checks.Check{newMockCheck}, checks: []checks.Check{newMockCheck},
stackID: "123",
getFunc: func(ctx context.Context, id resource.Identifier) (resource.Object, error) { getFunc: func(ctx context.Context, id resource.Identifier) (resource.Object, error) {
return existingObjectDifferentAnnotations, nil return existingObjectDifferentAnnotations, nil
}, },
@@ -165,9 +155,8 @@ func TestCheckTypesRegisterer_Run(t *testing.T) {
expectedErr: errors.New("update error"), expectedErr: errors.New("update error"),
}, },
{ {
name: "shutting down error", name: "shutting down error",
checks: []checks.Check{newMockCheck}, checks: []checks.Check{newMockCheck},
stackID: "123",
getFunc: func(ctx context.Context, id resource.Identifier) (resource.Object, error) { getFunc: func(ctx context.Context, id resource.Identifier) (resource.Object, error) {
return existingObjectDifferentAnnotations, nil return existingObjectDifferentAnnotations, nil
}, },
@@ -177,33 +166,14 @@ func TestCheckTypesRegisterer_Run(t *testing.T) {
expectedErr: nil, expectedErr: nil,
}, },
{ {
name: "cloud stack namespace", name: "custom namespace",
checks: []checks.Check{newMockCheck}, checks: []checks.Check{newMockCheck},
stackID: "456",
getFunc: func(ctx context.Context, id resource.Identifier) (resource.Object, error) { getFunc: func(ctx context.Context, id resource.Identifier) (resource.Object, error) {
return nil, k8sErrs.NewNotFound(schema.GroupResource{}, id.Name) return existingObjectDifferentAnnotations, nil
}, },
createFunc: func(ctx context.Context, id resource.Identifier, obj resource.Object, opts resource.CreateOptions) (resource.Object, error) { createFunc: func(ctx context.Context, id resource.Identifier, obj resource.Object, opts resource.CreateOptions) (resource.Object, error) {
if obj.GetNamespace() != "stack-456" { if obj.GetNamespace() != "custom-namespace" {
return nil, fmt.Errorf("expected namespace %s, got %s", "stack-456", obj.GetNamespace()) return nil, fmt.Errorf("expected namespace %s, got %s", "custom-namespace", obj.GetNamespace())
}
return obj, nil
},
expectedErr: nil,
},
{
name: "multiple orgs",
checks: []checks.Check{newMockCheck},
stackID: "",
orgService: &mockOrgService{orgs: []*org.OrgDTO{{ID: 1, Name: "Org1"}, {ID: 2, Name: "Org2"}}},
getFunc: func(ctx context.Context, id resource.Identifier) (resource.Object, error) {
return nil, k8sErrs.NewNotFound(schema.GroupResource{}, id.Name)
},
createFunc: func(ctx context.Context, id resource.Identifier, obj resource.Object, opts resource.CreateOptions) (resource.Object, error) {
// Should create in both org-1 and org-2 namespaces
ns := obj.GetNamespace()
if ns != "org-1" && ns != "org-2" {
return nil, fmt.Errorf("expected namespace org-1 or org-2, got %s", ns)
} }
return obj, nil return obj, nil
}, },
@@ -213,10 +183,6 @@ func TestCheckTypesRegisterer_Run(t *testing.T) {
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
orgSvc := tt.orgService
if orgSvc == nil {
orgSvc = &mockOrgService{orgs: []*org.OrgDTO{}}
}
r := &Runner{ r := &Runner{
checkRegistry: &mockCheckRegistry{checks: tt.checks}, checkRegistry: &mockCheckRegistry{checks: tt.checks},
client: &mockClient{ client: &mockClient{
@@ -224,8 +190,7 @@ func TestCheckTypesRegisterer_Run(t *testing.T) {
createFunc: tt.createFunc, createFunc: tt.createFunc,
updateFunc: tt.updateFunc, updateFunc: tt.updateFunc,
}, },
orgService: orgSvc, namespace: "custom-namespace",
stackID: tt.stackID,
log: logging.DefaultLogger, log: logging.DefaultLogger,
retryAttempts: 1, retryAttempts: 1,
retryDelay: 0, retryDelay: 0,
@@ -333,12 +298,3 @@ func (m *mockClient) Update(ctx context.Context, id resource.Identifier, obj res
} }
return nil, errors.New("not implemented") return nil, errors.New("not implemented")
} }
type mockOrgService struct {
org.Service
orgs []*org.OrgDTO
}
func (m *mockOrgService) Search(ctx context.Context, query *org.SearchOrgsQuery) ([]*org.OrgDTO, error) {
return m.orgs, nil
}
-10
View File
@@ -9,7 +9,6 @@ import (
"sync" "sync"
"time" "time"
"github.com/grafana/authlib/types"
"github.com/grafana/grafana-app-sdk/logging" "github.com/grafana/grafana-app-sdk/logging"
"github.com/grafana/grafana-app-sdk/resource" "github.com/grafana/grafana-app-sdk/resource"
advisorv0alpha1 "github.com/grafana/grafana/apps/advisor/pkg/apis/advisor/v0alpha1" advisorv0alpha1 "github.com/grafana/grafana/apps/advisor/pkg/apis/advisor/v0alpha1"
@@ -318,12 +317,3 @@ func waitForRetryAnnotation(ctx context.Context, log logging.Logger, client reso
log.Debug("Retry annotation persisted", "check", obj.GetName(), "item", itemToRetry) log.Debug("Retry annotation persisted", "check", obj.GetName(), "item", itemToRetry)
return nil return nil
} }
// getOrgIDFromNamespace extracts the org ID from a namespace using the standard authlib parser.
func getOrgIDFromNamespace(namespace string) (int64, error) {
info, err := types.ParseNamespace(namespace)
if err != nil {
return 0, fmt.Errorf("failed to parse namespace %s: %w", namespace, err)
}
return info.OrgID, nil
}
-58
View File
@@ -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)
}
+7 -8
View File
@@ -3,20 +3,19 @@ module github.com/grafana/grafana/apps/alerting/alertenrichment
go 1.25.3 go 1.25.3
require ( require (
github.com/grafana/grafana-app-sdk v0.48.1 github.com/grafana/grafana-app-sdk v0.46.0
github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250901080157-a0280d701b28 github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250901080157-a0280d701b28
k8s.io/apimachinery v0.34.1 k8s.io/apimachinery v0.34.1
k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b
) )
require ( require (
github.com/emicklei/go-restful/v3 v3.13.0 // indirect github.com/emicklei/go-restful/v3 v3.13.0 // indirect
github.com/fxamacker/cbor/v2 v2.9.0 // indirect github.com/fxamacker/cbor/v2 v2.9.0 // indirect
github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/logr v1.4.3 // indirect
github.com/go-openapi/jsonpointer v0.22.1 // indirect github.com/go-openapi/jsonpointer v0.21.0 // indirect
github.com/go-openapi/jsonreference v0.21.2 // indirect github.com/go-openapi/jsonreference v0.21.0 // indirect
github.com/go-openapi/swag v0.23.0 // indirect github.com/go-openapi/swag v0.23.0 // indirect
github.com/go-openapi/swag/jsonname v0.25.1 // indirect
github.com/gogo/protobuf v1.3.2 // indirect github.com/gogo/protobuf v1.3.2 // indirect
github.com/google/gnostic-models v0.7.0 // indirect github.com/google/gnostic-models v0.7.0 // indirect
github.com/josharian/intern v1.0.0 // indirect github.com/josharian/intern v1.0.0 // indirect
@@ -25,11 +24,11 @@ require (
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect
github.com/x448/float16 v0.8.4 // indirect github.com/x448/float16 v0.8.4 // indirect
go.yaml.in/yaml/v2 v2.4.3 // indirect go.yaml.in/yaml/v2 v2.4.2 // indirect
go.yaml.in/yaml/v3 v3.0.4 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect
golang.org/x/net v0.46.0 // indirect golang.org/x/net v0.45.0 // indirect
golang.org/x/text v0.30.0 // indirect golang.org/x/text v0.30.0 // indirect
google.golang.org/protobuf v1.36.10 // indirect google.golang.org/protobuf v1.36.9 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/klog/v2 v2.130.1 // indirect k8s.io/klog/v2 v2.130.1 // indirect
+14 -16
View File
@@ -8,14 +8,12 @@ github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sa
github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ= github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= 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/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-openapi/jsonpointer v0.22.1 h1:sHYI1He3b9NqJ4wXLoJDKmUmHkWy/L7rtEo92JUxBNk= github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=
github.com/go-openapi/jsonpointer v0.22.1/go.mod h1:pQT9OsLkfz1yWoMgYFy4x3U5GY5nUlsOn1qSBH5MkCM= github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
github.com/go-openapi/jsonreference v0.21.2 h1:Wxjda4M/BBQllegefXrY/9aq1fxBA8sI5M/lFU6tSWU= github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ=
github.com/go-openapi/jsonreference v0.21.2/go.mod h1:pp3PEjIsJ9CZDGCNOyXIQxsNuroxm8FAJ/+quA0yKzQ= github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4=
github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=
github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
github.com/go-openapi/swag/jsonname v0.25.1 h1:Sgx+qbwa4ej6AomWC6pEfXrA6uP2RkaNjA9BR8a1RJU=
github.com/go-openapi/swag/jsonname v0.25.1/go.mod h1:71Tekow6UOLBD3wS7XhdT98g5J5GR13NOTQ9/6Q11Zo=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/google/gnostic-models v0.7.0 h1:qwTtogB15McXDaNqTZdzPJRHvaVJlAl+HVQnLmJEJxo= github.com/google/gnostic-models v0.7.0 h1:qwTtogB15McXDaNqTZdzPJRHvaVJlAl+HVQnLmJEJxo=
@@ -23,8 +21,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 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= 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/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.46.0 h1:gvzQvCQgZJ/73BfAcbDt/6TAMhnVikVPxZt/UwDl+oc=
github.com/grafana/grafana-app-sdk v0.48.1/go.mod h1:5LljCz+wvmGfkQ8ZKTOfserhtXNEF0cSFthoWShvN6c= github.com/grafana/grafana-app-sdk v0.46.0/go.mod h1:LCTrqR1SwBS13XGVYveBmM7giJDDjzuXK+M9VzPuPWc=
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 h1:PgMfX4OPENz/iXmtDDIW9+poZY4UD0hhmXm7flVclDo=
github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250901080157-a0280d701b28/go.mod h1:av5N0Naq+8VV9MLF7zAkihy/mVq5UbS2EvRSJukDHlY= 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= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
@@ -60,8 +58,8 @@ github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0= go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI=
go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8= go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU=
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= 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-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
@@ -73,8 +71,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-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-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.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4= golang.org/x/net v0.45.0 h1:RLBg5JKixCy82FtLJpeNlVM0nrSqpCRYzVU1n8kj0tM=
golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210= golang.org/x/net v0.45.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 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-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.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -93,8 +91,8 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/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= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw=
google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
@@ -106,8 +104,8 @@ 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.1/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw=
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 h1:Y3gxNAuB0OBLImH611+UDZcmKS3g6CthxToOb37KgwE= k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b h1:MloQ9/bdJyIu9lb1PzujOPolHyvO06MXG5TUIj2mNAA=
k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912/go.mod h1:kdmbQkyfwUagLfXIad1y2TdrjPFWp2Q89B3qkRwf/pQ= k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b/go.mod h1:UZ2yyWbFTpuhSbFhv24aGNOdoRdJZgsIObGBUaYVsts=
k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 h1:hwvWFiBzdWw1FhfY1FooPn3kzWuJ8tmbZBHi4zVsl1Y= k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 h1:hwvWFiBzdWw1FhfY1FooPn3kzWuJ8tmbZBHi4zVsl1Y=
k8s.io/utils v0.0.0-20250604170112-4c0f3b243397/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= k8s.io/utils v0.0.0-20250604170112-4c0f3b243397/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 h1:gBQPwqORJ8d8/YNZWEjoZs7npUVDpVXUUOFfW6CgAqE= sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 h1:gBQPwqORJ8d8/YNZWEjoZs7npUVDpVXUUOFfW6CgAqE=
+6 -9
View File
@@ -1,11 +1,8 @@
include ../../sdk.mk include ../../sdk.mk
.PHONY: generate # Run Grafana App SDK code generation .PHONY: generate
generate: install-app-sdk update-app-sdk generate: do-generate ## Run Grafana App SDK code generation
@$(APP_SDK_BIN) generate \
--source=./kinds/ \ .PHONY: do-generate
--gogenpath=./pkg/apis \ do-generate: install-app-sdk update-app-sdk
--grouping=group \ @$(APP_SDK_BIN) generate --grouping=group --gogenpath=./pkg/apis --defencoding=yaml --postprocess
--genoperatorstate=false \
--defencoding=none
+15 -16
View File
@@ -3,11 +3,11 @@ module github.com/grafana/grafana/apps/alerting/notifications
go 1.25.3 go 1.25.3
require ( require (
github.com/grafana/grafana-app-sdk v0.48.1 github.com/grafana/grafana-app-sdk v0.46.0
github.com/grafana/grafana-app-sdk/logging v0.48.1 github.com/grafana/grafana-app-sdk/logging v0.45.0
k8s.io/apimachinery v0.34.1 k8s.io/apimachinery v0.34.1
k8s.io/apiserver v0.34.1 k8s.io/apiserver v0.34.1
k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b
) )
require ( require (
@@ -26,10 +26,9 @@ require (
github.com/getkin/kin-openapi v0.133.0 // indirect github.com/getkin/kin-openapi v0.133.0 // indirect
github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/logr v1.4.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-openapi/jsonpointer v0.22.1 // indirect github.com/go-openapi/jsonpointer v0.21.0 // indirect
github.com/go-openapi/jsonreference v0.21.2 // indirect github.com/go-openapi/jsonreference v0.21.0 // indirect
github.com/go-openapi/swag v0.23.0 // indirect github.com/go-openapi/swag v0.23.0 // indirect
github.com/go-openapi/swag/jsonname v0.25.1 // indirect
github.com/go-test/deep v1.1.1 // indirect github.com/go-test/deep v1.1.1 // indirect
github.com/gogo/protobuf v1.3.2 // indirect github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang-jwt/jwt/v5 v5.3.0 // indirect github.com/golang-jwt/jwt/v5 v5.3.0 // indirect
@@ -59,7 +58,7 @@ require (
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect 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_golang v1.23.2 // indirect
github.com/prometheus/client_model v0.6.2 // indirect github.com/prometheus/client_model v0.6.2 // indirect
github.com/prometheus/common v0.67.1 // indirect github.com/prometheus/common v0.66.1 // indirect
github.com/prometheus/procfs v0.16.1 // indirect github.com/prometheus/procfs v0.16.1 // indirect
github.com/puzpuzpuz/xsync/v2 v2.5.1 // indirect github.com/puzpuzpuz/xsync/v2 v2.5.1 // indirect
github.com/rogpeppe/go-internal v1.14.1 // indirect github.com/rogpeppe/go-internal v1.14.1 // indirect
@@ -82,20 +81,20 @@ require (
go.opentelemetry.io/proto/otlp v1.7.1 // indirect go.opentelemetry.io/proto/otlp v1.7.1 // indirect
go.uber.org/multierr v1.11.0 // indirect go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.27.0 // indirect go.uber.org/zap v1.27.0 // indirect
go.yaml.in/yaml/v2 v2.4.3 // indirect go.yaml.in/yaml/v2 v2.4.2 // indirect
go.yaml.in/yaml/v3 v3.0.4 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect
golang.org/x/net v0.46.0 // indirect golang.org/x/net v0.45.0 // indirect
golang.org/x/oauth2 v0.32.0 // indirect golang.org/x/oauth2 v0.30.0 // indirect
golang.org/x/sync v0.17.0 // indirect golang.org/x/sync v0.17.0 // indirect
golang.org/x/sys v0.37.0 // indirect golang.org/x/sys v0.36.0 // indirect
golang.org/x/term v0.36.0 // indirect golang.org/x/term v0.35.0 // indirect
golang.org/x/text v0.30.0 // indirect golang.org/x/text v0.30.0 // indirect
golang.org/x/time v0.14.0 // indirect golang.org/x/time v0.13.0 // indirect
gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20250908214217-97024824d090 // 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 google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090 // indirect
google.golang.org/grpc v1.76.0 // indirect google.golang.org/grpc v1.75.1 // indirect
google.golang.org/protobuf v1.36.10 // indirect google.golang.org/protobuf v1.36.9 // indirect
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect
+34 -36
View File
@@ -36,14 +36,12 @@ 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/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 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-openapi/jsonpointer v0.22.1 h1:sHYI1He3b9NqJ4wXLoJDKmUmHkWy/L7rtEo92JUxBNk= github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=
github.com/go-openapi/jsonpointer v0.22.1/go.mod h1:pQT9OsLkfz1yWoMgYFy4x3U5GY5nUlsOn1qSBH5MkCM= github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
github.com/go-openapi/jsonreference v0.21.2 h1:Wxjda4M/BBQllegefXrY/9aq1fxBA8sI5M/lFU6tSWU= github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ=
github.com/go-openapi/jsonreference v0.21.2/go.mod h1:pp3PEjIsJ9CZDGCNOyXIQxsNuroxm8FAJ/+quA0yKzQ= github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4=
github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=
github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
github.com/go-openapi/swag/jsonname v0.25.1 h1:Sgx+qbwa4ej6AomWC6pEfXrA6uP2RkaNjA9BR8a1RJU=
github.com/go-openapi/swag/jsonname v0.25.1/go.mod h1:71Tekow6UOLBD3wS7XhdT98g5J5GR13NOTQ9/6Q11Zo=
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
github.com/go-test/deep v1.1.1 h1:0r/53hagsehfO4bzD2Pgr/+RgHqhmf+k1Bpse2cTu1U= github.com/go-test/deep v1.1.1 h1:0r/53hagsehfO4bzD2Pgr/+RgHqhmf+k1Bpse2cTu1U=
@@ -71,10 +69,10 @@ 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/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 h1:JeSE6pjso5THxAzdVpqr6/geYxZytqFMBCOtn/ujyeo=
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674/go.mod h1:r4w70xmWCQKmi1ONH4KIaBptdivuRPyosB9RmPlGEwA= 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.46.0 h1:gvzQvCQgZJ/73BfAcbDt/6TAMhnVikVPxZt/UwDl+oc=
github.com/grafana/grafana-app-sdk v0.48.1/go.mod h1:5LljCz+wvmGfkQ8ZKTOfserhtXNEF0cSFthoWShvN6c= github.com/grafana/grafana-app-sdk v0.46.0/go.mod h1:LCTrqR1SwBS13XGVYveBmM7giJDDjzuXK+M9VzPuPWc=
github.com/grafana/grafana-app-sdk/logging v0.48.1 h1:veM0X5LAPyN3KsDLglWjIofndbGuf7MqnrDuDN+F/Ng= github.com/grafana/grafana-app-sdk/logging v0.45.0 h1:0SH6nYZpiLBZRwUq4J6+1vo8xuHKJjnO95/2pGOoA8w=
github.com/grafana/grafana-app-sdk/logging v0.48.1/go.mod h1:Gh/nBWnspK3oDNWtiM5qUF/fardHzOIEez+SPI3JeHA= github.com/grafana/grafana-app-sdk/logging v0.45.0/go.mod h1:Gh/nBWnspK3oDNWtiM5qUF/fardHzOIEez+SPI3JeHA=
github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.1.0 h1:QGLs/O40yoNK9vmy4rhUGBVyMf1lISBGtXRpsu/Qu/o= github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.1.0 h1:QGLs/O40yoNK9vmy4rhUGBVyMf1lISBGtXRpsu/Qu/o=
github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.1.0/go.mod h1:hM2alZsMUni80N33RBe6J0e423LB+odMj7d3EMP9l20= github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.1.0/go.mod h1:hM2alZsMUni80N33RBe6J0e423LB+odMj7d3EMP9l20=
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.2 h1:sGm2vDRFUrQJO/Veii4h4zG2vvqG6uWNkBHSTqXOZk0= github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.2 h1:sGm2vDRFUrQJO/Veii4h4zG2vvqG6uWNkBHSTqXOZk0=
@@ -140,8 +138,8 @@ github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:
github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= 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/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.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/common v0.67.1 h1:OTSON1P4DNxzTg4hmKCc37o4ZAZDv0cfXLkOt0oEowI= github.com/prometheus/common v0.66.1 h1:h5E0h5/Y8niHc5DlaLlWLArTQI7tMrsfQjHV+d9ZoGs=
github.com/prometheus/common v0.67.1/go.mod h1:RpmT9v35q2Y+lsieQsdOh5sXZ6ajUGC8NjZAmr8vb0Q= github.com/prometheus/common v0.66.1/go.mod h1:gcaUsgf3KfRSwHY4dIMXLPV0K/Wg1oZ8+SbZk/HH/dA=
github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg= github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg=
github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is=
@@ -217,15 +215,15 @@ go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0= go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI=
go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8= go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU=
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= 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-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-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 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.42.0 h1:chiH31gIWm57EkTXpwnqf8qeuMUi0yekh6mT2AvFlqI=
golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0= golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 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.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
@@ -236,11 +234,11 @@ 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-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-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.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4= golang.org/x/net v0.45.0 h1:RLBg5JKixCy82FtLJpeNlVM0nrSqpCRYzVU1n8kj0tM=
golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210= golang.org/x/net v0.45.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= 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.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI=
golang.org/x/oauth2 v0.32.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -252,23 +250,23 @@ golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/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-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/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.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k=
golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/term v0.36.0 h1:zMPR+aF8gfksFprF/Nc/rd1wRS1EI6nDBGyWAvDzx2Q= golang.org/x/term v0.35.0 h1:bZBVKBudEyhRcajGcNc3jIfWPqV4y/Kt2XcoigOWtDQ=
golang.org/x/term v0.36.0/go.mod h1:Qu394IJq6V6dCBRgwqshf3mPF85AqzYEzofzRdZkWss= golang.org/x/term v0.35.0/go.mod h1:TPGtkTLesOwf2DE8CgVYiZinHAOuy5AYUYT1lENIZnA=
golang.org/x/text v0.3.0/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.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 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 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k=
golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM= golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM=
golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI= golang.org/x/time v0.13.0 h1:eUlYslOIt32DgYD6utsuUeHs4d7AsEYLuIAdg7FlYgI=
golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= golang.org/x/time v0.13.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4=
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 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-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-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.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ= golang.org/x/tools v0.37.0 h1:DVSRzp7FwePZW356yEAChSdNcQo6Nsp+fex1SUW09lE=
golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs= golang.org/x/tools v0.37.0/go.mod h1:MBN5QPQtLMHVdvsbtarmTNukZDdgwdwlO5qGacAzF0w=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 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-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -281,13 +279,13 @@ google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9Ywl
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto/googleapis/api v0.0.0-20250908214217-97024824d090 h1:d8Nakh1G+ur7+P3GcMjpRDEkoLUcLW2iU92XVqR+XMQ= google.golang.org/genproto/googleapis/api v0.0.0-20250908214217-97024824d090 h1:d8Nakh1G+ur7+P3GcMjpRDEkoLUcLW2iU92XVqR+XMQ=
google.golang.org/genproto/googleapis/api v0.0.0-20250908214217-97024824d090/go.mod h1:U8EXRNSd8sUYyDfs/It7KVWodQr+Hf9xtxyxWudSwEw= google.golang.org/genproto/googleapis/api v0.0.0-20250908214217-97024824d090/go.mod h1:U8EXRNSd8sUYyDfs/It7KVWodQr+Hf9xtxyxWudSwEw=
google.golang.org/genproto/googleapis/rpc v0.0.0-20251002232023-7c0ddcbb5797 h1:CirRxTOwnRWVLKzDNrs0CXAaVozJoR4G9xvdRecrdpk= google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090 h1:/OQuEa4YWtDt7uQWHd3q3sUMb+QOLQUg1xa8CEsRv5w=
google.golang.org/genproto/googleapis/rpc v0.0.0-20251002232023-7c0ddcbb5797/go.mod h1:HSkG/KdJWusxU1F6CNrwNDjBMgisKxGnc5dAZfT0mjQ= google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090/go.mod h1:GmFNa4BdJZ2a8G+wCe9Bg3wwThLrJun751XstdJt5Og=
google.golang.org/grpc v1.18.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.76.0 h1:UnVkv1+uMLYXoIz6o7chp59WfQUYA2ex/BXQ9rHZu7A= google.golang.org/grpc v1.75.1 h1:/ODCNEuf9VghjgO3rqLcfg8fiOP0nSluljWFlDxELLI=
google.golang.org/grpc v1.76.0/go.mod h1:Ju12QI8M6iQJtbcsV+awF5a4hfJMLi4X0JLo94ULZ6c= google.golang.org/grpc v1.75.1/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ=
google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw=
google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
@@ -314,8 +312,8 @@ 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/component-base v0.34.1/go.mod h1:mknCpLlTSKHzAQJJnnHVKqjxR7gBeHRv0rPXA7gdtQ0=
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 h1:Y3gxNAuB0OBLImH611+UDZcmKS3g6CthxToOb37KgwE= k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b h1:MloQ9/bdJyIu9lb1PzujOPolHyvO06MXG5TUIj2mNAA=
k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912/go.mod h1:kdmbQkyfwUagLfXIad1y2TdrjPFWp2Q89B3qkRwf/pQ= k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b/go.mod h1:UZ2yyWbFTpuhSbFhv24aGNOdoRdJZgsIObGBUaYVsts=
k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 h1:hwvWFiBzdWw1FhfY1FooPn3kzWuJ8tmbZBHi4zVsl1Y= k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 h1:hwvWFiBzdWw1FhfY1FooPn3kzWuJ8tmbZBHi4zVsl1Y=
k8s.io/utils v0.0.0-20250604170112-4c0f3b243397/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= k8s.io/utils v0.0.0-20250604170112-4c0f3b243397/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2 h1:jpcvIRr3GLoUoEKRkHKSmGjxb6lWwrBlJsXc+eUYQHM= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2 h1:jpcvIRr3GLoUoEKRkHKSmGjxb6lWwrBlJsXc+eUYQHM=
@@ -4,6 +4,7 @@ import (
"context" "context"
"github.com/grafana/grafana-app-sdk/resource" "github.com/grafana/grafana-app-sdk/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
) )
type ReceiverClient struct { type ReceiverClient struct {
@@ -75,6 +76,24 @@ func (c *ReceiverClient) Patch(ctx context.Context, identifier resource.Identifi
return c.client.Patch(ctx, identifier, req, opts) return c.client.Patch(ctx, identifier, req, opts)
} }
func (c *ReceiverClient) UpdateStatus(ctx context.Context, identifier resource.Identifier, newStatus ReceiverStatus, opts resource.UpdateOptions) (*Receiver, error) {
return c.client.Update(ctx, &Receiver{
TypeMeta: metav1.TypeMeta{
Kind: ReceiverKind().Kind(),
APIVersion: GroupVersion.Identifier(),
},
ObjectMeta: metav1.ObjectMeta{
ResourceVersion: opts.ResourceVersion,
Namespace: identifier.Namespace,
Name: identifier.Name,
},
Status: newStatus,
}, resource.UpdateOptions{
Subresource: "status",
ResourceVersion: opts.ResourceVersion,
})
}
func (c *ReceiverClient) Delete(ctx context.Context, identifier resource.Identifier, opts resource.DeleteOptions) error { func (c *ReceiverClient) Delete(ctx context.Context, identifier resource.Identifier, opts resource.DeleteOptions) error {
return c.client.Delete(ctx, identifier, opts) return c.client.Delete(ctx, identifier, opts)
} }
@@ -21,6 +21,8 @@ type Receiver struct {
// Spec is the spec of the Receiver // Spec is the spec of the Receiver
Spec ReceiverSpec `json:"spec" yaml:"spec"` Spec ReceiverSpec `json:"spec" yaml:"spec"`
Status ReceiverStatus `json:"status" yaml:"status"`
} }
func (o *Receiver) GetSpec() any { func (o *Receiver) GetSpec() any {
@@ -37,11 +39,15 @@ func (o *Receiver) SetSpec(spec any) error {
} }
func (o *Receiver) GetSubresources() map[string]any { func (o *Receiver) GetSubresources() map[string]any {
return map[string]any{} return map[string]any{
"status": o.Status,
}
} }
func (o *Receiver) GetSubresource(name string) (any, bool) { func (o *Receiver) GetSubresource(name string) (any, bool) {
switch name { switch name {
case "status":
return o.Status, true
default: default:
return nil, false return nil, false
} }
@@ -49,6 +55,13 @@ func (o *Receiver) GetSubresource(name string) (any, bool) {
func (o *Receiver) SetSubresource(name string, value any) error { func (o *Receiver) SetSubresource(name string, value any) error {
switch name { switch name {
case "status":
cast, ok := value.(ReceiverStatus)
if !ok {
return fmt.Errorf("cannot set status type %#v, not of type ReceiverStatus", value)
}
o.Status = cast
return nil
default: default:
return fmt.Errorf("subresource '%s' does not exist", name) return fmt.Errorf("subresource '%s' does not exist", name)
} }
@@ -220,6 +233,7 @@ func (o *Receiver) DeepCopyInto(dst *Receiver) {
dst.TypeMeta.Kind = o.TypeMeta.Kind dst.TypeMeta.Kind = o.TypeMeta.Kind
o.ObjectMeta.DeepCopyInto(&dst.ObjectMeta) o.ObjectMeta.DeepCopyInto(&dst.ObjectMeta)
o.Spec.DeepCopyInto(&dst.Spec) o.Spec.DeepCopyInto(&dst.Spec)
o.Status.DeepCopyInto(&dst.Status)
} }
// Interface compliance compile-time check // Interface compliance compile-time check
@@ -291,3 +305,15 @@ func (s *ReceiverSpec) DeepCopy() *ReceiverSpec {
func (s *ReceiverSpec) DeepCopyInto(dst *ReceiverSpec) { func (s *ReceiverSpec) DeepCopyInto(dst *ReceiverSpec) {
resource.CopyObjectInto(dst, s) resource.CopyObjectInto(dst, s)
} }
// DeepCopy creates a full deep copy of ReceiverStatus
func (s *ReceiverStatus) DeepCopy() *ReceiverStatus {
cpy := &ReceiverStatus{}
s.DeepCopyInto(cpy)
return cpy
}
// DeepCopyInto deep copies ReceiverStatus into another ReceiverStatus object
func (s *ReceiverStatus) DeepCopyInto(dst *ReceiverStatus) {
resource.CopyObjectInto(dst, s)
}
@@ -3,42 +3,42 @@
package v0alpha1 package v0alpha1
// +k8s:openapi-gen=true // +k8s:openapi-gen=true
type PluginstatusOperatorState struct { type ReceiverstatusOperatorState struct {
// lastEvaluation is the ResourceVersion last evaluated // lastEvaluation is the ResourceVersion last evaluated
LastEvaluation string `json:"lastEvaluation"` LastEvaluation string `json:"lastEvaluation"`
// state describes the state of the lastEvaluation. // state describes the state of the lastEvaluation.
// It is limited to three possible states for machine evaluation. // It is limited to three possible states for machine evaluation.
State PluginStatusOperatorStateState `json:"state"` State ReceiverStatusOperatorStateState `json:"state"`
// descriptiveState is an optional more descriptive state field which has no requirements on format // descriptiveState is an optional more descriptive state field which has no requirements on format
DescriptiveState *string `json:"descriptiveState,omitempty"` DescriptiveState *string `json:"descriptiveState,omitempty"`
// details contains any extra information that is operator-specific // details contains any extra information that is operator-specific
Details map[string]interface{} `json:"details,omitempty"` Details map[string]interface{} `json:"details,omitempty"`
} }
// NewPluginstatusOperatorState creates a new PluginstatusOperatorState object. // NewReceiverstatusOperatorState creates a new ReceiverstatusOperatorState object.
func NewPluginstatusOperatorState() *PluginstatusOperatorState { func NewReceiverstatusOperatorState() *ReceiverstatusOperatorState {
return &PluginstatusOperatorState{} return &ReceiverstatusOperatorState{}
} }
// +k8s:openapi-gen=true // +k8s:openapi-gen=true
type PluginStatus struct { type ReceiverStatus struct {
// operatorStates is a map of operator ID to operator state evaluations. // operatorStates is a map of operator ID to operator state evaluations.
// Any operator which consumes this kind SHOULD add its state evaluation information to this field. // Any operator which consumes this kind SHOULD add its state evaluation information to this field.
OperatorStates map[string]PluginstatusOperatorState `json:"operatorStates,omitempty"` OperatorStates map[string]ReceiverstatusOperatorState `json:"operatorStates,omitempty"`
// additionalFields is reserved for future use // additionalFields is reserved for future use
AdditionalFields map[string]interface{} `json:"additionalFields,omitempty"` AdditionalFields map[string]interface{} `json:"additionalFields,omitempty"`
} }
// NewPluginStatus creates a new PluginStatus object. // NewReceiverStatus creates a new ReceiverStatus object.
func NewPluginStatus() *PluginStatus { func NewReceiverStatus() *ReceiverStatus {
return &PluginStatus{} return &ReceiverStatus{}
} }
// +k8s:openapi-gen=true // +k8s:openapi-gen=true
type PluginStatusOperatorStateState string type ReceiverStatusOperatorStateState string
const ( const (
PluginStatusOperatorStateStateSuccess PluginStatusOperatorStateState = "success" ReceiverStatusOperatorStateStateSuccess ReceiverStatusOperatorStateState = "success"
PluginStatusOperatorStateStateInProgress PluginStatusOperatorStateState = "in_progress" ReceiverStatusOperatorStateStateInProgress ReceiverStatusOperatorStateState = "in_progress"
PluginStatusOperatorStateStateFailed PluginStatusOperatorStateState = "failed" ReceiverStatusOperatorStateStateFailed ReceiverStatusOperatorStateState = "failed"
) )
@@ -4,6 +4,7 @@ import (
"context" "context"
"github.com/grafana/grafana-app-sdk/resource" "github.com/grafana/grafana-app-sdk/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
) )
type RoutingTreeClient struct { type RoutingTreeClient struct {
@@ -75,6 +76,24 @@ func (c *RoutingTreeClient) Patch(ctx context.Context, identifier resource.Ident
return c.client.Patch(ctx, identifier, req, opts) return c.client.Patch(ctx, identifier, req, opts)
} }
func (c *RoutingTreeClient) UpdateStatus(ctx context.Context, identifier resource.Identifier, newStatus RoutingTreeStatus, opts resource.UpdateOptions) (*RoutingTree, error) {
return c.client.Update(ctx, &RoutingTree{
TypeMeta: metav1.TypeMeta{
Kind: RoutingTreeKind().Kind(),
APIVersion: GroupVersion.Identifier(),
},
ObjectMeta: metav1.ObjectMeta{
ResourceVersion: opts.ResourceVersion,
Namespace: identifier.Namespace,
Name: identifier.Name,
},
Status: newStatus,
}, resource.UpdateOptions{
Subresource: "status",
ResourceVersion: opts.ResourceVersion,
})
}
func (c *RoutingTreeClient) Delete(ctx context.Context, identifier resource.Identifier, opts resource.DeleteOptions) error { func (c *RoutingTreeClient) Delete(ctx context.Context, identifier resource.Identifier, opts resource.DeleteOptions) error {
return c.client.Delete(ctx, identifier, opts) return c.client.Delete(ctx, identifier, opts)
} }
@@ -21,6 +21,8 @@ type RoutingTree struct {
// Spec is the spec of the RoutingTree // Spec is the spec of the RoutingTree
Spec RoutingTreeSpec `json:"spec" yaml:"spec"` Spec RoutingTreeSpec `json:"spec" yaml:"spec"`
Status RoutingTreeStatus `json:"status" yaml:"status"`
} }
func (o *RoutingTree) GetSpec() any { func (o *RoutingTree) GetSpec() any {
@@ -37,11 +39,15 @@ func (o *RoutingTree) SetSpec(spec any) error {
} }
func (o *RoutingTree) GetSubresources() map[string]any { func (o *RoutingTree) GetSubresources() map[string]any {
return map[string]any{} return map[string]any{
"status": o.Status,
}
} }
func (o *RoutingTree) GetSubresource(name string) (any, bool) { func (o *RoutingTree) GetSubresource(name string) (any, bool) {
switch name { switch name {
case "status":
return o.Status, true
default: default:
return nil, false return nil, false
} }
@@ -49,6 +55,13 @@ func (o *RoutingTree) GetSubresource(name string) (any, bool) {
func (o *RoutingTree) SetSubresource(name string, value any) error { func (o *RoutingTree) SetSubresource(name string, value any) error {
switch name { switch name {
case "status":
cast, ok := value.(RoutingTreeStatus)
if !ok {
return fmt.Errorf("cannot set status type %#v, not of type RoutingTreeStatus", value)
}
o.Status = cast
return nil
default: default:
return fmt.Errorf("subresource '%s' does not exist", name) return fmt.Errorf("subresource '%s' does not exist", name)
} }
@@ -220,6 +233,7 @@ func (o *RoutingTree) DeepCopyInto(dst *RoutingTree) {
dst.TypeMeta.Kind = o.TypeMeta.Kind dst.TypeMeta.Kind = o.TypeMeta.Kind
o.ObjectMeta.DeepCopyInto(&dst.ObjectMeta) o.ObjectMeta.DeepCopyInto(&dst.ObjectMeta)
o.Spec.DeepCopyInto(&dst.Spec) o.Spec.DeepCopyInto(&dst.Spec)
o.Status.DeepCopyInto(&dst.Status)
} }
// Interface compliance compile-time check // Interface compliance compile-time check
@@ -291,3 +305,15 @@ func (s *RoutingTreeSpec) DeepCopy() *RoutingTreeSpec {
func (s *RoutingTreeSpec) DeepCopyInto(dst *RoutingTreeSpec) { func (s *RoutingTreeSpec) DeepCopyInto(dst *RoutingTreeSpec) {
resource.CopyObjectInto(dst, s) resource.CopyObjectInto(dst, s)
} }
// DeepCopy creates a full deep copy of RoutingTreeStatus
func (s *RoutingTreeStatus) DeepCopy() *RoutingTreeStatus {
cpy := &RoutingTreeStatus{}
s.DeepCopyInto(cpy)
return cpy
}
// DeepCopyInto deep copies RoutingTreeStatus into another RoutingTreeStatus object
func (s *RoutingTreeStatus) DeepCopyInto(dst *RoutingTreeStatus) {
resource.CopyObjectInto(dst, s)
}
@@ -3,43 +3,42 @@
package v0alpha1 package v0alpha1
// +k8s:openapi-gen=true // +k8s:openapi-gen=true
type ExamplestatusOperatorState struct { type RoutingTreestatusOperatorState struct {
// lastEvaluation is the ResourceVersion last evaluated // lastEvaluation is the ResourceVersion last evaluated
LastEvaluation string `json:"lastEvaluation"` LastEvaluation string `json:"lastEvaluation"`
// state describes the state of the lastEvaluation. // state describes the state of the lastEvaluation.
// It is limited to three possible states for machine evaluation. // It is limited to three possible states for machine evaluation.
State ExampleStatusOperatorStateState `json:"state"` State RoutingTreeStatusOperatorStateState `json:"state"`
// descriptiveState is an optional more descriptive state field which has no requirements on format // descriptiveState is an optional more descriptive state field which has no requirements on format
DescriptiveState *string `json:"descriptiveState,omitempty"` DescriptiveState *string `json:"descriptiveState,omitempty"`
// details contains any extra information that is operator-specific // details contains any extra information that is operator-specific
Details map[string]interface{} `json:"details,omitempty"` Details map[string]interface{} `json:"details,omitempty"`
} }
// NewExamplestatusOperatorState creates a new ExamplestatusOperatorState object. // NewRoutingTreestatusOperatorState creates a new RoutingTreestatusOperatorState object.
func NewExamplestatusOperatorState() *ExamplestatusOperatorState { func NewRoutingTreestatusOperatorState() *RoutingTreestatusOperatorState {
return &ExamplestatusOperatorState{} return &RoutingTreestatusOperatorState{}
} }
// +k8s:openapi-gen=true // +k8s:openapi-gen=true
type ExampleStatus struct { type RoutingTreeStatus struct {
LastObservedGeneration int64 `json:"lastObservedGeneration"`
// operatorStates is a map of operator ID to operator state evaluations. // operatorStates is a map of operator ID to operator state evaluations.
// Any operator which consumes this kind SHOULD add its state evaluation information to this field. // Any operator which consumes this kind SHOULD add its state evaluation information to this field.
OperatorStates map[string]ExamplestatusOperatorState `json:"operatorStates,omitempty"` OperatorStates map[string]RoutingTreestatusOperatorState `json:"operatorStates,omitempty"`
// additionalFields is reserved for future use // additionalFields is reserved for future use
AdditionalFields map[string]interface{} `json:"additionalFields,omitempty"` AdditionalFields map[string]interface{} `json:"additionalFields,omitempty"`
} }
// NewExampleStatus creates a new ExampleStatus object. // NewRoutingTreeStatus creates a new RoutingTreeStatus object.
func NewExampleStatus() *ExampleStatus { func NewRoutingTreeStatus() *RoutingTreeStatus {
return &ExampleStatus{} return &RoutingTreeStatus{}
} }
// +k8s:openapi-gen=true // +k8s:openapi-gen=true
type ExampleStatusOperatorStateState string type RoutingTreeStatusOperatorStateState string
const ( const (
ExampleStatusOperatorStateStateSuccess ExampleStatusOperatorStateState = "success" RoutingTreeStatusOperatorStateStateSuccess RoutingTreeStatusOperatorStateState = "success"
ExampleStatusOperatorStateStateInProgress ExampleStatusOperatorStateState = "in_progress" RoutingTreeStatusOperatorStateStateInProgress RoutingTreeStatusOperatorStateState = "in_progress"
ExampleStatusOperatorStateStateFailed ExampleStatusOperatorStateState = "failed" RoutingTreeStatusOperatorStateStateFailed RoutingTreeStatusOperatorStateState = "failed"
) )

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