CLI: Allow snapshot inspect to work on internal raft snapshots directly. (#10089)
* CLI: Add support for reading internal raft snapshots to snapshot inspect * Add snapshot inspect test for raw state files * Add changelog entry * Update .changelog/10089.txt
This commit is contained in:
parent
d605632216
commit
5c409739c7
|
@ -0,0 +1,4 @@
|
||||||
|
```release-note:improvement
|
||||||
|
cli: snapshot inspect command can now inspect raw snapshots from a server's data
|
||||||
|
dir.
|
||||||
|
```
|
|
@ -1,10 +1,13 @@
|
||||||
package inspect
|
package inspect
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
"path"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
@ -111,18 +114,41 @@ func (c *cmd) Run(args []string) int {
|
||||||
}
|
}
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
|
|
||||||
readFile, meta, err := snapshot.Read(hclog.New(nil), f)
|
var readFile *os.File
|
||||||
if err != nil {
|
var meta *raft.SnapshotMeta
|
||||||
c.UI.Error(fmt.Sprintf("Error reading snapshot: %s", err))
|
|
||||||
|
if strings.ToLower(path.Base(file)) == "state.bin" {
|
||||||
|
// This is an internal raw raft snapshot not a gzipped archive one
|
||||||
|
// downloaded from the API, we can read it directly
|
||||||
|
readFile = f
|
||||||
|
|
||||||
|
// Assume the meta is colocated and error if not.
|
||||||
|
metaRaw, err := ioutil.ReadFile(path.Join(path.Dir(file), "meta.json"))
|
||||||
|
if err != nil {
|
||||||
|
c.UI.Error(fmt.Sprintf("Error reading meta.json from internal snapshot dir: %s", err))
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
var metaDecoded raft.SnapshotMeta
|
||||||
|
err = json.Unmarshal(metaRaw, &metaDecoded)
|
||||||
|
if err != nil {
|
||||||
|
c.UI.Error(fmt.Sprintf("Error parsing meta.json from internal snapshot dir: %s", err))
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
meta = &metaDecoded
|
||||||
|
} else {
|
||||||
|
readFile, meta, err = snapshot.Read(hclog.New(nil), f)
|
||||||
|
if err != nil {
|
||||||
|
c.UI.Error(fmt.Sprintf("Error reading snapshot: %s", err))
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
if err := readFile.Close(); err != nil {
|
||||||
|
c.UI.Error(fmt.Sprintf("Failed to close temp snapshot: %v", err))
|
||||||
|
}
|
||||||
|
if err := os.Remove(readFile.Name()); err != nil {
|
||||||
|
c.UI.Error(fmt.Sprintf("Failed to clean up temp snapshot: %v", err))
|
||||||
|
}
|
||||||
|
}()
|
||||||
}
|
}
|
||||||
defer func() {
|
|
||||||
if err := readFile.Close(); err != nil {
|
|
||||||
c.UI.Error(fmt.Sprintf("Failed to close temp snapshot: %v", err))
|
|
||||||
}
|
|
||||||
if err := os.Remove(readFile.Name()); err != nil {
|
|
||||||
c.UI.Error(fmt.Sprintf("Failed to clean up temp snapshot: %v", err))
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
info, err := c.enhance(readFile)
|
info, err := c.enhance(readFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -149,3 +149,23 @@ func TestSnapshotInspectKVDetailsDepthFilterCommand(t *testing.T) {
|
||||||
want := golden(t, t.Name(), ui.OutputWriter.String())
|
want := golden(t, t.Name(), ui.OutputWriter.String())
|
||||||
require.Equal(t, want, ui.OutputWriter.String())
|
require.Equal(t, want, ui.OutputWriter.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestSnapshotInspectCommandRaw test reading a snaphost directly from a raft
|
||||||
|
// data dir.
|
||||||
|
func TestSnapshotInspectCommandRaw(t *testing.T) {
|
||||||
|
|
||||||
|
filepath := "./testdata/raw/state.bin"
|
||||||
|
|
||||||
|
// Inspect the snapshot
|
||||||
|
ui := cli.NewMockUi()
|
||||||
|
c := New(ui)
|
||||||
|
args := []string{filepath}
|
||||||
|
|
||||||
|
code := c.Run(args)
|
||||||
|
if code != 0 {
|
||||||
|
t.Fatalf("bad: %d. %#v", code, ui.ErrorWriter.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
want := golden(t, t.Name(), ui.OutputWriter.String())
|
||||||
|
require.Equal(t, want, ui.OutputWriter.String())
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
ID 2-13-1602222343947
|
||||||
|
Size 5141
|
||||||
|
Index 13
|
||||||
|
Term 2
|
||||||
|
Version 1
|
||||||
|
|
||||||
|
Type Count Size
|
||||||
|
---- ---- ----
|
||||||
|
Register 3 1.7KB
|
||||||
|
ConnectCA 1 1.2KB
|
||||||
|
ConnectCAProviderState 1 1.1KB
|
||||||
|
Index 12 344B
|
||||||
|
Autopilot 1 199B
|
||||||
|
ConnectCAConfig 1 197B
|
||||||
|
FederationState 1 139B
|
||||||
|
SystemMetadata 1 68B
|
||||||
|
ChunkingState 1 12B
|
||||||
|
---- ---- ----
|
||||||
|
Total 5KB
|
|
@ -0,0 +1 @@
|
||||||
|
{"Version":1,"ID":"2-13-1602222343947","Index":13,"Term":2,"Peers":"ka4xMjcuMC4wLjE6ODMwMA==","Configuration":{"Servers":[{"Suffrage":0,"ID":"a577b288-b354-770e-e909-da0972eb20e8","Address":"127.0.0.1:8300"}]},"ConfigurationIndex":1,"Size":5141}
|
Binary file not shown.
|
@ -12,6 +12,15 @@ snapshot of the state of the Consul servers which includes key/value entries,
|
||||||
service catalog, prepared queries, sessions, and ACLs. The snapshot is read
|
service catalog, prepared queries, sessions, and ACLs. The snapshot is read
|
||||||
from the given file.
|
from the given file.
|
||||||
|
|
||||||
|
-> Typically this is used with Consul self-contained Snapshot files obtained
|
||||||
|
using the [`consul snapshot`](/commands/snapshot) command or [Snapshot
|
||||||
|
API](/api-docs/snapshot#generate-snapshot). If the file provided is named
|
||||||
|
`state.bin` however, the command will assume it is a raw raft snapshot in a
|
||||||
|
Consul server data directory and will attempt to read it directly. The
|
||||||
|
`state.bin` file must still be in the same directory as it's associated
|
||||||
|
`meta.json` file. This is useful for debugging data on live servers without
|
||||||
|
making a complete new snapshot via the CLI or API first.
|
||||||
|
|
||||||
The following fields are displayed when inspecting a snapshot:
|
The following fields are displayed when inspecting a snapshot:
|
||||||
|
|
||||||
- `ID` - A unique ID for the snapshot, only used for differentiation purposes.
|
- `ID` - A unique ID for the snapshot, only used for differentiation purposes.
|
||||||
|
@ -106,6 +115,29 @@ $ consul snapshot inspect -kvdetails -kvdepth 3 -kvfilter vault/core backup.snap
|
||||||
Please see the [HTTP API](/api/snapshot) documentation for
|
Please see the [HTTP API](/api/snapshot) documentation for
|
||||||
more details about snapshot internals.
|
more details about snapshot internals.
|
||||||
|
|
||||||
|
To inspect an internal snapshot directly from a Consul server data directory:
|
||||||
|
|
||||||
|
```shell-session
|
||||||
|
$ consul snapshot inspect /opt/consul/raft/snapshots/9-4600669-1618935304715/state.bin
|
||||||
|
ID 9-4600669-1618935304715
|
||||||
|
Size 4625420898
|
||||||
|
Index 4600669
|
||||||
|
Term 9
|
||||||
|
Version 1
|
||||||
|
|
||||||
|
Type Count Size
|
||||||
|
---- ---- ----
|
||||||
|
KVS 4089785 4.3GB
|
||||||
|
Register 9 5.2KB
|
||||||
|
CoordinateBatchUpdate 3 465B
|
||||||
|
Index 8 224B
|
||||||
|
Autopilot 1 199B
|
||||||
|
FederationState 1 139B
|
||||||
|
ChunkingState 1 12B
|
||||||
|
---- ---- ----
|
||||||
|
Total 4.3GB
|
||||||
|
```
|
||||||
|
|
||||||
#### Command Options
|
#### Command Options
|
||||||
|
|
||||||
- `-kvdetails` - Optional, provides a space usage breakdown for any KV data stored in Consul.
|
- `-kvdetails` - Optional, provides a space usage breakdown for any KV data stored in Consul.
|
||||||
|
|
Loading…
Reference in New Issue