Replace transmission-exporter with homegrown Python exporter #283

Merged
eblume merged 2 commits from feature/transmission-exporter-python into main 2026-03-04 21:55:01 -08:00
Owner

Summary

  • Replace unmaintained metalmatze/transmission-exporter:master sidecar with a homegrown Python exporter
  • Uses prometheus_client + transmission-rpc with collect-on-scrape pattern (fresh metrics per scrape, no stale labels)
  • Same metric names so existing Grafana Transmission dashboard works unchanged
  • Container built with uv for dependency management, follows grafana-sidecar Dockerfile pattern

Changes

  • New: containers/transmission-exporter/exporter.py — single-file exporter (~130 lines)
  • New: containers/transmission-exporter/Dockerfile — multi-stage Alpine build with uv
  • Modified: argocd/manifests/torrent/deployment.yaml — swap sidecar image reference
  • Modified: argocd/manifests/torrent/kustomization.yaml — add image tag entry
  • Modified: service-versions.yaml — add transmission-exporter entry

Deployment and Testing

  • Build container: mise run container-build-and-release transmission-exporter
  • Update kustomization.yaml newTag with build SHA
  • Branch deploy: argocd app set torrent --revision feature/transmission-exporter-python && argocd app sync torrent
  • Verify metrics: kubectl -n torrent --context=minikube-indri port-forward svc/transmission 19091:19091 then curl localhost:19091/metrics | grep transmission_
  • Verify Grafana Transmission dashboard panels populate
  • After merge: argocd app set torrent --revision main && argocd app sync torrent
## Summary - Replace unmaintained `metalmatze/transmission-exporter:master` sidecar with a homegrown Python exporter - Uses `prometheus_client` + `transmission-rpc` with collect-on-scrape pattern (fresh metrics per scrape, no stale labels) - Same metric names so existing Grafana Transmission dashboard works unchanged - Container built with `uv` for dependency management, follows `grafana-sidecar` Dockerfile pattern ## Changes - **New:** `containers/transmission-exporter/exporter.py` — single-file exporter (~130 lines) - **New:** `containers/transmission-exporter/Dockerfile` — multi-stage Alpine build with uv - **Modified:** `argocd/manifests/torrent/deployment.yaml` — swap sidecar image reference - **Modified:** `argocd/manifests/torrent/kustomization.yaml` — add image tag entry - **Modified:** `service-versions.yaml` — add transmission-exporter entry ## Deployment and Testing - [ ] Build container: `mise run container-build-and-release transmission-exporter` - [ ] Update kustomization.yaml newTag with build SHA - [ ] Branch deploy: `argocd app set torrent --revision feature/transmission-exporter-python && argocd app sync torrent` - [ ] Verify metrics: `kubectl -n torrent --context=minikube-indri port-forward svc/transmission 19091:19091` then `curl localhost:19091/metrics | grep transmission_` - [ ] Verify Grafana Transmission dashboard panels populate - [ ] After merge: `argocd app set torrent --revision main && argocd app sync torrent`
Swap out docker.io/metalmatze/transmission-exporter:master for a minimal
Python exporter using prometheus_client and transmission-rpc with the
collect-on-scrape pattern. Same metric names so Grafana dashboards work
unchanged. Uses uv for dependency management in the container build.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@ -12,2 +12,4 @@
- name: registry.ops.eblu.me/blumeops/transmission
newTag: v4.1.1-r1-ab34cbd
- name: registry.ops.eblu.me/blumeops/transmission-exporter
newTag: v1.0.0
Author
Owner

just checking, you probably know this already, but you'll need to include the sha of the commit as well once this is built.

just checking, you probably know this already, but you'll need to include the sha of the commit as well once this is built.
eblume marked this conversation as resolved
@ -0,0 +3,4 @@
ARG CONTAINER_APP_VERSION=1.0.0
FROM python:3.12-alpine3.22 AS base
Author
Owner

Let's use the latest stable python and alpine if possible, no reason to start out behind the curve on this greenfield project

Let's use the latest stable python and alpine if possible, no reason to start out behind the curve on this greenfield project
@ -0,0 +9,4 @@
WORKDIR /app
COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv
COPY exporter.py .
RUN uv venv .venv && \
Author
Owner

I actually dont think you even need to uv pip install anything or venv anything. Just use a uv run --script shebang on the python script, uv will take care of the rest at runtime

I actually dont think you even need to uv pip install anything or venv anything. Just use a uv run --script shebang on the python script, uv will take care of the rest at runtime
@ -0,0 +1,154 @@
# /// script
Author
Owner

yes as mentioned above, please use a shebang line like the mise-tasks use to run uv run --script here

yes as mentioned above, please use a shebang line like the mise-tasks use to run `uv run --script` here
@ -0,0 +2,4 @@
# requires-python = ">=3.12"
# dependencies = [
# "prometheus-client>=0.24,<1.0",
# "transmission-rpc>=7.0,<8.0",
Author
Owner

and for these deps, either unpin them or at least make sure we're using the most recent versions (that will work).

and for these deps, either unpin them or at least make sure we're using the most recent versions (that will work).
@ -0,0 +147,4 @@
# Block forever
import threading
threading.Event().wait()
Author
Owner

wait really, is this idiomatic for transmission's start_http_server func? You need to just block the caller forever... not like await an async or poll an event loop or something?

wait really, is this idiomatic for transmission's start_http_server func? You need to just block the caller forever... not like await an async or poll an event loop or something?
eblume marked this conversation as resolved
- Use #!/usr/bin/env -S uv run --script shebang with PEP 723 metadata
- Drop venv/pip multi-stage build; uv handles deps at runtime
- Upgrade to python:3.13-alpine3.23
- Unpin dependency versions (no upper bounds)
- Replace threading.Event().wait() with wsgiref serve_forever()

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
eblume merged commit f2704b26da into main 2026-03-04 21:55:01 -08:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
eblume/blumeops!283
No description provided.