Grafana: stock upstream server + lunar-dashboards deploy tool#76
Grafana: stock upstream server + lunar-dashboards deploy tool#76idelvall wants to merge 15 commits into
Conversation
Run stock grafana/grafana:13.0.3 instead of a Lunar-built/derived image; install plugins/datasources/dashboards over the Grafana API via the renamed lunar-dashboards deploy tool (post-install/upgrade hook Job + reconverge sidecar). - values: grafana.image -> grafana/grafana:13.0.3; add grafana.dashboardsDeploy (enabled/blocking/reconvergeSidecar/backoffLimit/image/dbPassword) and grafana.persistence (optional PVC, off by default). - grafana-deployment: stock server env only (GF_SERVER_ROOT_URL, GF_SECURITY_ADMIN_*, GF_USERS_ALLOW_SIGN_UP); reconverge sidecar; optional PVC. - new grafana-deploy-job.yaml (non-blocking hook), grafana-db-secret.yaml (read-only grafana_user password), grafana-pvc.yaml. - hub + migrate jobs: HUB_GRAFANA_USER/PASSWORD + HUB_GRAFANA_DB_PASSWORD. - helpers: grafanaDBSecretName + grafanaDeployHubEnv. Companion to earthly/lunar#2007. Chart 2.12.0 -> 2.13.0. Co-authored-by: Cursor <cursoragent@cursor.com>
🌒 Earthly Lunar
|
Drop the optional/opt-in surface, keeping the essential deploy path: - remove grafana.persistence + grafana-pvc.yaml (PVC volume/mount/fsGroup) — the reconverge sidecar keeps the pod stateless without it - remove the blocking toggle (the deploy hook is always non-blocking) - remove the reconvergeSidecar/backoffLimit knobs (sidecar always on when dashboardsDeploy.enabled; backoffLimit hardcoded) - drop the external-Grafana chart branch (deploy Job gates on grafana.enabled + dashboardsDeploy.enabled) Kept: stock grafana/grafana, deploy hook Job, reconverge sidecar, and the Hub + grafana_user DB-role wiring. Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
There was a problem hiding this comment.
Two issues before this can land, one blocking. The pre-install/pre-upgrade migrate hook now reads a chart-generated non-hook secret, so the default fresh install (and the first upgrade to 2.13.0) fail at the hook. Separately, the deploy Job and reconverge sidecar do not actually wait for the Hub, so dashboards can silently fail to install on first install. Details inline.
Addresses the charts#76 review: - Blocking: the pre-install migrate hook read HUB_GRAFANA_DB_PASSWORD from the plain <release>-grafana-db secret, which Helm creates only after pre-install hooks complete — so a fresh install (and the first upgrade to 2.13.0) failed with CreateContainerConfigError -> DeadlineExceeded -> rollback. Drop the chart-generated grafana-db secret (+ grafanaDBSecretName helper + the dashboardsDeploy.dbPassword values) and supply the grafana_user password operator-side via hub.extraEnv, exactly like HUB_SQLAPI_PASSWORD. No chart secret means no hook-ordering dependency. - Non-blocking: deploy.sh makes a single Hub gRPC call with no internal retry, and nothing waited for the Hub, so on a fresh install the deploy raced the hub becoming Ready and dashboards silently didn't install until the next upgrade. Add a wait-for-hub grpcurl loop (reflection list) to the deploy Job's init container and the reconverge sidecar, alongside wait-for-grafana; fix the misleading backoffLimit comment. Co-authored-by: Cursor <cursoragent@cursor.com>
|
Bugbot is not enabled for your account, so this pull request was not reviewed. Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs. |
There was a problem hiding this comment.
Both concerns addressed. The chart-generated grafana-db secret is gone (HUB_GRAFANA_DB_PASSWORD now rides hub.extraEnv like HUB_SQLAPI_PASSWORD, so the pre-install migrate hook no longer references a not-yet-created secret), and the deploy Job init container plus the reconverge sidecar both wait for the Hub gRPC before deploy.sh runs. Renders clean on defaults. LGTM.
The chart comments/CHANGELOG referenced GetGrafanaDBConfig, which is not a real Hub RPC — the deploy tool (and companion earthly/lunar#2007) call GetGrafanaConnectionString (hubapi/hub.proto). Revert the never-applied rename so the chart's docs match the actual Hub API. Co-authored-by: Cursor <cursoragent@cursor.com>
|
Bugbot is not enabled for your account, so this pull request was not reviewed. Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs. |
Gate the content-deploy Job on dashboardsDeploy.enabled alone (was: also required grafana.enabled), so it runs for a customer-owned/external Grafana as well as the chart's own pod: - Internal (grafana.enabled): unchanged "direct" route — GRAFANA_URL targets the in-cluster Service and the init container waits for Grafana's API. - External (grafana.enabled=false): GRAFANA_URL is omitted and the in-cluster Grafana wait is skipped, so deploy.sh resolves the endpoint (URL + auth) from the Hub via GetGrafanaEndpoint. The operator configures the Hub for it (grafana.externalURL + HUB_GRAFANA_TOKEN or USER/PASSWORD + HUB_GRAFANA_DB_PASSWORD via hub.extraEnv). The Hub-gRPC wait stays unconditional. Docs updated in values.yaml + CHANGELOG. Co-authored-by: Cursor <cursoragent@cursor.com>
|
Bugbot is not enabled for your account, so this pull request was not reviewed. Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs. |
The grafana_user role is internal (the Hub vends its connection to the deploy tool; never user-facing), so the chart should generate its password rather than require HUB_GRAFANA_DB_PASSWORD via hub.extraEnv. Ship the password as a pre-install/pre-upgrade hook secret weighted -10 (below the migrate Job's -5) so it exists before that Job creates the role and before the hub Deployment reads it — resolving the ordering bug that made a chart-generated plain secret fail on fresh install. resource-policy: keep + a lookup guard create it once and keep it stable (the password must stay in sync with the DB role, which the content-hashed 02_grafana code package won't re-run to reset). Gated on dashboardsDeploy.enabled so external Grafana gets it too; BYO via dbPassword.secretName. Reverts the operator-supplied HUB_GRAFANA_DB_PASSWORD path. Co-authored-by: Cursor <cursoragent@cursor.com>
|
Bugbot is not enabled for your account, so this pull request was not reviewed. Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs. |
…tions HUB_SQLAPI_CONNECTION_OPTIONS and HUB_GRAFANA_DB_CONNECTION_OPTIONS default to sslmode=disable in the Hub, but sqlapi_user and grafana_user connect to the same Postgres as the hub. Set both from hub.db.connectionOptions (like the operator's OPERATOR_DB_CONNECTION_OPTIONS) so all connections share one SSL mode — the sqlapi option always, the grafana option under dashboardsDeploy.enabled. Co-authored-by: Cursor <cursoragent@cursor.com>
|
Bugbot is not enabled for your account, so this pull request was not reviewed. Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs. |
dchw
left a comment
There was a problem hiding this comment.
We will need a version bump? Unsure how that fits with our new release process.
I think this update warrants a major version bump?
| - name: kiosk-config | ||
| mountPath: /etc/nginx/conf.d | ||
| {{- if .Values.grafana.dashboardsDeploy.enabled }} | ||
| - name: dashboards-reconverge |
There was a problem hiding this comment.
Wonder if its worth adding a readiness probe here to prevent grafana from getting traffic unless successfully provisioned?
There was a problem hiding this comment.
AI-generated (Opus 4.8) posted at request of @idelvall.
Going to pass on this one. The provisioning path is deliberately non-blocking — a failed provision is logged but never blocks or rolls back the upgrade. A readiness gate inverts that: a provisioning hiccup (or a Hub blip on a pod restart) would pull Grafana itself out of the Service, which is worse than briefly serving an un-provisioned Grafana — and that empty window is only until the post-install Job / reconverge sidecar finish (seconds). We are OK with a briefly-empty Grafana. Happy to revisit as an opt-in, first-provision-only gate if it ever actually bites.
…ning) - Replace grafana.enabled + grafana.provisioning.enabled with a single grafana.mode = chart | external | off (infra renders in chart mode; dashboards provision when mode != off); fail fast on the removed keys. - Unify grafana.externalURL -> grafana.url and grafana.admin -> grafana.auth (+ tokenKey). In external mode the chart wires url + auth into the Hub (HUB_GRAFANA_URL_BASE + HUB_GRAFANA_TOKEN or USER/PASSWORD) — no hub.extraEnv. - Standardize naming on "provisioning" (value, Job, provision-reconverge sidecar, helper). - Add securityContext + resources to the provision Job and reconverge sidecar; securityContext to the kiosk sidecar. - DRY wait-for-hub/grafana and the image ref into helpers. - provision Job backoffLimit 6 -> 2 (match migrate Job). - Document why grafana_user's DB password is chart-generated. - Chart 2.13.0 -> 3.0.0; update CHANGELOG + README. Co-authored-by: Cursor <cursoragent@cursor.com>
|
Bugbot is not enabled for your account, so this pull request was not reviewed. Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs. |
|
AI-generated (Opus 4.8) posted at request of @idelvall. Re: the version bump / "how it fits the new release process" — bumped the chart to 3.0.0 (major). It is a breaking values-shape change (
|
Co-authored-by: Cursor <cursoragent@cursor.com> # Conflicts: # charts/lunar/CHANGELOG.md # charts/lunar/Chart.yaml # charts/lunar/values.yaml
|
Bugbot is not enabled for your account, so this pull request was not reviewed. Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs. |
Co-authored-by: Cursor <cursoragent@cursor.com> # Conflicts: # charts/lunar/CHANGELOG.md # charts/lunar/Chart.yaml # charts/lunar/values.yaml
|
Bugbot is not enabled for your account, so this pull request was not reviewed. Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs. |
The chart now runs stock upstream grafana/grafana, so the release bump must not rewrite grafana.image.tag to a lunar version. Chart and hub versions stay in lockstep — Chart.yaml version plus the hub/operator/init/sidecar tags still track the release version; grafana is left untouched. Co-authored-by: Cursor <cursoragent@cursor.com>
|
Bugbot is not enabled for your account, so this pull request was not reviewed. Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs. |
|
Bugbot is not enabled for your account, so this pull request was not reviewed. Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs. |
Merging this branch must not change Chart.yaml's version, or chart-releaser would publish 3.0.0 before the matching lunar-hub 3.0.0 / lunar-dashboards images exist. The lunar-hub 3.0.0 release auto-dispatches bump-and-pr on charts main, which sets the chart version (and image tags) to 3.0.0 in lockstep — after the images are published. The CHANGELOG 3.0.0 entry stays ready and becomes that release's notes. Co-authored-by: Cursor <cursoragent@cursor.com>
Goal
Run stock upstream Grafana (
grafana/grafana:13.1.0) instead of a Lunar-built/derived image, and install Lunar's plugins/datasources/dashboards over the Grafana HTTP API with a newlunar-dashboardsdeploy tool. This drops the AGPL and maintenance burden of shipping a modified Grafana, and lets the same tool target both the chart's own Grafana pod and a customer-owned/external Grafana.Context and problem
The chart shipped a bespoke
lunar-grafanaimage with plugins, dashboards and a theme baked in, plus an entrypoint wired to Postgres and the Hub. That couples us to a modified Grafana (AGPL implications, ongoing maintenance, larger image) and only ever works for the in-cluster pod. Companion to earthly/lunar#2007 (design: earthly/plans#58), which adds the Hub RPCs (GetGrafanaEndpoint,GetGrafanaConnectionString), the02_grafanagrafana_usermigration, and thelunar-dashboardsimage. Docs follow-up: earthly/lunar#2027.Changes
Stock Grafana pod
grafana.image->grafana/grafana:13.1.0. The pod runs stock Grafana with onlyGF_SERVER_ROOT_URL,GF_SECURITY_ADMIN_*andGF_USERS_ALLOW_SIGN_UPset; dropped the baked plugins/dashboards/theme and thePOSTGRES_*/LUNAR_HUB_*env the old entrypoint needed. The kiosk sidecar (browser view) is unchanged.lunar-dashboardsdeploy tool (grafana.dashboardsDeploy)deploy.sh) that installs plugins/datasources/dashboards over the Grafana API, resolving the target Grafana endpoint + a read-only DB connection from the Hub over gRPC (so it needs no Grafana/DB args in the chart).grafana-deploy-job.yaml):post-install/post-upgrade, gated ondashboardsDeploy.enabled. Targets the chart's own pod directly (in-cluster Service) or a customer-owned/external Grafana (grafana.enabled=false; endpoint + auth resolved from the Hub). An init container waits for the Hub's gRPC (and, for the chart pod, Grafana's API) so the deploy doesn't race the Hub becoming Ready on a fresh install. Non-blocking: a failed deploy is logged but never fails/rolls back the Hub upgrade.localhost:3000.Hub wiring for the deploy tool
grafana_userDB role for the datasource: its password is chart-generated - apre-install/pre-upgradehook secret weighted before the migrate Job (-10<-5) withhelm.sh/resource-policy: keep, so it exists before the migrate Job creates the role and stays stable across upgrades (BYO viadashboardsDeploy.dbPassword.secretName). The migrate Job creates the role WITH it on a fresh DB, and the Hub vends the connection viaGetGrafanaConnectionString. It's internal (never user-facing), so no operator config is needed.HUB_GRAFANA_USER/HUB_GRAFANA_PASSWORD) viaGetGrafanaEndpoint.grafanaDeployHubEnv(LUNAR_HUB_*) shared by the deploy Job and the reconverge sidecar.Chart metadata
Chart.yaml2.12.0 -> 2.13.0; CHANGELOG entry + upgrade note.Requires / notes
GetGrafanaEndpoint/GetGrafanaConnectionStringRPCs + the02_grafanagrafana_usermigration) and a publishedghcr.io/earthly/lunar-dashboardsat a matching tag (dashboardsDeploy.image.tagdefaults tohub.image.tag).grafana_userDB password is chart-generated - no operator config required. For an external Grafana, setgrafana.externalURL(->HUB_GRAFANA_URL_BASE) andHUB_GRAFANA_TOKEN(orHUB_GRAFANA_USER+HUB_GRAFANA_PASSWORD) viahub.extraEnv, and ensure the external Grafana can reach the Hub's Postgres.grafana/grafana:13.1.0andghcr.io/earthly/lunar-dashboardstoo.Test plan
helm lint.helm templaterenders on: defaults (chart pod),grafana.enabled=false+dashboardsDeploy.enabled=true(external),dashboardsDeploy.enabled=false, and a BYOdashboardsDeploy.dbPassword.secretName.