59 lines
3.0 KiB
Markdown
59 lines
3.0 KiB
Markdown
# Harbor state recovery
|
|
|
|
Harbor keeps the existing data directory and `state.json` path. The current persisted format is `schemaVersion: 6`: schema v2 introduced local route rules, v3 added rule enabled state, v4 added stable server IDs, v5 embeds the canonical `profiles[]` collection with desired/applied profile identity, and v6 adds an explicit `vpn` or `direct` outbound to every route rule.
|
|
|
|
## Atomic writes
|
|
|
|
Persistent files are written to a unique temporary file in the same directory, flushed with `fsync`, closed and atomically renamed over the target. A failure before rename leaves the previous target untouched and removes the temporary file.
|
|
|
|
Profile/server switching prepares candidate config and runtime before the final state publication. If any later step fails, Harbor restores the previous config, runtime and canonical state.
|
|
|
|
## Migration to profiles
|
|
|
|
On startup, a legacy state is normalized before the process starts. Harbor creates one profile named `Основной`, moves the provider URL/config and metadata into it, and preserves unambiguous desired/applied server identity. A legacy state explicitly marked stopped clears stale applied residue.
|
|
|
|
Before replacing state Harbor saves the original beside it:
|
|
|
|
```text
|
|
state.json.backup-v4-2026-08-11T12-00-00-000Z
|
|
```
|
|
|
|
After a valid profile has been committed, the raw legacy cache is saved and removed as a second owner:
|
|
|
|
```text
|
|
subscription-cache.json.backup-v1-2026-08-11T12-00-00-000Z
|
|
```
|
|
|
|
An invalid legacy provider config is backed up but not started. Harbor removes stale generated config and returns to a stopped first-run state.
|
|
|
|
## Migration to ordered VPN/Direct rules
|
|
|
|
When schemas v0-v5 are read, Harbor preserves the order of `routeRules` and `appliedRouteRules` and adds `outbound: "direct"` to legacy entries before atomically committing schema v6. The original file is preserved using its actual source version, for example:
|
|
|
|
```text
|
|
state.json.backup-v5-2026-08-17T12-00-00-000Z
|
|
```
|
|
|
|
After migration, malformed schema-v6 rules are rejected; Harbor does not reinterpret a missing or unknown outbound as direct.
|
|
|
|
## Corrupt JSON
|
|
|
|
If `state.json` cannot be parsed, Harbor renames the exact damaged bytes to:
|
|
|
|
```text
|
|
state.json.corrupt-2026-08-11T12-00-00-000Z
|
|
```
|
|
|
|
It then creates a valid empty current-schema state and reports storage recovery. A corrupt legacy subscription cache is preserved with the same suffix and is never used to start stale config.
|
|
|
|
## Manual recovery and downgrade
|
|
|
|
Perform recovery while Harbor is stopped:
|
|
|
|
1. Copy the whole data directory.
|
|
2. Inspect the intended backup with `jq . <backup-file>`.
|
|
3. Restore only matching state/cache backups to their original filenames.
|
|
4. Start Harbor and verify `GET /api/state` before applying a profile.
|
|
|
|
A pre-v6 binary cannot interpret the explicit ordered VPN/Direct rule contract. Restore `state.json.backup-v<fromVersion>-*` matching the rollback binary; deploying old code over schema v6 is not safe. A rollback to pre-v5 additionally requires the matching state and subscription-cache backups because that binary cannot interpret canonical profiles.
|