feat(grafana): auto-generate plugin-sync sidecar in register_plugin()
- Dominant language
- Starlark
- Stars
- 0
- Forks
- 0
- PR merge metrics
- No merged PRs in 30d
Description
## Summary
Every plugin repo using `register_plugin()` with a named-volume `dist` spec currently has to manually define an identical plugin-sync sidecar service in its `cc-docker-compose.yaml`. This is ~20 lines of boilerplate YAML that gets copy-pasted across repos. `register_plugin()` could auto-generate this service, eliminating the duplication.
## Current Pattern (repeated in every plugin repo)
Each plugin repo defines an Alpine sidecar in its compose file:
```yaml
services:
slo-plugin-sync:
image: alpine:latest
volumes:
- slo-plugin-dist:/dist
- ./dist:/src:ro
command:
- sh
- -c
- |
echo "Waiting for plugin build (plugin.json)..."
while [ ! -f /src/plugin.json ]; do sleep 2; done
echo "Plugin found, syncing files..."
cp -r /src/* /dist/
echo "Plugin synced successfully"
touch /tmp/healthy
echo "Watching for changes..."
while true; do sleep 5; cp -r /src/* /dist/ 2>/dev/null || true; done
healthcheck:
test: ['CMD', 'test', '-f', '/tmp/healthy']
interval: 5s
timeout: 3s
retries: 30
start_period: 300s
volumes:
slo-plugin-dist:
```
And then registers the plugin referencing the volume:
```python
grafana.register_plugin([{
'name': 'grafana-slo-app',
'dist': 'slo-plugin-dist:/var/lib/grafana/plugins/grafana-slo-app',
'depends_on': ['slo-plugin-sync'],
}])
```
This exact pattern is already duplicated in at least `grafana/slo` and `grafana/service-model` (byte-for-byte identical logic, just different volume/service names).
## Proposed Enhancement
When `register_plugin()` sees a named-volume `dist` spec (i.e., `volume-name:/path`), it could auto-generate the sync sidecar service, the named volume, and the `depends_on` entry. The plugin repo would only need:
```python
grafana.register_plugin([{
'name': 'grafana-slo-app',
'dist': 'slo-plugin-dist:/var/lib/grafana/plugins/grafana-slo-app',
'sync_source': './dist', # host path to sync from
}])
```
`register_plugin()` would then emit compose overrides containing:
1. A `{name}-plugin-sync` service definition (the Alpine sidecar)
2. The named volume declaration
3. A `depends_on` with `condition: service_healthy` on Grafana
4. The existing volume mount + provisioning file logic
### Why the sidecar exists
Docker Compose doesn't allow populating a named volume from a host bind-mount at startup. The sidecar bridges `./dist` (bind-mount) to the named volume that Grafana mounts. It also provides a 5-second polling loop for hot-reload during development.
### Opt-out
Repos with custom sync needs could still define their own sidecar and omit `sync_source`, falling back to today's behavior.
## Benefits
- Eliminates copy-paste boilerplate across plugin repos
- Centralizes the sync logic so improvements (e.g., `inotifywait` instead of polling, better error handling) propagate to all consumers
- New plugin repos adopting compose_composer don't need to understand or copy the sidecar pattern
- Reduces the surface area for subtle bugs (e.g., missing healthcheck, wrong start_period)
## Context
- `grafana/slo` cc-compose.yaml: `slo-plugin-sync` service
- `grafana/service-model` cc-docker-compose.yaml: `servicemodel-plugin-sync` service
- Both are functionally identical
Contributor guide
Research direction
Start at register_plugin() and compare its current compose override and provisioning behavior with the sidecars in grafana/slo cc-compose.yaml and grafana/service-model cc-docker-compose.yaml. Trace how named-volume dist specs and depends_on are emitted. Done means sync_source generates the sidecar, volume, health-gated dependency, and existing mounts while omitting it when sync_source is absent.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- docker-compose, grafana
- Domain
- devops, infrastructure
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100