1 Commits
Author SHA1 Message Date
clawbot 2564116149 restore and verify report an unknown snapshot ID as not found (closes #426)
check / check (push) Successful in 9m32s
A snapshot ID that names no snapshot in the local index or on the
destination store made restore and verify fail on a missing object at
a hashed path, and verify printed a header for it first. Resolving a
snapshot ID now uses the look-up `snapshot remove` already does, so
all three commands give the same error, and verify prints its header
only after the snapshot is found.

Model: opus-5-5
2026-11-11 01:19:05 +00:00
3 changed files with 1218 additions and 21 deletions

No files matched your search

+1205 -3
View File
File diff suppressed because it is too large. Load diff
+11 -16
View File
@@ -1477,7 +1477,7 @@ func (v *Vaultik) RemoveSnapshot(
return result, err
}
inLocalIndex, err := v.checkSnapshotExists(snapshotID, opts.LocalOnly)
inLocalIndex, err := v.findSnapshot(snapshotID, opts.LocalOnly)
if err != nil {
return result, err
}
@@ -1540,20 +1540,15 @@ func (v *Vaultik) RemoveSnapshot(
return result, nil
}
// checkSnapshotExists returns errSnapshotNotFound when the local index
// has no row for snapshotID and, unless localOnly is set, the
// destination store has no metadata for it either. inLocalIndex reports
// whether the local index has that row. The destination store is
// consulted only when the local index has no row, so a snapshot in the
// local index can still be removed from it while the destination store
// is unreachable, and only after checkDestinationMarker passes, so an
// unplugged volume's empty mount point is not taken for a store without
// the snapshot.
//
//nolint:nonamedreturns // the result name says what the bool means
func (v *Vaultik) checkSnapshotExists(
snapshotID string, localOnly bool,
) (inLocalIndex bool, err error) {
// findSnapshot reports whether the local index has a row for
// snapshotID, and returns errSnapshotNotFound when there is no row and,
// unless localOnly is set, no metadata on the destination store either.
// The destination store is consulted only when the local index has no
// row, so a snapshot in the local index can still be removed from it
// while the destination store is unreachable, and only after
// checkDestinationMarker passes, so an unplugged volume's empty mount
// point is not taken for a store without the snapshot.
func (v *Vaultik) findSnapshot(snapshotID string, localOnly bool) (bool, error) {
if v.Repositories != nil {
snap, err := v.Repositories.Snapshots.GetByID(v.ctx, snapshotID)
if err != nil {
@@ -1570,7 +1565,7 @@ func (v *Vaultik) checkSnapshotExists(
errSnapshotNotFound, snapshotID)
}
err = v.checkDestinationMarker()
err := v.checkDestinationMarker()
if err != nil {
return false, err
}
+2 -2
View File
@@ -30,7 +30,7 @@ var (
// - A human snapshot ID (hostname_name_timestamp), which a host holding
// the local index has. It is hashed to its remote key. An ID that
// names no snapshot in the local index or on the destination store
// is an error (see checkSnapshotExists).
// is an error (see findSnapshot).
// - A remote key, or the leading part of one, which is all a host with
// no local index can know — it is exactly what `snapshot list` prints
// for a remote-only snapshot (see formatRemoteOnlyID). It is resolved
@@ -42,7 +42,7 @@ var (
// RFC3339 timestamp).
func (v *Vaultik) resolveSnapshotRemoteKey(identifier string) (string, error) {
if !isRemoteKeyOrPrefix(identifier) {
_, err := v.checkSnapshotExists(identifier, false)
_, err := v.findSnapshot(identifier, false)
if err != nil {
return "", err
}