Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
39ca0e3111 |
@@ -336,11 +336,9 @@ local index alone, and still exits zero.
|
|||||||
(whether the snapshot is in the local index), `remote_key` (the full
|
(whether the snapshot is in the local index), `remote_key` (the full
|
||||||
64-character storage key), and `remote_present` (whether it was seen
|
64-character storage key), and `remote_present` (whether it was seen
|
||||||
on the destination store, or `null` if the destination could not be
|
on the destination store, or `null` if the destination could not be
|
||||||
listed). Warnings about an unlistable destination, a local index
|
listed). Warnings about an unlistable destination, unreadable
|
||||||
bound to a different destination (with both destinations and the
|
manifests, and a truncated listing all go to stderr through the
|
||||||
same two ways out), unreadable manifests, and a truncated listing all
|
logger, so stdout stays a single parseable document.
|
||||||
go to stderr through the logger, so stdout stays a single parseable
|
|
||||||
document.
|
|
||||||
|
|
||||||
**`snapshot verify`**: Verify snapshot integrity.
|
**`snapshot verify`**: Verify snapshot integrity.
|
||||||
* Default (shallow): checks that every blob the manifest lists is present in
|
* Default (shallow): checks that every blob the manifest lists is present in
|
||||||
|
|||||||
@@ -105,26 +105,7 @@ func (v *Vaultik) ListSnapshots(jsonOutput bool) error {
|
|||||||
return snapshots[i].Timestamp.After(snapshots[j].Timestamp)
|
return snapshots[i].Timestamp.After(snapshots[j].Timestamp)
|
||||||
})
|
})
|
||||||
|
|
||||||
stored, configured, err := v.storageBinding()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// A local index bound to another destination describes that one, so
|
|
||||||
// its records are expected to be missing here, and prune refuses to
|
|
||||||
// run. The binding is reported instead of advising prune.
|
|
||||||
boundElsewhere := stored != "" && stored != configured
|
|
||||||
|
|
||||||
if jsonOutput {
|
if jsonOutput {
|
||||||
// stdout holds only the document, so this goes to the logger.
|
|
||||||
if boundElsewhere {
|
|
||||||
log.Warn("Local index is bound to a different backup "+
|
|
||||||
"destination; to proceed, revert storage_url (or the s3.* "+
|
|
||||||
"endpoint, bucket and prefix) to the bound destination, "+
|
|
||||||
"or run 'vaultik database delete'",
|
|
||||||
"bound_to", stored, "configured", configured)
|
|
||||||
}
|
|
||||||
|
|
||||||
if remoteErr == nil {
|
if remoteErr == nil {
|
||||||
v.reportJSONListingLimits(listing)
|
v.reportJSONListingLimits(listing)
|
||||||
}
|
}
|
||||||
@@ -146,6 +127,15 @@ func (v *Vaultik) ListSnapshots(jsonOutput bool) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
stored, configured, err := v.storageBinding()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// A local index bound to another destination describes that one, so
|
||||||
|
// its records are expected to be missing here, and prune refuses to
|
||||||
|
// run. The binding is reported instead of advising prune.
|
||||||
|
boundElsewhere := stored != "" && stored != configured
|
||||||
if boundElsewhere {
|
if boundElsewhere {
|
||||||
v.UI.Warningf("%v\n%s", errStorageBindingMismatch,
|
v.UI.Warningf("%v\n%s", errStorageBindingMismatch,
|
||||||
buildBindingMismatchMessage(stored, configured))
|
buildBindingMismatchMessage(stored, configured))
|
||||||
|
|||||||
@@ -456,39 +456,6 @@ func TestListSnapshots_BoundElsewhereDoesNotAdvisePrune(t *testing.T) {
|
|||||||
assert.NotContains(t, out, "vaultik prune")
|
assert.NotContains(t, out, "vaultik prune")
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestListSnapshots_JSONReportsBoundElsewhere is the --json side of the
|
|
||||||
// test above. Every local row comes out with remote_present false, which
|
|
||||||
// a script reads as stale local records unless it is told, on stderr,
|
|
||||||
// that the local index is bound to a different destination.
|
|
||||||
//
|
|
||||||
//nolint:paralleltest // captureProcessStderr replaces os.Stderr
|
|
||||||
func TestListSnapshots_JSONReportsBoundElsewhere(t *testing.T) {
|
|
||||||
const (
|
|
||||||
oldURL = "file:///mnt/backups/old"
|
|
||||||
newURL = "file:///mnt/backups/new"
|
|
||||||
)
|
|
||||||
|
|
||||||
env := newListEnv(t)
|
|
||||||
env.v.Config.StorageURL = newURL
|
|
||||||
require.NoError(t, env.v.Repositories.LocalMeta.Set(context.Background(),
|
|
||||||
database.LocalMetaKeyStorageURL, oldURL))
|
|
||||||
env.addLocal(t, listLocalID, time.Date(2026, 3, 1, 10, 0, 0, 0, time.UTC))
|
|
||||||
|
|
||||||
stderr := captureProcessStderr(t, func() {
|
|
||||||
require.NoError(t, env.v.ListSnapshots(true))
|
|
||||||
})
|
|
||||||
|
|
||||||
rows := decodeListJSON(t, env.stdout.String())
|
|
||||||
require.Len(t, rows, 1)
|
|
||||||
assert.Equal(t, listLocalID, rows[0].ID)
|
|
||||||
|
|
||||||
assert.Contains(t, stderr, "bound to a different backup destination")
|
|
||||||
assert.Contains(t, stderr, oldURL)
|
|
||||||
assert.Contains(t, stderr, newURL)
|
|
||||||
assert.Contains(t, stderr, "revert storage_url")
|
|
||||||
assert.Contains(t, stderr, "vaultik database delete")
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestListSnapshots_UnreachableRemoteDegrades covers the promise in the
|
// TestListSnapshots_UnreachableRemoteDegrades covers the promise in the
|
||||||
// doc comment: an unreachable destination is a warning plus local-only
|
// doc comment: an unreachable destination is a warning plus local-only
|
||||||
// output, never a failure.
|
// output, never a failure.
|
||||||
|
|||||||
Reference in New Issue
Block a user