# ZMB Webui Backend API FastAPI backend for ZFS pool, dataset, and snapshot management. ## Quick Start (Local Development) ### Prerequisites - Python 3.11+ - ZFS tools installed (`zpool`, `zfs`) ### Setup ```bash cd backend # Create virtual environment python3 -m venv venv source venv/bin/activate # Install dependencies pip install -r requirements.txt # Create default admin user (password: admin) python3 -c "from services.auth import auth_service; auth_service.add_user('admin', 'admin')" # Run development server python3 main.py ``` Server runs on `http://localhost:8000` ## API Endpoints ### Authentication ```bash # Login curl -X POST http://localhost:8000/api/auth/login \ -H "Content-Type: application/json" \ -d '{"username":"admin","password":"admin"}' # Returns: {"access_token":"...", "token_type":"bearer"} ``` ### Pools ```bash # List pools (requires auth) curl http://localhost:8000/api/pools \ -H "Authorization: Bearer YOUR_TOKEN" # Get pool status curl http://localhost:8000/api/pools/tank \ -H "Authorization: Bearer YOUR_TOKEN" # Start scrub curl -X POST http://localhost:8000/api/pools/tank/scrub \ -H "Authorization: Bearer YOUR_TOKEN" ``` ### Datasets ```bash # List datasets curl http://localhost:8000/api/datasets \ -H "Authorization: Bearer YOUR_TOKEN" # Create dataset curl -X POST http://localhost:8000/api/datasets \ -H "Authorization: Bearer YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{"name":"tank/backup","properties":{"compression":"lz4"}}' # Delete dataset curl -X DELETE http://localhost:8000/api/datasets/tank/test \ -H "Authorization: Bearer YOUR_TOKEN" ``` ### Snapshots ```bash # List snapshots curl http://localhost:8000/api/snapshots \ -H "Authorization: Bearer YOUR_TOKEN" # Create snapshot curl -X POST http://localhost:8000/api/snapshots \ -H "Authorization: Bearer YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{"dataset":"tank/share"}' # Delete snapshot curl -X DELETE http://localhost:8000/api/snapshots/tank/share@2026-04-14-120000 \ -H "Authorization: Bearer YOUR_TOKEN" # Rollback snapshot curl -X POST http://localhost:8000/api/snapshots/rollback \ -H "Authorization: Bearer YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{"snapshot":"tank/share@2026-04-14-120000"}' ``` ### File Manager (Browse /tank/share) ```bash # Browse directory curl "http://localhost:8000/api/files/browse?path=/" \ -H "Authorization: Bearer YOUR_TOKEN" # Get file info curl "http://localhost:8000/api/files/info?path=/document.pdf" \ -H "Authorization: Bearer YOUR_TOKEN" # Read text file (< 10MB) curl "http://localhost:8000/api/files/read?path=/config.json&limit=1000" \ -H "Authorization: Bearer YOUR_TOKEN" # Download file curl "http://localhost:8000/api/files/download?path=/archive.tar.gz" \ -H "Authorization: Bearer YOUR_TOKEN" \ -O # Upload file curl -X POST "http://localhost:8000/api/files/upload?path=/" \ -H "Authorization: Bearer YOUR_TOKEN" \ -F "file=@/local/path/file.txt" # Create directory curl -X POST http://localhost:8000/api/files/mkdir \ -H "Authorization: Bearer YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{"path":"/new_folder"}' # Create file curl -X POST http://localhost:8000/api/files/create \ -H "Authorization: Bearer YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{"path":"/notes.txt","content":"Hello World"}' # Rename file curl -X POST http://localhost:8000/api/files/rename \ -H "Authorization: Bearer YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{"old_path":"/oldname.txt","new_name":"newname.txt"}' # Delete file curl -X DELETE "http://localhost:8000/api/files/delete?path=/file.txt" \ -H "Authorization: Bearer YOUR_TOKEN" # Delete directory (recursive) curl -X DELETE "http://localhost:8000/api/files/delete?path=/folder&recursive=true" \ -H "Authorization: Bearer YOUR_TOKEN" # Get space usage curl http://localhost:8000/api/files/space \ -H "Authorization: Bearer YOUR_TOKEN" ``` ## Architecture ### Services - **zfs_runner.py**: Subprocess wrapper for ZFS commands with caching - **auth.py**: JWT token generation and verification ### Routers - **auth.py**: Login endpoint - **pools.py**: Pool list, status, scrub operations - **datasets.py**: Dataset CRUD operations - **snapshots.py**: Snapshot CRUD, rollback ### Models - **pool.py**: Pool, PoolStatus, PoolHealth - **dataset.py**: Dataset, DatasetType - **snapshot.py**: Snapshot - **auth.py**: User, Token, TokenData ## Caching Strategy - Pool status: 30s TTL - Snapshots: 60s TTL - Datasets: 60s TTL Cache is cleared on mutations (create/delete operations). ## Performance Notes ### For 4GB RAM Raspberry Pi: - gunicorn: 2 workers - Memory limit: 512M soft / 768M hard - Connection timeout: 30s - Max requests per worker: 500 (recycle to prevent memory leaks) ### Optimizations: - ZFS queries limited to max depth 2 - Snapshots limited to 50 by default (can be increased with `?limit=N`) - Subprocess timeout: 5s - In-memory TTL cache (no Redis required) ## Production Deployment 1. Copy backend to `/opt/zmb-webui/backend` 2. Install systemd service: `sudo cp deploy/zmb-webui-backend.service /etc/systemd/system/` 3. Update users: `python3 -c "from services.auth import auth_service; auth_service.add_user('yourusername', 'strongpassword')"` 4. Start service: ```bash sudo systemctl daemon-reload sudo systemctl enable zmb-webui-backend sudo systemctl start zmb-webui-backend ``` ## Troubleshooting ### ZFS commands not working - Check: `zpool list` runs without errors - Check: Running as root or with proper sudo permissions - Check: ZFS kernel module is loaded: `lsmod | grep zfs` ### Memory usage growing - Check: `ps aux | grep uvicorn` for VSZ/RSS - Restart service: `systemctl restart zmb-webui-backend` - Increase frequency of restarts in crontab if needed ### Slow responses - Check: `zpool status` output (large pool = slow scrub) - Clear cache: `curl -X POST /api/pools/clear-cache` (with auth) - Consider increasing cache TTLs in `zfs_runner.py` ## Development Tips - Use `curl` or Postman for API testing - Check logs: `journalctl -u zmb-webui-backend -f` - Interactive API docs: `http://localhost:8000/docs` (after running)