Files
hobbs-iac/docs/plans/2026-03-05-farm-manager-design.md
T
jeremy de1d9e1d93 infra: full IaC state after hf-pdocker-01 rebuild (2026-03-08)
Replaces initial Nomad/Consul/Terraform skeleton with current Docker-based
infrastructure across all three nodes (hf-pdocker-01, hf-pdocker-02, bart).

Key changes:
- CLAUDE.md: updated service distribution reflecting hf-pdocker-01 restored
- docs/plans/2026-03-08-hf-pdocker-01-rebuild.md: new rebuild plan doc
- compose/bart/: ai-agents, guacamole, matrix, media, openvas, smarthome, watchtower
- compose/hf-pdocker-02/: traefik, monitoring, adguard, gitea, semaphore, wikijs,
  unifi, vaultwarden, actual-budget, mcpo, netclaw, trivy, watchtower, n8n
- compose/hf-pdocker-01/: frigate, frigate-notify, farm-agent
- stacks/: all Swarm stack definitions (monitoring, traefik, smarthome, matrix,
  guacamole, media, ai-agents, frigate, gitea, semaphore, wikijs, unifi, etc.)
- .gitignore: exclude .env credential files and acme.json certs
- .env.example: placeholder credential files for all services
- .claude/agents/: gitea-backup and other infrastructure agent configs
- scripts/: frigate media cleanup and NAS sync scripts

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-08 18:51:25 -05:00

183 lines
5.9 KiB
Markdown

# Farm Manager — Design Document
**Date**: 2026-03-05
**Status**: Approved
## Overview
A web-based dashboard for managing Docker services across the 3-node homelab cluster. Provides full control (start/stop/restart/logs/pull) with service grouping for bulk operations.
## Architecture
Three components:
1. **Dashboard** — Static HTML/CSS/JS served by the API server. Dark theme, single page with service cards, group management, and slide-out log viewer.
2. **API Server** — Python FastAPI on hf-pdocker-01:8888. Serves frontend, proxies Docker commands to node agents, manages group definitions in JSON.
3. **Node Agent** — Python FastAPI on each node:8889. Mounts Docker socket, exposes REST API for container operations. Auto-detects Swarm vs Compose containers.
```
Browser → Dashboard (hf-pdocker-01:8888)
↓
API Server
↙ ↓ ↘
Agent Agent Agent
(01:8889) (02:8889) (bart:8889)
↓ ↓ ↓
Docker Docker Docker
Socket Socket Socket
```
## API Endpoints
### API Server (hf-pdocker-01:8888)
| Method | Path | Description |
|--------|------|-------------|
| GET | `/api/nodes` | List all nodes with health status |
| GET | `/api/services` | All containers across all nodes |
| POST | `/api/services/{node}/{container}/start` | Start container |
| POST | `/api/services/{node}/{container}/stop` | Stop container |
| POST | `/api/services/{node}/{container}/restart` | Restart container |
| GET | `/api/services/{node}/{container}/logs?tail=100` | Stream logs |
| POST | `/api/services/{node}/{container}/pull` | Pull latest image |
| GET | `/api/groups` | List all groups |
| POST | `/api/groups` | Create group |
| PUT | `/api/groups/{id}` | Edit group |
| DELETE | `/api/groups/{id}` | Delete group |
| POST | `/api/groups/{id}/start` | Start all services in group |
| POST | `/api/groups/{id}/stop` | Stop all services in group |
| POST | `/api/groups/{id}/restart` | Restart all services in group |
### Node Agent (each node:8889)
| Method | Path | Description |
|--------|------|-------------|
| GET | `/containers` | List all containers with status |
| POST | `/containers/{id}/start` | Start |
| POST | `/containers/{id}/stop` | Stop |
| POST | `/containers/{id}/restart` | Restart |
| GET | `/containers/{id}/logs?tail=100` | Get logs |
| POST | `/containers/{id}/pull` | Pull latest image |
| GET | `/health` | Agent health check |
## Frontend UI
- **Sidebar**: Node list with health dots, group list with expand/collapse, "All Services" view, group management button
- **Main area**: Grid of service cards (name, status badge, node, image, uptime, action buttons)
- **Log viewer**: Slide-out right panel, last 200 lines, auto-scroll
- **Group actions**: Toolbar with Start All / Stop All / Restart All, confirmation modal for destructive actions
- **Group editor**: Modal with name field and checkbox service list
- **Styling**: Dark theme, custom CSS variables, no framework
## Data Storage
### Groups (`/mnt/docker-data/configs/farm-manager/groups.json`)
```json
{
"groups": [
{
"id": "ai-agents",
"name": "AI Agents",
"services": [
{"node": "hf-pdocker-01", "container": "ai-agents_margaret"},
{"node": "hf-pdocker-01", "container": "ai-agents_spirit"},
{"node": "hf-pdocker-01", "container": "ai-agents_bob"},
{"node": "hf-pdocker-01", "container": "ai-agents_clippy"}
]
}
]
}
```
### Node config (`config.json`)
```json
{
"nodes": [
{"name": "hf-pdocker-01", "host": "192.168.86.192", "agent_port": 8889},
{"name": "hf-pdocker-02", "host": "192.168.86.100", "agent_port": 8889},
{"name": "bart", "host": "192.168.86.167", "agent_port": 8889}
]
}
```
### Default Groups
| Group | Services |
|-------|----------|
| AI Agents | margaret, spirit, bob, clippy |
| Smart Home | homeassistant, esphome, mosquitto |
| Monitoring | grafana, prometheus, alertmanager, influxdb, blackbox-exporter |
| Media | jellyfin, sonarr, radarr, sabnzbd, nzbhydra2, jellyseerr |
| Matrix | synapse, synapse-db, wellknown |
| Guacamole | guacamole, guacd, guacamole-db |
| Dev Tools | gitea, gitea-db, semaphore, semaphore-db, wikijs, wikijs-db |
| Security | vaultwarden, trivy, openvas |
| Network | traefik, adguard, unifi, unifi-db |
| Frigate | frigate, frigate-notify |
## Deployment
### Node Agent (all 3 nodes)
- Path: `/mnt/docker-data/compose/{node}/farm-agent/docker-compose.yml`
- Image: built once, pushed to registry at 127.0.0.1:5050
- Mounts: `/var/run/docker.sock`
- Port: 8889
- mem_limit: 128M
### API Server + Dashboard (hf-pdocker-01)
- Path: `/mnt/docker-data/compose/hf-pdocker-01/farm-manager/docker-compose.yml`
- Port: 8888
- Config: `/mnt/docker-data/configs/farm-manager/`
- mem_limit: 256M
### Swarm Handling
Node agent auto-detects Swarm-managed containers and uses `docker service` API for Swarm services, `docker` API for Compose containers.
## Repo
- Gitea: `jeremy/farm-manager` (git.hobbs.farm)
- Structure:
```
farm-manager/
├── agent/
│ ├── main.py
│ ├── docker_ops.py
│ ├── requirements.txt
│ └── Dockerfile
├── server/
│ ├── main.py
│ ├── routes/
│ ├── static/
│ │ ├── index.html
│ │ ├── style.css
│ │ └── app.js
│ ├── requirements.txt
│ └── Dockerfile
├── tests/
│ ├── test_agent.py
│ ├── test_server.py
│ └── conftest.py
├── config.json
├── groups.json
└── README.md
```
## Testing
| Layer | Scope | Tool |
|-------|-------|------|
| Unit | Agent Docker operations, group CRUD, API proxy logic | pytest + pytest-asyncio |
| Integration | API server ↔ mock agent, group persistence | pytest + httpx TestClient |
| Contract | Agent response schemas match dashboard expectations | pydantic models |
## Monitoring
- Prometheus blackbox probes: `:8888/health` and `:8889/health` on each node
- No auth (internal LAN only)