mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-08-22 07:06:51 +00:00
doc: V3 operations design — user-friendly setup, shell commands, REST API
Covers three personas (developer/operator/platform engineer) with: - One-command setup: weed server -block (10 seconds to first volume) - Shell commands: block.list, block.status, block.health, block.create, etc. - REST API: /block/volumes CRUD, /block/health - Observability: Prometheus metrics, alerting rules, Grafana dashboard - Actionable error messages (every error tells you what to do next) - Dry-run by default for all destructive operations Competitive comparison: 10s setup vs Ceph 30min, 13.5x write IOPS, single binary for object + block storage. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
2bc8dfcdde
commit
3ba622d9e0
@@ -0,0 +1,585 @@
|
||||
# V3 Operations Design
|
||||
|
||||
Date: 2026-04-13
|
||||
Status: design draft
|
||||
Purpose: define the user-facing operations experience for sw-block
|
||||
|
||||
## 1. Design Principles
|
||||
|
||||
### 1.1 One command to start
|
||||
|
||||
A developer should go from zero to a working block volume in under 10
|
||||
seconds with one command. No config files, no YAML, no separate services.
|
||||
|
||||
### 1.2 Dry-run by default
|
||||
|
||||
Every destructive operation previews what it will do. The user must
|
||||
explicitly confirm with `-apply`. This is already the SeaweedFS shell
|
||||
convention — extend it to all block operations.
|
||||
|
||||
### 1.3 Shell is the operations interface
|
||||
|
||||
`weed shell` is the single entry point for admin operations. No separate
|
||||
CLI tool. The shell already provides tab completion, command history,
|
||||
distributed locking, and 90+ commands. Block operations plug into the
|
||||
same framework.
|
||||
|
||||
### 1.4 Health at a glance
|
||||
|
||||
An admin should never need to grep logs to understand cluster state.
|
||||
`block.health` shows everything in one screen. Green/yellow/red, not
|
||||
log lines.
|
||||
|
||||
### 1.5 Developer sees only PVC
|
||||
|
||||
K8s developers interact with storage through `PersistentVolumeClaim`.
|
||||
They never see iSCSI, NVMe-oF, replication, failover, or rebuild.
|
||||
The CSI driver handles everything.
|
||||
|
||||
### 1.6 Three personas, three interfaces
|
||||
|
||||
| Persona | Interface | What they see |
|
||||
|---------|-----------|---------------|
|
||||
| Developer | K8s PVC / REST API | "Give me 100GB storage" |
|
||||
| Operator | `weed shell` | Volume health, failover, rebuild, snapshots |
|
||||
| Platform engineer | Config + monitoring | Cluster sizing, Prometheus, alerting |
|
||||
|
||||
## 2. Setup Experience
|
||||
|
||||
### 2.1 Single-node development (10 seconds)
|
||||
|
||||
```bash
|
||||
# Download
|
||||
curl -O https://github.com/seaweedfs/seaweedfs/releases/latest/weed
|
||||
|
||||
# Start everything in one process
|
||||
./weed server -block -block.size=100G -dir=/data
|
||||
|
||||
# Output:
|
||||
# Master started on :9333
|
||||
# Volume server started on :8480
|
||||
# Block service started (iSCSI :3260)
|
||||
# Created default volume "vol-1" (100GB, RF=1)
|
||||
#
|
||||
# Connect from this machine:
|
||||
# iscsiadm -m discovery -t st -p localhost:3260
|
||||
# iscsiadm -m node -T iqn.2024-01.com.seaweedfs:vol.vol-1 -l
|
||||
#
|
||||
# Or use NVMe-oF:
|
||||
# nvme discover -t tcp -a 127.0.0.1 -s 4420
|
||||
```
|
||||
|
||||
The output tells the user exactly what to do next. No documentation
|
||||
needed for the first connection.
|
||||
|
||||
### 2.2 Two-node replicated (30 seconds)
|
||||
|
||||
```bash
|
||||
# Node 1 (master + volume server):
|
||||
./weed server -block -block.size=100G -ip=10.0.0.1
|
||||
|
||||
# Node 2 (volume server only):
|
||||
./weed volume -block -block.size=100G -ip=10.0.0.3 \
|
||||
-mserver=10.0.0.1:9333
|
||||
|
||||
# Create replicated volume:
|
||||
./weed shell -master=10.0.0.1:9333
|
||||
> block.create -name=mydb -size=100G -rf=2 -apply
|
||||
Created "mydb" (100GB, RF=2, sync_all)
|
||||
Primary: 10.0.0.1:8480
|
||||
Replica: 10.0.0.3:8480
|
||||
iSCSI: iqn.2024-01.com.seaweedfs:vol.mydb at 10.0.0.1:3260
|
||||
```
|
||||
|
||||
### 2.3 Kubernetes (2 minutes)
|
||||
|
||||
```bash
|
||||
# Install CSI driver
|
||||
helm repo add seaweedfs https://seaweedfs.github.io/charts
|
||||
helm install sw-block seaweedfs/sw-block-csi \
|
||||
--set master.address=10.0.0.1:9333
|
||||
|
||||
# Create StorageClass
|
||||
kubectl apply -f - <<EOF
|
||||
apiVersion: storage.k8s.io/v1
|
||||
kind: StorageClass
|
||||
metadata:
|
||||
name: sw-block
|
||||
provisioner: seaweedfs.com/block
|
||||
parameters:
|
||||
replicaFactor: "2"
|
||||
durabilityMode: sync_all
|
||||
allowVolumeExpansion: true
|
||||
EOF
|
||||
|
||||
# Developer just uses PVC:
|
||||
kubectl apply -f - <<EOF
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: my-database
|
||||
spec:
|
||||
storageClassName: sw-block
|
||||
accessModes: [ReadWriteOnce]
|
||||
resources:
|
||||
requests:
|
||||
storage: 100Gi
|
||||
EOF
|
||||
```
|
||||
|
||||
### 2.4 Setup comparison
|
||||
|
||||
| System | Commands to first working volume | Time |
|
||||
|--------|--------------------------------|------|
|
||||
| sw-block | 1 (`weed server -block`) | 10s |
|
||||
| MinIO | 1 (`minio server`) | 5s (object only, no block) |
|
||||
| SeaweedFS (object) | 1 (`weed server`) | 5s |
|
||||
| Longhorn | 3 (`helm install` + PVC) | 5min |
|
||||
| Ceph | 5-8 (`cephadm bootstrap` + OSD + RBD) | 30min |
|
||||
| TrueNAS | Web installer + wizard | 15min |
|
||||
|
||||
## 3. Shell Commands
|
||||
|
||||
### 3.1 Command naming convention
|
||||
|
||||
All block commands start with `block.`. Subcommands use dots.
|
||||
This matches the existing shell convention (`volume.list`, `fs.ls`,
|
||||
`ec.encode`).
|
||||
|
||||
### 3.2 Volume lifecycle
|
||||
|
||||
```
|
||||
block.create Create a new block volume
|
||||
block.delete Delete a block volume (dry-run by default)
|
||||
block.list List all block volumes with health status
|
||||
block.status Show detailed status of one volume
|
||||
block.expand Expand volume size (online, no downtime)
|
||||
```
|
||||
|
||||
### 3.3 Data protection
|
||||
|
||||
```
|
||||
block.snapshot Create a CoW snapshot
|
||||
block.snapshot.list List snapshots for a volume
|
||||
block.snapshot.delete Delete a snapshot
|
||||
block.snapshot.export Export snapshot to S3 (SeaweedFS object store)
|
||||
block.snapshot.restore Restore volume from snapshot
|
||||
```
|
||||
|
||||
### 3.4 HA operations
|
||||
|
||||
```
|
||||
block.promote Manual failover: promote replica to primary
|
||||
block.rebuild Trigger manual rebuild for a replica
|
||||
block.assign Change replica assignment (add/remove replica)
|
||||
```
|
||||
|
||||
### 3.5 Cluster health
|
||||
|
||||
```
|
||||
block.health Cluster-wide health summary
|
||||
block.servers List block-capable volume servers
|
||||
block.events Recent events (failover, rebuild, degraded)
|
||||
```
|
||||
|
||||
### 3.6 Benchmarking
|
||||
|
||||
```
|
||||
block.bench Run fio benchmark on a volume (creates temp volume if needed)
|
||||
block.bench.compare Compare performance of two runs
|
||||
```
|
||||
|
||||
### 3.7 Detailed command specs
|
||||
|
||||
#### block.list
|
||||
|
||||
```
|
||||
> block.list
|
||||
NAME SIZE RF MODE PRIMARY REPLICA HEALTH IOPS
|
||||
pvc-data-01 100G 2 publish_healthy 10.0.0.1:8480 10.0.0.3:8480 1.0 45.2K
|
||||
pvc-db-01 50G 2 degraded 10.0.0.3:8480 (rebuilding 78%) 0.8 38.1K
|
||||
pvc-temp 200G 1 healthy 10.0.0.1:8480 — 1.0 52.0K
|
||||
|
||||
> block.list -json
|
||||
[{"name":"pvc-data-01","size":107374182400,"rf":2,"mode":"publish_healthy",...}]
|
||||
```
|
||||
|
||||
Columns:
|
||||
- NAME: volume name
|
||||
- SIZE: allocated size
|
||||
- RF: replica factor
|
||||
- MODE: engine projection mode
|
||||
- PRIMARY: current primary server
|
||||
- REPLICA: replica server(s) with status
|
||||
- HEALTH: 0.0-1.0 score
|
||||
- IOPS: current write IOPS (from last heartbeat)
|
||||
|
||||
#### block.status
|
||||
|
||||
```
|
||||
> block.status mydb
|
||||
Volume: mydb
|
||||
Size: 100G (used: 34G, 34%)
|
||||
RF: 2 (sync_all)
|
||||
Mode: publish_healthy
|
||||
Epoch: 3
|
||||
|
||||
Primary: 10.0.0.1:8480
|
||||
WAL head: 284756
|
||||
Checkpoint: 284700
|
||||
Uptime: 3d 14h
|
||||
|
||||
Replica: 10.0.0.3:8480
|
||||
State: in_sync
|
||||
Flushed: 284756
|
||||
Lag: 0 entries
|
||||
|
||||
iSCSI: iqn.2024-01.com.seaweedfs:vol.mydb at 10.0.0.1:3260
|
||||
NVMe-oF: nqn.2024-01.com.seaweedfs:vol.mydb at 10.0.0.1:4420
|
||||
|
||||
Snapshots:
|
||||
mydb@2026-04-13T10:30 34G (3 hours ago)
|
||||
mydb@2026-04-12T22:00 32G (15 hours ago)
|
||||
|
||||
Recent events:
|
||||
2026-04-11 02:12 rebuild completed (2.1s, 1GB transferred)
|
||||
2026-04-09 22:54 auto-failover (10.0.0.1 → 10.0.0.3, epoch 1→2)
|
||||
|
||||
Health: 1.0 (last scrub: 2026-04-12, 0 errors)
|
||||
```
|
||||
|
||||
#### block.health
|
||||
|
||||
```
|
||||
> block.health
|
||||
╔═══════════════════════════════════════╗
|
||||
║ BLOCK CLUSTER HEALTH: OK ║
|
||||
╚═══════════════════════════════════════╝
|
||||
|
||||
Volumes: 12 total
|
||||
11 healthy
|
||||
1 degraded (pvc-db-01: rebuilding)
|
||||
0 offline
|
||||
|
||||
Servers: 3 online, 0 offline
|
||||
10.0.0.1:8480 ██████████ 6 volumes, 450G used
|
||||
10.0.0.3:8480 ████████ 5 volumes, 380G used
|
||||
10.0.0.5:8480 ██████ 4 volumes, 280G used
|
||||
|
||||
Capacity: 1.1T used / 3.0T total (37%)
|
||||
|
||||
Last 24h:
|
||||
Failovers: 0
|
||||
Rebuilds: 1 (pvc-db-01, in progress, 78%)
|
||||
Scrub errors: 0
|
||||
|
||||
Alerts: none
|
||||
```
|
||||
|
||||
#### block.create (dry-run)
|
||||
|
||||
```
|
||||
> block.create -name=analytics -size=500G -rf=2
|
||||
DRY RUN — no changes made
|
||||
|
||||
Would create volume "analytics":
|
||||
Size: 500G
|
||||
RF: 2 (sync_all)
|
||||
Primary: 10.0.0.5:8480 (most free space: 720G)
|
||||
Replica: 10.0.0.1:8480 (550G free, different rack)
|
||||
iSCSI IQN: iqn.2024-01.com.seaweedfs:vol.analytics
|
||||
|
||||
Run with -apply to execute.
|
||||
|
||||
> block.create -name=analytics -size=500G -rf=2 -apply
|
||||
Created "analytics" (500GB, RF=2, sync_all)
|
||||
Primary: 10.0.0.5:8480
|
||||
Replica: 10.0.0.1:8480
|
||||
iSCSI: iqn.2024-01.com.seaweedfs:vol.analytics at 10.0.0.5:3260
|
||||
```
|
||||
|
||||
#### block.delete (always requires -apply -confirm)
|
||||
|
||||
```
|
||||
> block.delete -name=old-vol
|
||||
DRY RUN — no changes made
|
||||
|
||||
Would delete volume "old-vol":
|
||||
Size: 50G (used: 23G)
|
||||
RF: 2 (primary: 10.0.0.1, replica: 10.0.0.3)
|
||||
Snapshots: 3 (would also be deleted)
|
||||
Age: 45 days
|
||||
|
||||
WARNING: This permanently destroys all data and snapshots.
|
||||
Run with -apply -confirm to execute.
|
||||
|
||||
> block.delete -name=old-vol -apply -confirm
|
||||
Deleted "old-vol" (50GB, 3 snapshots removed)
|
||||
```
|
||||
|
||||
#### block.promote (manual failover)
|
||||
|
||||
```
|
||||
> block.promote -name=mydb -target=10.0.0.3:8480
|
||||
DRY RUN — no changes made
|
||||
|
||||
Would promote 10.0.0.3:8480 to primary for "mydb":
|
||||
Current primary: 10.0.0.1:8480 (epoch 2)
|
||||
New primary: 10.0.0.3:8480 (would become epoch 3)
|
||||
Replica state: in_sync (lag: 0 entries)
|
||||
Impact: iSCSI connections will reconnect (~2s disruption)
|
||||
|
||||
Run with -apply to execute.
|
||||
|
||||
> block.promote -name=mydb -target=10.0.0.3:8480 -apply
|
||||
Promoted 10.0.0.3:8480 to primary for "mydb" (epoch 2→3)
|
||||
Old primary 10.0.0.1:8480 will rejoin as replica after next heartbeat.
|
||||
```
|
||||
|
||||
## 4. REST API
|
||||
|
||||
### 4.1 Endpoints
|
||||
|
||||
All under `/block/` prefix on the master server.
|
||||
|
||||
| Method | Path | Description |
|
||||
|--------|------|-------------|
|
||||
| `GET` | `/block/volumes` | List all block volumes |
|
||||
| `POST` | `/block/volumes` | Create block volume |
|
||||
| `GET` | `/block/volumes/{name}` | Get volume status |
|
||||
| `DELETE` | `/block/volumes/{name}` | Delete volume |
|
||||
| `PUT` | `/block/volumes/{name}/expand` | Expand volume |
|
||||
| `POST` | `/block/volumes/{name}/promote` | Manual failover |
|
||||
| `POST` | `/block/volumes/{name}/snapshots` | Create snapshot |
|
||||
| `GET` | `/block/volumes/{name}/snapshots` | List snapshots |
|
||||
| `DELETE` | `/block/volumes/{name}/snapshots/{id}` | Delete snapshot |
|
||||
| `GET` | `/block/health` | Cluster health summary |
|
||||
| `GET` | `/block/servers` | List block-capable servers |
|
||||
| `GET` | `/block/events` | Recent events |
|
||||
|
||||
### 4.2 Examples
|
||||
|
||||
```bash
|
||||
# Create volume
|
||||
curl -X POST http://master:9333/block/volumes \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"name":"mydb","sizeBytes":107374182400,"replicaFactor":2}'
|
||||
|
||||
# Response:
|
||||
{
|
||||
"name": "mydb",
|
||||
"sizeBytes": 107374182400,
|
||||
"replicaFactor": 2,
|
||||
"durabilityMode": "sync_all",
|
||||
"primary": "10.0.0.1:8480",
|
||||
"replica": "10.0.0.3:8480",
|
||||
"iscsiIqn": "iqn.2024-01.com.seaweedfs:vol.mydb",
|
||||
"iscsiPortal": "10.0.0.1:3260",
|
||||
"epoch": 1,
|
||||
"mode": "bootstrap_pending"
|
||||
}
|
||||
|
||||
# Get health
|
||||
curl http://master:9333/block/health
|
||||
|
||||
# Response:
|
||||
{
|
||||
"status": "ok",
|
||||
"volumes": {"total": 12, "healthy": 11, "degraded": 1},
|
||||
"servers": {"total": 3, "online": 3},
|
||||
"capacity": {"usedBytes": 1181116006400, "totalBytes": 3221225472000}
|
||||
}
|
||||
```
|
||||
|
||||
## 5. Observability
|
||||
|
||||
### 5.1 Prometheus metrics
|
||||
|
||||
Already implemented. Key metrics:
|
||||
|
||||
```prometheus
|
||||
# Volume level
|
||||
sw_block_volume_mode{name="mydb"} 1 # 1=healthy
|
||||
sw_block_volume_iops{name="mydb",op="write"} 45200
|
||||
sw_block_volume_size_bytes{name="mydb"} 107374182400
|
||||
sw_block_volume_used_bytes{name="mydb"} 36507222016
|
||||
|
||||
# Replica level
|
||||
sw_block_replica_state{name="mydb",server="10.0.0.3"} 3 # 3=in_sync
|
||||
sw_block_replica_lag_entries{name="mydb",server="10.0.0.3"} 0
|
||||
|
||||
# Cluster level
|
||||
sw_block_volumes_total 12
|
||||
sw_block_volumes_healthy 11
|
||||
sw_block_volumes_degraded 1
|
||||
sw_block_servers_online 3
|
||||
|
||||
# Events
|
||||
sw_block_failovers_total 2
|
||||
sw_block_rebuilds_total 5
|
||||
sw_block_rebuild_duration_seconds{name="mydb"} 2.1
|
||||
```
|
||||
|
||||
### 5.2 Alerting rules
|
||||
|
||||
Recommended Prometheus alert rules:
|
||||
|
||||
```yaml
|
||||
groups:
|
||||
- name: sw-block
|
||||
rules:
|
||||
- alert: BlockVolumeDegraded
|
||||
expr: sw_block_volume_mode != 1
|
||||
for: 5m
|
||||
labels:
|
||||
severity: warning
|
||||
annotations:
|
||||
summary: "Block volume {{ $labels.name }} is degraded"
|
||||
|
||||
- alert: BlockVolumeOffline
|
||||
expr: sw_block_volume_mode == 0
|
||||
for: 1m
|
||||
labels:
|
||||
severity: critical
|
||||
|
||||
- alert: BlockRebuildStalled
|
||||
expr: sw_block_rebuild_duration_seconds > 300
|
||||
labels:
|
||||
severity: warning
|
||||
summary: "Rebuild for {{ $labels.name }} taking > 5 minutes"
|
||||
|
||||
- alert: BlockCapacityHigh
|
||||
expr: sw_block_cluster_used_bytes / sw_block_cluster_total_bytes > 0.85
|
||||
labels:
|
||||
severity: warning
|
||||
summary: "Block cluster capacity > 85%"
|
||||
```
|
||||
|
||||
### 5.3 Grafana dashboard
|
||||
|
||||
Provide a pre-built Grafana dashboard JSON that shows:
|
||||
- Cluster health panel (big green/yellow/red indicator)
|
||||
- Volume list with mode, health, IOPS
|
||||
- IOPS over time (per-volume and aggregate)
|
||||
- Latency percentiles (p50, p99, p999)
|
||||
- Rebuild/failover event markers
|
||||
- Capacity trend
|
||||
- Per-server utilization
|
||||
|
||||
## 6. Error Messages
|
||||
|
||||
Every error should tell the user what happened, why, and what to do:
|
||||
|
||||
```
|
||||
# Bad:
|
||||
Error: volume not found
|
||||
|
||||
# Good:
|
||||
Error: block volume "mydb" not found.
|
||||
Available volumes: pvc-data-01, pvc-db-01, pvc-temp
|
||||
Run 'block.list' to see all volumes.
|
||||
```
|
||||
|
||||
```
|
||||
# Bad:
|
||||
Error: cannot create volume
|
||||
|
||||
# Good:
|
||||
Error: cannot create volume "analytics" (500GB, RF=2).
|
||||
Reason: not enough servers. Need 2 servers for RF=2, but only 1 is online.
|
||||
Run 'block.servers' to check server status.
|
||||
```
|
||||
|
||||
```
|
||||
# Bad:
|
||||
Error: promote failed
|
||||
|
||||
# Good:
|
||||
Error: cannot promote 10.0.0.3:8480 for "mydb".
|
||||
Reason: replica is not in_sync (current state: rebuilding, 78% complete).
|
||||
Wait for rebuild to complete, then retry.
|
||||
Run 'block.status mydb' for details.
|
||||
```
|
||||
|
||||
## 7. Comparison with Competitors
|
||||
|
||||
### 7.1 What we steal
|
||||
|
||||
| From | What | How |
|
||||
|------|------|-----|
|
||||
| MinIO | One-command startup | `weed server -block` |
|
||||
| SeaweedFS | Shell as operations interface | `block.*` commands in `weed shell` |
|
||||
| Ceph | Dry-run on all destructive ops | `-apply` flag required |
|
||||
| Ceph | Declarative cluster spec | Future: `block.apply -f cluster.yaml` |
|
||||
| Longhorn | Auto-rebuild on config change | Change RF in shell, system handles rebuild |
|
||||
| Longhorn | One-click snapshot | `block.snapshot mydb` (one command, no params) |
|
||||
| TrueNAS | iSCSI setup wizard | `block.setup` interactive guide |
|
||||
| TrueNAS | Actionable error messages | Every error says what to do next |
|
||||
|
||||
### 7.2 What we do better
|
||||
|
||||
| Area | Competitors | sw-block |
|
||||
|------|------------|----------|
|
||||
| Setup time | Ceph: 30min, Longhorn: 5min | 10 seconds |
|
||||
| Write IOPS (RF=2) | Ceph: 4.5K | 61K (13.5x) |
|
||||
| Rebuild time (1GB) | Ceph: minutes | 2 seconds |
|
||||
| CLI | Ceph: many tools, Longhorn: kubectl | Single `weed shell` |
|
||||
| Object + Block | Separate systems | Same binary, same cluster |
|
||||
|
||||
### 7.3 What we do not provide (yet)
|
||||
|
||||
| Feature | Who has it | Priority |
|
||||
|---------|-----------|----------|
|
||||
| Web dashboard | Ceph, Longhorn, TrueNAS | P3 |
|
||||
| Declarative cluster spec | Ceph `ceph orch` | P3 |
|
||||
| Grafana dashboard JSON | Ceph, Longhorn | P2 |
|
||||
| Multi-cluster management | None (all single-cluster) | Not planned |
|
||||
|
||||
## 8. Implementation Phases
|
||||
|
||||
### Phase 1: Shell commands (P0)
|
||||
|
||||
Implement in `weed/shell/`:
|
||||
- `block.list` — volume list with health
|
||||
- `block.status` — detailed volume status
|
||||
- `block.create` — create with dry-run
|
||||
- `block.delete` — delete with dry-run + confirm
|
||||
- `block.health` — cluster health summary
|
||||
|
||||
These commands call existing master gRPC APIs. No new backend code
|
||||
needed — just shell-side formatting.
|
||||
|
||||
Estimated: ~400 lines, 5 new files in `weed/shell/`.
|
||||
|
||||
### Phase 2: REST API (P1)
|
||||
|
||||
Implement in `weed/server/master_server_handlers_block.go`:
|
||||
- CRUD endpoints for volumes
|
||||
- Health endpoint
|
||||
- Server list endpoint
|
||||
|
||||
These wrap existing `BlockVolumeRegistry` and `blockAssignmentQueue`
|
||||
methods. JSON request/response.
|
||||
|
||||
Estimated: ~300 lines.
|
||||
|
||||
### Phase 3: Enhanced operations (P2)
|
||||
|
||||
- `block.snapshot` / `block.snapshot.list`
|
||||
- `block.expand`
|
||||
- `block.promote` with dry-run
|
||||
- `block.events` (recent failover/rebuild log)
|
||||
- `block.bench` (built-in fio wrapper)
|
||||
|
||||
### Phase 4: Developer experience (P2)
|
||||
|
||||
- `weed server -block` one-click mode
|
||||
- Actionable error messages for all block operations
|
||||
- Connection string output on volume creation
|
||||
- `block.setup` interactive wizard
|
||||
|
||||
### Phase 5: Dashboards (P3)
|
||||
|
||||
- Grafana dashboard JSON
|
||||
- Prometheus alert rules template
|
||||
- Web UI for block volume management (if demand exists)
|
||||
Reference in New Issue
Block a user