Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ea91b78afd |
@@ -2,7 +2,9 @@ package cli //nolint:testpackage // shares hermeticConfig and the capture helper
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -91,8 +93,9 @@ func TestEntryJSONFailureIsReportedOnStderr(t *testing.T) {
|
|||||||
// --json` on a snapshot in the local index, against a destination
|
// --json` on a snapshot in the local index, against a destination
|
||||||
// directory that does not exist. The command removes the snapshot from
|
// directory that does not exist. The command removes the snapshot from
|
||||||
// the local index and still exits 0. Its stdout must hold the document
|
// the local index and still exits 0. Its stdout must hold the document
|
||||||
// alone, with the warning about the destination store, and the command
|
// alone, with the warning about the destination store on stderr: the
|
||||||
// to run again once it is reachable, on stderr.
|
// command to run again once it is reachable, and the snapshot's ID in
|
||||||
|
// the record's snapshot_id field.
|
||||||
//
|
//
|
||||||
//nolint:paralleltest // replaces os.Args, os.Stdout, os.Stderr and the xdg globals
|
//nolint:paralleltest // replaces os.Args, os.Stdout, os.Stderr and the xdg globals
|
||||||
func TestEntrySnapshotRemoveJSONWarningIsOnStderr(t *testing.T) {
|
func TestEntrySnapshotRemoveJSONWarningIsOnStderr(t *testing.T) {
|
||||||
@@ -104,10 +107,21 @@ func TestEntrySnapshotRemoveJSONWarningIsOnStderr(t *testing.T) {
|
|||||||
|
|
||||||
require.Equal(t, 0, code)
|
require.Equal(t, 0, code)
|
||||||
requireExactlyOneJSONDocument(t, stdout)
|
requireExactlyOneJSONDocument(t, stdout)
|
||||||
assert.Contains(t, stderr,
|
|
||||||
"Could not remove snapshot metadata from remote storage")
|
// stderr is a pipe here, so the logger writes one JSON record a line.
|
||||||
assert.Contains(t, stderr,
|
var warning map[string]any
|
||||||
"run 'vaultik snapshot remove "+stalePruneSnapshotID+"' again")
|
|
||||||
|
for line := range strings.Lines(stderr) {
|
||||||
|
if strings.Contains(line,
|
||||||
|
"Could not remove snapshot metadata from remote storage") {
|
||||||
|
require.NoError(t, json.Unmarshal([]byte(line), &warning))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
require.NotNil(t, warning, "the warning must reach stderr")
|
||||||
|
assert.Contains(t, warning[slog.MessageKey],
|
||||||
|
"run 'vaultik snapshot remove' with the snapshot's ID again")
|
||||||
|
assert.Equal(t, stalePruneSnapshotID, warning["snapshot_id"])
|
||||||
}
|
}
|
||||||
|
|
||||||
// writeMissingDestinationConfig builds a config whose destination
|
// writeMissingDestinationConfig builds a config whose destination
|
||||||
|
|||||||
@@ -1110,6 +1110,12 @@ type RemoveResult struct {
|
|||||||
// just-removed snapshot left behind on the destination store.
|
// just-removed snapshot left behind on the destination store.
|
||||||
const pruneCommandHint = "vaultik prune"
|
const pruneCommandHint = "vaultik prune"
|
||||||
|
|
||||||
|
// snapshotRemoveCommandHint is the command suggested, with the
|
||||||
|
// snapshot's ID, when a remove could not reach the destination store:
|
||||||
|
// running it again removes the snapshot's metadata there, which
|
||||||
|
// `vaultik prune` never does.
|
||||||
|
const snapshotRemoveCommandHint = "vaultik snapshot remove"
|
||||||
|
|
||||||
// RemoveSnapshot removes a snapshot from the local index database and,
|
// RemoveSnapshot removes a snapshot from the local index database and,
|
||||||
// unless LocalOnly is set, also strips the snapshot's metadata from the
|
// unless LocalOnly is set, also strips the snapshot's metadata from the
|
||||||
// destination store. Blobs are NOT touched: removing a snapshot's
|
// destination store. Blobs are NOT touched: removing a snapshot's
|
||||||
@@ -1241,18 +1247,17 @@ func (v *Vaultik) removeSnapshotRemote(snapshotID string, opts *RemoveOptions) b
|
|||||||
|
|
||||||
err := v.deleteRemoteSnapshotByKey(remoteKey)
|
err := v.deleteRemoteSnapshotByKey(remoteKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
removeCommand := "vaultik snapshot remove " + snapshotID
|
|
||||||
|
|
||||||
log.Warn("Could not remove snapshot metadata from remote storage; "+
|
log.Warn("Could not remove snapshot metadata from remote storage; "+
|
||||||
"run '"+removeCommand+"' again once the remote is reachable",
|
"run '"+snapshotRemoveCommandHint+"' with the snapshot's ID "+
|
||||||
"error", err)
|
"again once the remote is reachable",
|
||||||
|
"snapshot_id", snapshotID, "error", err)
|
||||||
|
|
||||||
// The UI writes to stdout, which under --json holds only the
|
// The UI writes to stdout, which under --json holds only the
|
||||||
// document; the log record above is the warning on stderr.
|
// document; the log record above is the warning on stderr.
|
||||||
if v.UI != nil && !opts.JSON {
|
if v.UI != nil && !opts.JSON {
|
||||||
v.UI.Warningf("Could not remove snapshot metadata from remote: "+
|
v.UI.Warningf("Could not remove snapshot metadata from remote: "+
|
||||||
"%v. Run '%s' again once the remote is reachable.",
|
"%v. Run '%s %s' again once the remote is reachable.",
|
||||||
err, removeCommand)
|
err, snapshotRemoveCommandHint, snapshotID)
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
return false
|
||||||
|
|||||||
Reference in New Issue
Block a user