etcdctl: make-mirror --rev drops the source prefix by default
Bug report criteria
- This is not a security report.
- This is a reproducible bug, not a support request.
- I have read the bug reporting guidelines.
- I have checked existing issues and pull requests for duplicates.
What happened?
etcdctl make-mirror --prefix=app/ --rev=3 removes app/ from destination keys unless --dest-prefix is also supplied. A full sync preserves the prefix with the same configuration.
When resuming a mirror, a source update to app/key writes to key, leaving the existing destination app/key stale. A subsequent source deletion also targets key. This can overwrite or delete a separate destination key.
What did you expect to happen?
Preserve the source prefix during incremental sync, just as during full sync. Removing or replacing the prefix should require --no-dest-prefix or --dest-prefix.
How can we reproduce it (as minimally and precisely as possible)?
With two fresh, single-member clusters on 127.0.0.1:2379 and 127.0.0.1:3379:
# Seed the source at revisions 2 and 3.
./bin/etcdctl --endpoints=127.0.0.1:2379 put app/key old
./bin/etcdctl --endpoints=127.0.0.1:2379 put app/key new
# Seed an existing mirror and an unrelated destination key.
./bin/etcdctl --endpoints=127.0.0.1:3379 put app/key old
./bin/etcdctl --endpoints=127.0.0.1:3379 put key unrelated
./bin/etcdctl --endpoints=127.0.0.1:2379 make-mirror --prefix=app/ --rev=3 127.0.0.1:3379
In another terminal, wait for the mirrored update:
./bin/etcdctl --endpoints=127.0.0.1:3379 watch '' --prefix --rev=4
Actual output:
PUT
key
new
Expected key: app/key. Deleting app/key on the source subsequently deletes key on the destination, while destination app/key still contains old.
Anything else we need to know?
The default destination prefix is assigned only inside if startRev == 0 in make_mirror_command.go. --rev values greater than 1 skip that branch. The existing revision test specifies --no-dest-prefix, which masks this case.
The incremental-sync feature was introduced in #13519. The open test migration #20908 does not change this initialization.
Etcd version
etcd Version: 3.8.0-alpha.0
Git SHA: 9ba96c87c
Go Version: go1.27.1
Go OS/Arch: linux/amd64
etcdctl version: 3.8.0-alpha.0
API version: 3.8
Etcd configuration
Two independent local single-member clusters with separate, empty data directories. No authentication or additional server settings are required.
Etcd debug information
The servers return successful operations. The incorrect key mapping occurs in etcdctl.
Relevant log output
The watch output above shows the incorrect destination key. In an isolated reproduction with a sentinel write to wait for sync completion:
After source PUT app/key new: {"app/key": "old", "key": "new"}
After source DELETE app/key: {"app/key": "old"}
Sentinel keys are omitted from these two state summaries.
Source: etcd-io/etcd