Files
harbor-net/docs/recovery/state-recovery.md
T
dokril daec12e013
Build and Deploy Gateway / build-and-push (push) Failing after 14s
Build and Deploy Gateway / deploy (push) Has been skipped
Update Harbor client and gateway integration workflows
2026-08-19 18:16:10 +03:00

3.7 KiB

Harbor state recovery

Harbor keeps the existing data directory and state.json path. The current persisted format is schemaVersion: 8: 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, v6 adds an explicit vpn or direct outbound to every route rule, v7 stores connectivity-diagnostics settings, and v8 adds Gateway failover state.

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:

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:

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:

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.

Migration to failover

Schemas v0-v7 migrate to v8 with failover disabled, empty switch history and no applied dual config. Migration does not start probes, enable traffic accounting or change the single-channel runtime. The original state is preserved as state.json.backup-v<fromVersion>-* before the atomic replacement.

The separate activity-journal.json is created on the first important event. It uses the same atomic write and corrupt-file isolation mechanism as state, retains at most 30 days, and can be removed while Harbor is stopped without affecting subscriptions, routing or VPN startup.

Corrupt JSON

If state.json cannot be parsed, Harbor renames the exact damaged bytes to:

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-v8 binary cannot interpret failover state. Restore state.json.backup-v<fromVersion>-* matching the rollback binary; deploying old code over schema v8 is not safe. A rollback to pre-v5 additionally requires the matching state and subscription-cache backups because that binary cannot interpret canonical profiles.