92bed208e0
ARCHITECTURE ============ Backend: FastAPI + uvicorn (port 8000) - JWT authentication with PAM system users - ZFS CLI wrapper with caching (30-60s TTL) - WebSocket pool status broadcaster (30s interval) - Services: auth, zfs_runner, file_manager, shares, identities, system_info - Routers: pools, datasets, snapshots, shares, identities, navigator, system Frontend: Next.js 15 + TypeScript (static export) - Incremental Static Regeneration (ISR) for weak hardware - Type-safe API client (lib/api.ts) - Dark mode + custom Tailwind theme - Pages: Dashboard, Login, Snapshots, Datasets, Shares, etc. DEPLOYMENT ========== Test Target: 192.168.1.179:8090 (Debian LXC) Production: 10.66.120.3:9090 (Raspberry Pi 4GB ARM64) Updater: Automated Gitea-based deployment (update-test.sh, update-pi.sh) FEATURES COMPLETED ================== Phase 3a: Dashboard Quick Stats (System, CPU, Memory, Storage) - Real-time stats with color-coded progress bars - Responsive grid layout (mobile: 1, tablet: 2, desktop: 4 columns) - ISR-optimized for fast loads on weak hardware REBRANDING ========== Renamed throughout: - Project: 'ZFS Manager' → 'ZMB Webui' - Services: 'zfs-manager' → 'zmb-webui' - Systemd units: zfs-manager-backend → zmb-webui-backend - Configuration files and documentation Co-Authored-By: Patrick <patrick@perlbach24.de>
228 lines
6.1 KiB
Markdown
228 lines
6.1 KiB
Markdown
# 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)
|