Skip to main content

Restore

The restore command pushes the desired state from your Git repository back to Consul KV. It compares Git (source of truth) against the current Consul state and generates a plan of SET and DELETE operations. All writes use CAS (Check-And-Set) to prevent overwriting concurrent changes.

When to restore

  • A bad config change is causing production issues and you need to revert.
  • Consul data was accidentally deleted.
  • You're setting up a new Consul cluster and need to seed it from a backup.
  • Drift detection found differences you want to correct.

Dry-run preview

Always start with --dry-run:

consul-guardian restore \
--consul-addr http://localhost:8500 \
--prefix "config/" \
--git-repo ./consul-backup \
--dry-run

Output:

Restore plan for prefix "config/" (source: git):

+ CREATE config/cache/ttl (3 bytes)
~ UPDATE config/database/host (15 bytes, CAS index: 847)
~ UPDATE config/database/max-connections (4 bytes, CAS index: 923)
- DELETE config/temp/debug-mode (CAS index: 1052)

Summary: 3 sets, 1 delete, 4 total operations

The plan shows exactly what will happen:

  • CREATE -- Key exists in Git but not in Consul (CAS index 0).
  • UPDATE -- Key exists in both but values differ. The CAS index ensures Guardian only writes if the key hasn't been modified since the plan was generated.
  • DELETE -- Key exists in Consul but not in Git.

Executing the restore

Once you've reviewed the plan, run without --dry-run:

consul-guardian restore \
--consul-addr http://localhost:8500 \
--prefix "config/" \
--git-repo ./consul-backup

Output:

Restore plan for prefix "config/" (source: git):

+ CREATE config/cache/ttl (3 bytes)
~ UPDATE config/database/host (15 bytes, CAS index: 847)

Summary: 2 sets, 0 deletes, 2 total operations

Restore complete: 2 succeeded, 0 failed (12ms)

Selective restore

Prefix-based

Restore only keys under a specific prefix:

consul-guardian restore --prefix "config/database/"

This only touches keys under config/database/ and leaves everything else alone.

Single key

To restore a single key, use a prefix that matches exactly one key:

consul-guardian restore --prefix "config/database/host"

CAS safety

Every restore operation uses Consul's Check-And-Set mechanism. Here's why this matters:

  1. Guardian reads the current ModifyIndex for each key in Consul.
  2. When writing, it includes this index in the CAS operation.
  3. If another process modified the key between Guardian's read and write, the CAS check fails.
  4. A failed CAS means "someone else changed this key since you last looked at it" -- Guardian reports the conflict rather than silently overwriting.

This prevents a common disaster scenario: you start a restore while a deployment is also updating Consul. Without CAS, the restore would overwrite the deployment's changes.

Full disaster recovery scenario

Your Consul cluster lost its data. Here's how to recover:

# 1. Start a fresh Consul cluster
docker run -d --name consul -p 8500:8500 hashicorp/consul:1.18 agent -dev

# 2. Clone the backup repo (if not already local)
git clone git@github.com:yourorg/consul-backup.git

# 3. Preview the restore
consul-guardian restore \
--consul-addr http://localhost:8500 \
--prefix "config/" \
--git-repo ./consul-backup \
--dry-run

# 4. Execute the restore
consul-guardian restore \
--consul-addr http://localhost:8500 \
--prefix "config/" \
--git-repo ./consul-backup

# 5. Verify
consul kv get -recurse config/

For a full cluster restore (including ACLs and sessions), use snapshot restore instead. See Snapshots.

Real-world example

At 3am, an automated deploy script sets config/rate-limit/max-rps to 10 instead of 10000. API requests start getting throttled. The on-call engineer runs:

# See the Git history for that key
cd consul-backup
git log --oneline -- config/rate-limit/max-rps
# a1b2c3d consul-guardian: 1 keys changed (5 minutes ago)
# x9y8z7w consul-guardian: 1 keys changed (2 weeks ago)

# Restore the previous state of the prefix
consul-guardian restore --prefix "config/rate-limit/" --dry-run
consul-guardian restore --prefix "config/rate-limit/"

Service restored in under 2 minutes.