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>
This commit is contained in:
@@ -0,0 +1,182 @@
|
||||
# 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)
|
||||
Reference in New Issue
Block a user