Skip to content

HyperDX Dashboard Provisioner#190

Open
ZeynelKoca wants to merge 1 commit into
ClickHouse:mainfrom
ZeynelKoca:inject-json-dashboards
Open

HyperDX Dashboard Provisioner#190
ZeynelKoca wants to merge 1 commit into
ClickHouse:mainfrom
ZeynelKoca:inject-json-dashboards

Conversation

@ZeynelKoca

@ZeynelKoca ZeynelKoca commented Mar 13, 2026

Copy link
Copy Markdown

Summary

  • Add dashboard provisioning via k8s-sidecar that discovers ConfigMaps labeled hyperdx.io/dashboard: "true" across all namespaces
  • k8s-sidecar writes dashboard JSON to a shared volume, HyperDX upserts them natively
  • Dashboards matched by name for idempotency (update existing, create new, never delete)
  • Two ways to provide dashboards: inline in values or via labeled ConfigMaps from any namespace

Design decisions

  • k8s-sidecar + native HyperDX provisioner: Sidecar handles ConfigMap discovery (same pattern as Grafana). HyperDX handles MongoDB upsert natively
  • ClusterRole: Needed for cross-namespace ConfigMap discovery.

Dependencies

@changeset-bot

changeset-bot Bot commented Mar 13, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: d0f332d

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
helm-charts Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@CLAassistant

CLAassistant commented Mar 13, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@ZeynelKoca

Copy link
Copy Markdown
Author

Implements feature request #170

@ZeynelKoca ZeynelKoca force-pushed the inject-json-dashboards branch from 0243f23 to 752d6a5 Compare March 13, 2026 12:36
@heiba

heiba commented Mar 22, 2026

Copy link
Copy Markdown

@dhable Can we please look at this PR and see how we can progress it ?

@ZeynelKoca ZeynelKoca force-pushed the inject-json-dashboards branch 2 times, most recently from 7d182d9 to 64af4b1 Compare March 22, 2026 23:56
@ZeynelKoca

Copy link
Copy Markdown
Author

As per PR description, I redesigned the initial implementation to handle upsert behavior natively through hyperdx (same pattern as Grafana). This PR is dependent on hyperdxio/hyperdx#1962

@ZeynelKoca ZeynelKoca force-pushed the inject-json-dashboards branch 3 times, most recently from 04bbee1 to 5714065 Compare April 3, 2026 16:02
@dhable dhable self-requested a review April 6, 2026 18:34

@dhable dhable left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for following up the feature change with a helm change as well. Great to keep these two up-to-date.

I think the need to provision RBAC roles and scan for tagged config maps is more than our typical users would expect from an application install. Using the default ConfigMap functionality to mount the dashboard data as a file would avoid the need for an additional service account, RBAC, etc.

Comment thread charts/clickstack/values.yaml
Comment thread charts/clickstack/templates/hyperdx/deployment.yaml Outdated
@ZeynelKoca ZeynelKoca force-pushed the inject-json-dashboards branch from bd006b9 to a437052 Compare April 7, 2026 18:56
@ZeynelKoca

Copy link
Copy Markdown
Author

Thank you for following up the feature change with a helm change as well. Great to keep these two up-to-date.

I think the need to provision RBAC roles and scan for tagged config maps is more than our typical users would expect from an application install. Using the default ConfigMap functionality to mount the dashboard data as a file would avoid the need for an additional service account, RBAC, etc.

No worries, the dashboard provisioning would be really nice for us as we're planning to go into production with clickstack soon and implementing missing features is faster than creating an issue 😄

Ready for another review!

@ZeynelKoca ZeynelKoca requested a review from dhable April 7, 2026 19:03
@ZeynelKoca

Copy link
Copy Markdown
Author

@dhable Gentle bump. Happy to hear your thoughts on the implementation

@tincann

tincann commented May 6, 2026

Copy link
Copy Markdown

@dhable it would be great if this feature could be released! Very handy.

kodiakhq Bot pushed a commit to hyperdxio/hyperdx that referenced this pull request May 19, 2026
## Summary

Add a `provision-dashboards` task that reads `.json` files from a directory and upserts dashboards into MongoDB, following the existing task system pattern (same as `check-alerts`).

Provisioned dashboards are flagged with `provisioned: true` so they never overwrite user-created dashboards with the same name. Files are validated against `DashboardWithoutIdSchema`. Removing a file does not delete the dashboard (safe by default, same as Grafana). The task is deployment-agnostic: it reads from a directory, regardless of how files get there.

When `DASHBOARD_PROVISIONER_DIR` is set, `entry.prod.sh` automatically starts the task as an additional process alongside the API, App, and check-alerts.

**Note:** Users can currently edit provisioned dashboards through the UI, but changes will be overwritten on the next sync cycle. Grafana handles this by blocking saves on provisioned dashboards. Adding a similar guard would be a good follow-up to improve UX.

| Variable | Required | Default | Description |
|----------|----------|---------|-------------|
| `DASHBOARD_PROVISIONER_DIR` | Yes |  | Directory to read `.json` files from |
| `DASHBOARD_PROVISIONER_TEAM_ID` | No* |  | Scope to a specific team ID |
| `DASHBOARD_PROVISIONER_ALL_TEAMS` | No* | `false` | Set to `true` to provision to all teams |

\*One of `DASHBOARD_PROVISIONER_TEAM_ID` or `DASHBOARD_PROVISIONER_ALL_TEAMS=true` is required.

### How to test locally or on Vercel

1. Create a directory with a dashboard JSON file:
   ```bash
   mkdir /tmp/dashboards
   echo '{"name":"Test Dashboard","tiles":[],"tags":[]}' > /tmp/dashboards/test.json
2. Run the task:
DASHBOARD_PROVISIONER_DIR=/tmp/dashboards DASHBOARD_PROVISIONER_ALL_TEAMS=true \
  ./packages/api/bin/hyperdx task provision-dashboards
3. Verify the dashboard appears in the UI
4. Modify the JSON file, run again, verify it updates
5. Delete the JSON file, run again, verify the dashboard persists

References

- Related PRs: ClickHouse/ClickStack-helm-charts#190
@ZeynelKoca ZeynelKoca force-pushed the inject-json-dashboards branch from a437052 to b577121 Compare June 30, 2026 09:15
@ZeynelKoca ZeynelKoca requested a review from a team as a code owner June 30, 2026 09:15
@github-actions

github-actions Bot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Deep Review

✅ No critical issues found.

The dashboard-provisioning feature is well-constructed and unusually well-tested (~950 lines of new helm-unittest coverage). RBAC is safe-by-default: dashboards.enabled=false renders nothing; enabling with namespaces: [] produces only a namespaced Role/RoleBinding; cluster-wide access requires an explicit, case-sensitive [ALL] sentinel that validateDashboards refuses to combine with named namespaces. Watched scope (NAMESPACE env) and granted scope (Role vs ClusterRole) derive from the same helpers, so they cannot drift. No secrets are introduced.

🟡 P2 — recommended

  • charts/clickstack/templates/hyperdx/deployment.yaml:395 — The dashboard-watcher is a plain container with no readiness probe, so when it CrashLoops (e.g. rbac.create=false with no out-of-band grant → 403) the pod goes NotReady and the healthy HyperDX app is dropped from its Service endpoints — an app-wide availability regression triggered by an auxiliary component.
    • Fix: Run the watcher as a native sidecar (initContainers entry with restartPolicy: Always) so its failures don't gate app readiness; this also removes the first-boot ordering race where the app reads an empty /dashboards before the watcher populates it.
    • reliability
🔵 P3 nitpicks (4)
  • charts/clickstack/templates/hyperdx/deployment.yaml:397 — The dashboard-watcher container omits imagePullPolicy while the app container sets one, an inconsistency that leans on the cluster default for the pinned tag.

    • Fix: Add an imagePullPolicy to the watcher container to match the app container.
  • charts/clickstack/templates/_helpers.tpl:122validateDashboards is invoked only from deployment.yaml, and dashboardsClusterWide uses exact has "ALL" while validation trims/uppercases, so rendering an individual dashboard template in isolation (e.g. helm template --show-only templates/hyperdx/dashboard-provisioner-rbac.yaml) bypasses validation and can emit a RoleBinding targeting an invalid namespace; a full helm install always renders deployment.yaml so validation fires normally.

    • Fix: Include clickstack.hyperdx.validateDashboards at the top of dashboard-provisioner-rbac.yaml and dashboard-configmap.yaml too, and derive dashboardsClusterWide from trimmed values so the sentinel check matches validation.
    • correctness, adversarial
  • charts/clickstack/values.yaml:1464 — The default watcher memory limit (64Mi) is likely to OOMKill under namespaces: [ALL] cluster-wide discovery on large clusters; the risk is noted in a comment but the shipped default is unchanged.

    • Fix: Consider raising the default memory limit when cluster-wide, or emit a NOTES hint to bump resources on the [ALL] path.
  • charts/clickstack/tests/dashboard-provisioner_test.yaml:855 — Coverage gaps for new branches: serviceAccount.create: true combined with dashboards, rbac.create: false combined with [ALL]/multi-namespace scope, and no single test tying the watcher NAMESPACE env to the emitted RoleBinding namespace set for one value set.

    • Fix: Add these cases so a future edit that desyncs granted scope from watched scope, or the explicit-create SA branch, is caught.
    • testing, correctness

Reviewers (7): correctness, security, reliability, adversarial, testing, maintainability, project-standards.

Testing gaps:

  • helm-unittest cannot verify the sidecar actually discovers ConfigMaps or that the app consumes DASHBOARD_PROVISIONER_* env at runtime — an integration-tests/ suite installing with dashboards enabled and RBAC scoped to a second namespace would close this.
  • No test asserts pod-level Ready behavior when the watcher CrashLoops (rbac.create=false path).

@ZeynelKoca ZeynelKoca force-pushed the inject-json-dashboards branch 7 times, most recently from c4c6715 to c86387f Compare June 30, 2026 14:43
@ZeynelKoca ZeynelKoca force-pushed the inject-json-dashboards branch 7 times, most recently from a5bf038 to f43379e Compare July 1, 2026 11:50
k8s-sidecar watches ConfigMaps labeled "hyperdx.io/dashboard: true"
across all namespaces and writes dashboard JSON to a shared volume.
HyperDX reads and upserts them natively via file-based provisioner.

Requires hyperdxio/hyperdx#1962
@ZeynelKoca ZeynelKoca force-pushed the inject-json-dashboards branch from f43379e to d0f332d Compare July 1, 2026 12:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants