feat(grafanactl): add scratch folder support for user-writable dashboards - #276
Open
mmazur wants to merge 2 commits into
Open
feat(grafanactl): add scratch folder support for user-writable dashboards#276mmazur wants to merge 2 commits into
mmazur wants to merge 2 commits into
Conversation
…ards Add a "scratchFolders" config option that creates Grafana folders where Viewers get Edit permission, allowing them to create/save/delete dashboards. Dashboards are auto-deleted after a configurable maxAge (based on creation time). Empty subfolders are cleaned up recursively. Cleanup errors (dashboard deletion, folder deletion, permission updates) are logged as warnings and never fail the pipeline. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
mmazur
force-pushed
the
scratchpad-folder
branch
from
July 28, 2026 12:03
d093b6a to
727e82e
Compare
Track which dashboards were deleted during expiry and exclude them from the folder dashboard count, so subfolders emptied by expiry are cleaned up immediately rather than requiring a second sync cycle. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
Pull request overview
Adds “scratch folder” support to grafanactl sync dashboards so users can create/edit dashboards in designated Grafana folders that are automatically permissioned and periodically cleaned up (expired dashboards removed; empty subfolders deleted leaf-first).
Changes:
- Introduces
scratchFoldersin the observability config (name,maxAge) with duration parsing/validation. - Extends the Grafana client wrapper with folder permission, folder search, and folder deletion operations.
- Implements scratch-folder sync: ensure folder exists, set Viewer→Edit permissions, delete expired dashboards (including in subfolders), and recursively delete empty subfolders; includes unit tests and injectable clock.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| tools/grafanactl/internal/grafana/syncer.go | Injects a clock and wires scratch-folder sync into the main dashboard sync flow. |
| tools/grafanactl/internal/grafana/scratch.go | Implements scratch-folder creation/permissioning and expiry/cleanup logic. |
| tools/grafanactl/internal/grafana/scratch_test.go | Adds unit tests covering scratch-folder behavior, edge cases, and error handling. |
| tools/grafanactl/internal/grafana/client.go | Adds folder permission/search/delete helpers needed by scratch sync. |
| tools/grafanactl/config/config.go | Adds ScratchFolder config type and maxAge parsing/validation. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
https://redhat.atlassian.net/browse/AROSLSRE-1631
Summary
scratchFoldersconfig option tografana-dashboardsin the observability configgrafanactl sync dashboards, scratch folders are created (or found), Viewer role gets Edit permission, and dashboards older thanmaxAgeare auto-deleted based on creation timeDetails
Config example:
New/modified files:
config/config.go—ScratchFoldertype withMaxAge()duration parserinternal/grafana/client.go—GetFolderPermissions,UpdateFolderPermissions,SearchFolders,DeleteFolderByUIDinternal/grafana/syncer.go— Injectable clock, callssyncScratchFoldersfromSync()internal/grafana/scratch.go— Scratch folder sync logicinternal/grafana/scratch_test.go— 20 unit testsTesting
Tested end-to-end against a personal Azure Managed Grafana instance (
mmazurtesting) deployed viamake pipeline/Grafanawith a config override. All tests run usinggrafanactl sync dashboardspointed at the test instance.GET /api/foldersand permissions showed Viewer=Edit, Editor=Edit, Admin=Admin viaGET /api/folders/<uid>/permissions. ✅maxAge: 1sinobservability.yaml, waited 10 seconds, ran sync. Log showed "Deleting expired scratch dashboard" with the correct title and UID. Verified dashboard gone via API. ✅maxAge: 168h, created a fresh dashboard, ran sync immediately. Log showed "Scratch dashboard not expired". Dashboard confirmed still present. ✅GET /api/searchbefore and after scratch sync operations. All non-scratch folders (Azure Managed Prometheus, SRE, infra, etc.) retained their exact dashboard counts throughout all test runs. ✅POST /api/folderswithparentUid), added a dashboard, setmaxAge: 1s, waited 10 seconds, ran sync. Log showed "Deleting expired scratch dashboard" for the subfolder dashboard. ✅maxAge: 168h. Log showed "Scratch dashboard not expired", subfolder confirmed still present, no folder deletions. ✅GET /api/folders. ✅--dry-run. Log showed "DRY_RUN: Would delete expired scratch dashboard", "DRY_RUN: Would delete empty scratch subfolder", and "DRY_RUN: Would set permissions on scratch folder". Verified via API that dashboard and subfolder both still existed afterward. ✅TestSyncScratchFolders_DashboardDeleteErrorIsNonFatal,TestSyncScratchFolders_MetadataErrorIsNonFatal, andTestSyncScratchFolders_FolderDeleteErrorIsNonFatalconfirm that individual deletion failures are logged and skipped without failing the overall sync.TestSyncScratchFolders_PermissionErrorIsFatalandTestSyncScratchFolders_CreateFolderErrorIsFatalconfirm that permission and folder-creation failures are fatal. All 20 unit tests pass. ✅🤖 Generated with Claude Code