Fail snapshot remove when a destination-only snapshot's metadata cannot be deleted (closes #340)
check / check (push) Canceled after 0s
check / check (push) Canceled after 0s
When a snapshot was only on the destination store and deleting its metadata there failed, snapshot remove warned and exited 0 having removed nothing. That failure is now an error. A snapshot in the local index keeps its behaviour: it is removed from the local index and the failed delete on the destination store is a warning. The README and the help text said the `vaultik prune` follow-up is printed on every success; they now say it is printed only when metadata was removed from the destination store, and never under --json. The comments on RemoveSnapshot and removeSnapshotRemote describe both cases; removeSnapshotRemote's also says it returns true only when the delete finished without an error and removed at least one object. Model: opus-5-5
This commit was merged in pull request #370.
This commit is contained in:
1 parent
5db2e920e5
commit
9fd88a34c7
4 files changed
+89
-29
No files matched your search
@@ -1228,9 +1228,11 @@ const snapshotRemoveCommandHint = "vaultik snapshot remove"
|
||||
// destination store. Blobs are NOT touched: removing a snapshot's
|
||||
// blobs requires reading every remaining remote manifest (the remote
|
||||
// may hold snapshots this host doesn't know about), which is what
|
||||
// `vaultik prune` is for — the command prints the prune invocation to
|
||||
// run as a follow-up. When the remote is unreachable the command still
|
||||
// completes the local-DB removal and warns.
|
||||
// `vaultik prune` is for — when metadata was removed from the
|
||||
// destination store, the text output names the prune invocation to run
|
||||
// as a follow-up. When removing the metadata fails, a snapshot in the
|
||||
// local index is still removed from it, with a warning; a snapshot
|
||||
// only on the destination store is an error.
|
||||
func (v *Vaultik) RemoveSnapshot(
|
||||
snapshotID string, opts *RemoveOptions,
|
||||
) (*RemoveResult, error) {
|
||||
@@ -1265,8 +1267,10 @@ func (v *Vaultik) RemoveSnapshot(
|
||||
}
|
||||
}
|
||||
|
||||
if !opts.LocalOnly {
|
||||
result.RemoteRemoved = v.removeSnapshotRemote(snapshotID, opts)
|
||||
result.RemoteRemoved, err = v.removeSnapshotRemote(
|
||||
snapshotID, inLocalIndex, opts)
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
|
||||
if v.SnapshotManager != nil {
|
||||
@@ -1391,19 +1395,33 @@ func (v *Vaultik) confirmRemoveSnapshot(snapshotID string, opts *RemoveOptions)
|
||||
}
|
||||
|
||||
// removeSnapshotRemote strips the snapshot's metadata from the
|
||||
// destination store, warning and proceeding on failure: the local-DB
|
||||
// removal has already happened, so the user is told the remote half
|
||||
// didn't finish and to run `vaultik snapshot remove` for the snapshot
|
||||
// again once the destination store is reachable (`vaultik prune` never
|
||||
// removes snapshot metadata). Returns true when the remote removal
|
||||
// succeeded and deleted something.
|
||||
func (v *Vaultik) removeSnapshotRemote(snapshotID string, opts *RemoveOptions) bool {
|
||||
// destination store. It returns true only when the delete finished
|
||||
// without an error and removed at least one object; under LocalOnly it
|
||||
// does nothing. When the snapshot is only on the destination store, a
|
||||
// failure is returned as an error, because that removal is all the
|
||||
// command does. When the snapshot was in the local index, its removal
|
||||
// there has already happened, so a failure is only a warning telling the
|
||||
// user to run `vaultik snapshot remove` for the snapshot again once the
|
||||
// destination store is reachable (`vaultik prune` never removes snapshot
|
||||
// metadata).
|
||||
func (v *Vaultik) removeSnapshotRemote(
|
||||
snapshotID string, inLocalIndex bool, opts *RemoveOptions,
|
||||
) (bool, error) {
|
||||
if opts.LocalOnly {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
log.Info("Removing snapshot metadata from remote storage",
|
||||
"snapshot_id", snapshotID)
|
||||
|
||||
remoteKey := snapshot.RemoteSnapshotKey(snapshotID)
|
||||
|
||||
deleted, err := v.deleteRemoteSnapshotByKey(remoteKey)
|
||||
if err != nil && !inLocalIndex {
|
||||
return false, fmt.Errorf(
|
||||
"removing snapshot metadata from destination store: %w", err)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
log.Warn("Could not remove snapshot metadata from remote storage; "+
|
||||
"run '"+snapshotRemoveCommandHint+"' with the snapshot's ID "+
|
||||
@@ -1418,10 +1436,10 @@ func (v *Vaultik) removeSnapshotRemote(snapshotID string, opts *RemoveOptions) b
|
||||
err, snapshotRemoveCommandHint, snapshotID)
|
||||
}
|
||||
|
||||
return false
|
||||
return false, nil
|
||||
}
|
||||
|
||||
return deleted > 0
|
||||
return deleted > 0, nil
|
||||
}
|
||||
|
||||
// RemoveAllSnapshots removes every snapshot known to the local
|
||||
|
||||
Reference in new issue
Block a user