open-consul/snapshot/archive_test.go

135 lines
3.3 KiB
Go
Raw Normal View History

Adds support for snapshots and restores. (#2396) * Updates Raft library to get new snapshot/restore API. * Basic backup and restore working, but need some cleanup. * Breaks out a snapshot module and adds a SHA256 integrity check. * Adds snapshot ACL and fills in some missing comments. * Require a consistent read for snapshots. * Make sure snapshot works if ACLs aren't enabled. * Adds a bit of package documentation. * Returns an empty response from restore to avoid EOF errors. * Adds API client support for snapshots. * Makes internal file names match on-disk file snapshots. * Adds DC and token coverage for snapshot API test. * Adds missing documentation. * Adds a unit test for the snapshot client endpoint. * Moves the connection pool out of the client for easier testing. * Fixes an incidental issue in the prepared query unit test. I realized I had two servers in bootstrap mode so this wasn't a good setup. * Adds a half close to the TCP stream and fixes panic on error. * Adds client and endpoint tests for snapshots. * Moves the pool back into the snapshot RPC client. * Adds a TLS test and fixes half-closes for TLS connections. * Tweaks some comments. * Adds a low-level snapshot test. This is independent of Consul so we can pull this out into a library later if we want to. * Cleans up snapshot and archive and completes archive tests. * Sends a clear error for snapshot operations in dev mode. Snapshots require the Raft snapshots to be readable, which isn't supported in dev mode. Send a clear error instead of a deep-down Raft one. * Adds docs for the snapshot endpoint. * Adds a stale mode and index feedback for snapshot saves. This gives folks a way to extract data even if the cluster has no leader. * Changes the internal format of a snapshot from zip to tgz. * Pulls in Raft fix to cancel inflight before a restore. * Pulls in new Raft restore interface. * Adds metadata to snapshot saves and a verify function. * Adds basic save and restore snapshot CLI commands. * Gets rid of tarball extensions and adds restore message. * Fixes an incidental bad link in the KV docs. * Adds documentation for the snapshot CLI commands. * Scuttle any request body when a snapshot is saved. * Fixes archive unit test error message check. * Allows for nil output writers in snapshot RPC handlers. * Renames hash list Decode to DecodeAndVerify. * Closes the client connection for snapshot ops. * Lowers timeout for restore ops. * Updates Raft vendor to get new Restore signature and integrates with Consul. * Bounces the leader's internal state when we do a restore.
2016-10-26 02:20:24 +00:00
package snapshot
import (
"bytes"
"crypto/rand"
"fmt"
"io"
"io/ioutil"
"os"
"reflect"
"strings"
"testing"
"github.com/hashicorp/raft"
)
func TestArchive(t *testing.T) {
// Create some fake snapshot data.
metadata := raft.SnapshotMeta{
Index: 2005,
Term: 2011,
Configuration: raft.Configuration{
Servers: []raft.Server{
raft.Server{
Suffrage: raft.Voter,
ID: raft.ServerID("hello"),
Address: raft.ServerAddress("127.0.0.1:8300"),
},
},
},
Size: 1024,
}
var snap bytes.Buffer
var expected bytes.Buffer
both := io.MultiWriter(&snap, &expected)
if _, err := io.Copy(both, io.LimitReader(rand.Reader, 1024)); err != nil {
t.Fatalf("err: %v", err)
}
// Write out the snapshot.
var archive bytes.Buffer
if err := write(&archive, &metadata, &snap); err != nil {
t.Fatalf("err: %v", err)
}
// Read the snapshot back.
var newMeta raft.SnapshotMeta
var newSnap bytes.Buffer
if err := read(&archive, &newMeta, &newSnap); err != nil {
t.Fatalf("err: %v", err)
}
// Check the contents.
if !reflect.DeepEqual(newMeta, metadata) {
t.Fatalf("bad: %#v", newMeta)
}
var buf bytes.Buffer
if _, err := io.Copy(&buf, &newSnap); err != nil {
t.Fatalf("err: %v", err)
}
if !bytes.Equal(buf.Bytes(), expected.Bytes()) {
t.Fatalf("snapshot contents didn't match")
}
}
func TestArchive_BadData(t *testing.T) {
cases := []struct {
Name string
Error string
}{
{"../test/snapshot/empty.tar", "failed checking integrity of snapshot"},
{"../test/snapshot/extra.tar", "unexpected file \"nope\""},
{"../test/snapshot/missing-meta.tar", "hash check failed for \"meta.json\""},
{"../test/snapshot/missing-state.tar", "hash check failed for \"state.bin\""},
{"../test/snapshot/missing-sha.tar", "file missing"},
{"../test/snapshot/corrupt-meta.tar", "hash check failed for \"meta.json\""},
{"../test/snapshot/corrupt-state.tar", "hash check failed for \"state.bin\""},
{"../test/snapshot/corrupt-sha.tar", "list missing hash for \"nope\""},
Adds support for snapshots and restores. (#2396) * Updates Raft library to get new snapshot/restore API. * Basic backup and restore working, but need some cleanup. * Breaks out a snapshot module and adds a SHA256 integrity check. * Adds snapshot ACL and fills in some missing comments. * Require a consistent read for snapshots. * Make sure snapshot works if ACLs aren't enabled. * Adds a bit of package documentation. * Returns an empty response from restore to avoid EOF errors. * Adds API client support for snapshots. * Makes internal file names match on-disk file snapshots. * Adds DC and token coverage for snapshot API test. * Adds missing documentation. * Adds a unit test for the snapshot client endpoint. * Moves the connection pool out of the client for easier testing. * Fixes an incidental issue in the prepared query unit test. I realized I had two servers in bootstrap mode so this wasn't a good setup. * Adds a half close to the TCP stream and fixes panic on error. * Adds client and endpoint tests for snapshots. * Moves the pool back into the snapshot RPC client. * Adds a TLS test and fixes half-closes for TLS connections. * Tweaks some comments. * Adds a low-level snapshot test. This is independent of Consul so we can pull this out into a library later if we want to. * Cleans up snapshot and archive and completes archive tests. * Sends a clear error for snapshot operations in dev mode. Snapshots require the Raft snapshots to be readable, which isn't supported in dev mode. Send a clear error instead of a deep-down Raft one. * Adds docs for the snapshot endpoint. * Adds a stale mode and index feedback for snapshot saves. This gives folks a way to extract data even if the cluster has no leader. * Changes the internal format of a snapshot from zip to tgz. * Pulls in Raft fix to cancel inflight before a restore. * Pulls in new Raft restore interface. * Adds metadata to snapshot saves and a verify function. * Adds basic save and restore snapshot CLI commands. * Gets rid of tarball extensions and adds restore message. * Fixes an incidental bad link in the KV docs. * Adds documentation for the snapshot CLI commands. * Scuttle any request body when a snapshot is saved. * Fixes archive unit test error message check. * Allows for nil output writers in snapshot RPC handlers. * Renames hash list Decode to DecodeAndVerify. * Closes the client connection for snapshot ops. * Lowers timeout for restore ops. * Updates Raft vendor to get new Restore signature and integrates with Consul. * Bounces the leader's internal state when we do a restore.
2016-10-26 02:20:24 +00:00
}
for i, c := range cases {
f, err := os.Open(c.Name)
if err != nil {
t.Fatalf("err: %v", err)
}
defer f.Close()
var metadata raft.SnapshotMeta
err = read(f, &metadata, ioutil.Discard)
if err == nil || !strings.Contains(err.Error(), c.Error) {
t.Fatalf("case %d (%s): %v", i, c.Name, err)
}
}
}
func TestArchive_hashList(t *testing.T) {
hl := newHashList()
for i := 0; i < 16; i++ {
h := hl.Add(fmt.Sprintf("file-%d", i))
if _, err := io.CopyN(h, rand.Reader, 32); err != nil {
t.Fatalf("err: %v", err)
}
}
// Do a normal round trip.
var buf bytes.Buffer
if err := hl.Encode(&buf); err != nil {
t.Fatalf("err: %v", err)
}
if err := hl.DecodeAndVerify(&buf); err != nil {
t.Fatalf("err: %v", err)
}
// Have a local hash that isn't in the file.
buf.Reset()
if err := hl.Encode(&buf); err != nil {
t.Fatalf("err: %v", err)
}
hl.Add("nope")
err := hl.DecodeAndVerify(&buf)
if err == nil || !strings.Contains(err.Error(), "file missing for \"nope\"") {
t.Fatalf("err: %v", err)
}
// Have a hash in the file that we haven't seen locally.
buf.Reset()
if err := hl.Encode(&buf); err != nil {
t.Fatalf("err: %v", err)
}
delete(hl.hashes, "nope")
err = hl.DecodeAndVerify(&buf)
if err == nil || !strings.Contains(err.Error(), "list missing hash for \"nope\"") {
t.Fatalf("err: %v", err)
}
}