diff --git a/README.md b/README.md index 978efe7..e0dec3b 100644 --- a/README.md +++ b/README.md @@ -88,17 +88,18 @@ export VITE_OIDC_ISSUER=https://auth.example.com/application/o/manage/ export VITE_OIDC_CLIENT_ID=manage export VITE_OIDC_REDIRECT_URI=https://manage.example.com/oidc/callback export VITE_OIDC_POST_LOGOUT_REDIRECT_URI=https://manage.example.com/ -export VITE_GRAFANA_URL=https://grafana.manage.example.com -export VITE_PROMETHEUS_URL=https://prometheus.manage.example.com export MANAGE_ENCRYPTION_KEY=$(python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())") docker compose up --build ``` +> Observability services (Grafana, Prometheus, Alertmanager) are configured in +> the app on the **Services** page — no env vars for them. + Inline one-liner example: ```bash -BACKEND_APP_HOST=api.manage.example.com FRONTEND_APP_HOST=manage.example.com CERT_RESOLVER=letsencrypt VITE_OIDC_ISSUER=https://auth.example.com/application/o/manage/ VITE_OIDC_CLIENT_ID=manage VITE_OIDC_REDIRECT_URI=https://manage.example.com/oidc/callback VITE_OIDC_POST_LOGOUT_REDIRECT_URI=https://manage.example.com/ VITE_GRAFANA_URL=https://grafana.manage.example.com VITE_PROMETHEUS_URL=https://prometheus.manage.example.com docker compose up --build +BACKEND_APP_HOST=api.manage.example.com FRONTEND_APP_HOST=manage.example.com CERT_RESOLVER=letsencrypt VITE_OIDC_ISSUER=https://auth.example.com/application/o/manage/ VITE_OIDC_CLIENT_ID=manage VITE_OIDC_REDIRECT_URI=https://manage.example.com/oidc/callback VITE_OIDC_POST_LOGOUT_REDIRECT_URI=https://manage.example.com/ docker compose up --build ``` For local development, no SSH key is required unless you want to connect to remote SSH machines later: @@ -145,9 +146,9 @@ VITE_OIDC_SCOPE=openid profile email VITE_OIDC_REDIRECT_URI=https://manage.example.com/oidc/callback VITE_OIDC_POST_LOGOUT_REDIRECT_URI=https://manage.example.com/ -# Grafana / Prometheus public URLs for frontend deep-links (service adapters read URLs from service records) -VITE_GRAFANA_URL=https://grafana.manage.example.com -VITE_PROMETHEUS_URL=https://prometheus.manage.example.com +# Observability services (Grafana, Prometheus, Alertmanager) are configured in +# the app on the Services page. The only observability env var is the optional +# PROMETHEUS_ENABLED toggle (defaults on) for Manage's own /metrics endpoint. # Required: master key encrypting service secrets (API keys/tokens) at rest. # Generate one with: python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())" @@ -185,5 +186,4 @@ cd frontend && npx tsc --noEmit && npm run build - Job templates are shell-quoted. Add new templates in `backend/src/media_library_viewer_api/jobs.py`. - Root-level Docker Compose files are provided for production (`docker-compose.yml`) and local development (`docker-compose.dev.yml`), and both rely on Compose interpolation rather than `env_file` entries. They deploy **only** the backend and frontend; Manage never deploys its own observability stack (see `docker-compose.observability.yml` for an optional standalone example). - The configurable dashboard stores widget instances in the backend SQLite settings database. New installs seed default Jellyfin activity and Backups widgets automatically. -- Grafana and Prometheus widget adapters resolve URLs from service records configured in the app; `VITE_GRAFANA_URL` / `VITE_PROMETHEUS_URL` are only used for frontend deep-links. No credentials are stored in widget config; service API keys are encrypted at rest with `MANAGE_ENCRYPTION_KEY`. -- `ALERTMANAGER_URL` is optional. When unset, the Alertmanager proxy endpoints return graceful "not configured" responses instead of erroring. +- Grafana, Prometheus, and Alertmanager are configured as **service instances** in the app (Services page); their widget adapters resolve URLs from service records, and no observability URLs/credentials live in env vars. No credentials are stored in widget config; service API keys are encrypted at rest with `MANAGE_ENCRYPTION_KEY`. When no alertmanager service is configured, the alert proxy endpoints return graceful "not configured" responses. diff --git a/context.md b/context.md index 17a5e51..3449e3e 100644 --- a/context.md +++ b/context.md @@ -1,13 +1,19 @@ # Code Context -> **Status (2026-06-23):** Manage no longer deploys an observability stack. -> The root `docker-compose.yml` / `docker-compose.dev.yml` ship **only** the -> backend and frontend; Grafana, Prometheus, Loki, Alertmanager, Alloy, and Node -> Exporter were removed from them. Manage connects to **existing** instances. -> The standalone example stack lives in `docker-compose.observability.yml`. Some -> snippets below still reference the former in-compose services and are kept as -> historical context; treat `docker-compose.observability.yml` as authoritative -> for the stack layout. +> **Status (2026-06-23):** Manage no longer deploys an observability stack, +> and observability is no longer env-configured. The root `docker-compose.yml` / +> `docker-compose.dev.yml` ship **only** the backend and frontend; Grafana, +> Prometheus, Loki, Alertmanager, Alloy, and Node Exporter were removed from +> them. Manage connects to **existing** instances, and Alertmanager/Grafana/ +> Prometheus are now **service-registry instances** configured in the UI (no +> `ALERTMANAGER_URL`, `VITE_GRAFANA_URL`, `VITE_PROMETHEUS_URL`, or +> `PROMETHEUS_FILE_SD_DIR` env vars). The file-SD writer was removed; external +> Prometheus uses `http_sd_configs` against `GET /api/monitoring/prometheus-targets`. +> The standalone example stack lives in `docker-compose.observability.yml`. The +> detailed snippets below describe the **former** in-compose, env-configured +> model and are kept as historical context only; treat the service registry +> (Services page UI + `openspec/changes/observability-service-registry/`) and +> `docker-compose.observability.yml` as authoritative. ## Files Retrieved diff --git a/docs/REQUIREMENTS.md b/docs/REQUIREMENTS.md index 63c6648..252d95f 100644 --- a/docs/REQUIREMENTS.md +++ b/docs/REQUIREMENTS.md @@ -332,7 +332,7 @@ the widget/addon-pages model were removed. `MANAGE_ENCRYPTION_KEY` is now requir ## Decision Log - 2026-06-23: Made all observability integration service-registry first-class with zero service env config. Alertmanager is now a 6th service type (`integrations/alertmanager.py`) with an `active_alerts` widget, mirroring Grafana/Prometheus. The monitoring router resolves alertmanager/grafana/prometheus from service records (first-enabled-instance default, optional `?service_id=`); added `/api/monitoring/grafana-status` and `/prometheus-status` health probes. The Observability page discovers services from the registry (dropped `import.meta.env.VITE_GRAFANA_URL`) and renders health cards; the dashboard gained an `active_alerts` widget. Removed the backend `alertmanager_url`/`alertmanager_webhook_url` fields and the frontend `VITE_GRAFANA_URL`/`VITE_PROMETHEUS_URL` build args — observability services are configured in the UI only. Removed the `PROMETHEUS_FILE_SD_DIR` shared-file bridge + `write_prometheus_targets` file writer; external Prometheus now uses `http_sd_configs` against `GET /api/monitoring/prometheus-targets` (`build_node_exporter_targets` + that endpoint stay). The webhook receiver is log-only (dropped the outbound forward). The only observability env var remaining is `PROMETHEUS_ENABLED` (Manage's own `/metrics` toggle). See `openspec/changes/observability-service-registry/`. -- 2026-06-23: Removed all observability services from the root Compose files. `docker-compose.yml` and `docker-compose.dev.yml` now deploy **only** the backend and frontend; the `monitoring` network and the `prometheus`/`loki`/`alloy`/`grafana`/`alertmanager`/`node-exporter` services and their named volumes were deleted, and the `GRAFANA_APP_HOST` Traefik rule was removed. Manage connects to **existing** Grafana/Prometheus/Alertmanager instances and does not deploy them itself. The backend `alertmanager_url` default is now empty, and the `/api/monitoring/alerts` and `/alertmanager-status` endpoints return graceful "not configured" responses when `ALERTMANAGER_URL` is unset. The previous in-compose stack is preserved as an optional standalone example in `docker-compose.observability.yml` (config under `monitoring/`, documented in `docs/observability-runbooks.md`). `VITE_GRAFANA_URL`/`VITE_PROMETHEUS_URL` remain as optional frontend deep-link overrides. +- 2026-06-23: Removed all observability services from the root Compose files. `docker-compose.yml` and `docker-compose.dev.yml` now deploy **only** the backend and frontend; the `monitoring` network and the `prometheus`/`loki`/`alloy`/`grafana`/`alertmanager`/`node-exporter` services and their named volumes were deleted, and the `GRAFANA_APP_HOST` Traefik rule was removed. Manage connects to **existing** Grafana/Prometheus/Alertmanager instances and does not deploy them itself. The backend `alertmanager_url` default is now empty, and the `/api/monitoring/alerts` and `/alertmanager-status` endpoints return graceful "not configured" responses when `ALERTMANAGER_URL` is unset. The previous in-compose stack is preserved as an optional standalone example in `docker-compose.observability.yml` (config under `monitoring/`, documented in `docs/observability-runbooks.md`). (The `VITE_GRAFANA_URL`/`VITE_PROMETHEUS_URL` overrides were later removed entirely — see the service-registry entry above.) - 2026-06-17: Decommissioned the legacy Manage-side system-metric scraping. Removed the backend `MonitoringPoller` (SSH-ran `df` on every machine every 5 min into a local SQLite `monitoring_machine_actions` table), the entire `services/monitoring_actions.py` module, the `/api/monitoring/poller`, `/api/monitoring/machines/{id}/actions`, and `/api/monitoring/disk` endpoints, the `monitoring_machine_actions` table (DROP on startup), the three `monitoring_poll_*` / `monitoring_action_retention_days` config knobs, and the orphaned frontend `DiskSpaceCard` + `DiskSpace` type. System metrics are now owned exclusively by Prometheus + node_exporter + Grafana. Kept the Alertmanager proxy (`/alerts`, `/alertmanager-status`, `/alertmanager-webhook`), `/prometheus-targets`, `/machines`, the `node_exporter_*` machine fields, and the on-demand `disk_usage` job template. - 2026-06-17: Completed the web UI rework to a single design system. The frontend now uses **shadcn/ui + Tailwind CSS v4 + lucide-react** exclusively, with CSS `@theme` tokens in `src/index.css` (primary `#4f8cff`; `chart-1..5` repurposed as status/Grafana-link cues). Removed `@mui/material`, `@mui/icons-material`, `@mui/x-data-grid`, `@emotion/react`, `@emotion/styled`, `recharts`, `d3`, and the `src/theme.ts` shim. Tables moved from `@mui/x-data-grid`/AG Grid to a visibility-only TanStack `DataTable` wrapper (pagination, row selection, row click, column visibility — no sorting/resizing). Adopted the thin-dashboard observability model (no in-app charts; Alertmanager alerts + Prometheus target health + Grafana deep-links). Reconciled the information architecture: Backups is a top-level nav item at `/backups`, and the media surface is named Media at `/media` with `/applications` redirecting to `/media` (mirroring `/monitoring` → `/observability`). Frontend tests moved to Vitest + @testing-library/react (`npm test`), with legacy node suites in `frontend/tests`. - 2026-06-13: Adopted a dedicated, self-hosted observability subsystem based on Prometheus, Grafana Loki, Grafana, and Alertmanager. Metrics will be pulled from Node Exporter on machines and from application exporters in containers; logs will be structured JSON shipped by Promtail/Grafana Alloy. The existing POSIX remote collector will be removed and backup alerts migrated to Alertmanager rules. See `docs/monitoring-logging-design.md`. diff --git a/docs/monitoring-logging-design.md b/docs/monitoring-logging-design.md index 9f80156..5c82efd 100644 --- a/docs/monitoring-logging-design.md +++ b/docs/monitoring-logging-design.md @@ -307,6 +307,17 @@ The existing POSIX remote collector will be removed, and the Python backup alert ## Implementation Plan +> **Superseded mechanisms (2026-06-23):** Phases 2 and 3 originally wired Manage +> to a co-deployed Prometheus/Alertmanager via a shared-file **file-SD bridge** +> (`PROMETHEUS_FILE_SD_DIR` + `write_prometheus_targets`) and an +> `alertmanager_url` env var. Both have been removed. Manage now resolves +> Alertmanager/Grafana/Prometheus from the **service registry**, and external +> Prometheus instances consume node-exporter targets via **`http_sd_configs`** +> against `GET /api/monitoring/prometheus-targets`. Treat the Phase 2/3 +> file/config details below as the historical implementation, not the current +> wiring. See `openspec/changes/observability-service-registry/` and the +> decision log in `docs/REQUIREMENTS.md`. + ### Phase 0 — Foundation and Cleanup - [x] Add `prometheus-client` and `python-json-logger` to `backend/pyproject.toml`. diff --git a/frontend/README.md b/frontend/README.md index 90f9803..7aeda57 100644 --- a/frontend/README.md +++ b/frontend/README.md @@ -67,4 +67,4 @@ VITE_API_URL=http://your-backend-host:8000 - **Production**: export the required Compose variables in your shell, run `docker compose up --build`, and manage local/remote machines from **Settings**. - **Observability**: Manage only deploys backend + frontend. It connects to **existing** Grafana/Prometheus/Alertmanager instances; see `docker-compose.observability.yml` for an optional standalone example stack. A machine can be `local` (the API host itself) or `ssh` (a remote host), and the UI treats both the same after configuration. -In development, the Vite proxy handles `/api` requests automatically. `VITE_GRAFANA_URL` / `VITE_PROMETHEUS_URL` are optional frontend deep-link overrides for your existing instances. +In development, the Vite proxy handles `/api` requests automatically. Observability services (Grafana, Prometheus, Alertmanager) are configured in the app on the Services page — there are no observability env vars.