|
|
@ -2,7 +2,6 @@ package fsm
|
|
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"bytes"
|
|
|
|
"reflect"
|
|
|
|
|
|
|
|
"testing"
|
|
|
|
"testing"
|
|
|
|
"time"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
|
|
|
@ -14,21 +13,17 @@ import (
|
|
|
|
"github.com/hashicorp/consul/api"
|
|
|
|
"github.com/hashicorp/consul/api"
|
|
|
|
"github.com/hashicorp/consul/lib/stringslice"
|
|
|
|
"github.com/hashicorp/consul/lib/stringslice"
|
|
|
|
"github.com/hashicorp/consul/sdk/testutil"
|
|
|
|
"github.com/hashicorp/consul/sdk/testutil"
|
|
|
|
|
|
|
|
"github.com/hashicorp/go-msgpack/codec"
|
|
|
|
"github.com/hashicorp/go-raftchunking"
|
|
|
|
"github.com/hashicorp/go-raftchunking"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
func TestFSM_SnapshotRestore_OSS(t *testing.T) {
|
|
|
|
func TestFSM_SnapshotRestore_OSS(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
|
|
|
|
assert := assert.New(t)
|
|
|
|
|
|
|
|
require := require.New(t)
|
|
|
|
|
|
|
|
logger := testutil.Logger(t)
|
|
|
|
logger := testutil.Logger(t)
|
|
|
|
fsm, err := New(nil, logger)
|
|
|
|
fsm, err := New(nil, logger)
|
|
|
|
if err != nil {
|
|
|
|
require.NoError(t, err)
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Add some state
|
|
|
|
// Add some state
|
|
|
|
node1 := &structs.Node{
|
|
|
|
node1 := &structs.Node{
|
|
|
@ -49,8 +44,8 @@ func TestFSM_SnapshotRestore_OSS(t *testing.T) {
|
|
|
|
"testMeta": "testing123",
|
|
|
|
"testMeta": "testing123",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
require.NoError(fsm.state.EnsureNode(1, node1))
|
|
|
|
require.NoError(t, fsm.state.EnsureNode(1, node1))
|
|
|
|
require.NoError(fsm.state.EnsureNode(2, node2))
|
|
|
|
require.NoError(t, fsm.state.EnsureNode(2, node2))
|
|
|
|
|
|
|
|
|
|
|
|
// Add a service instance with Connect config.
|
|
|
|
// Add a service instance with Connect config.
|
|
|
|
connectConf := structs.ServiceConnect{
|
|
|
|
connectConf := structs.ServiceConnect{
|
|
|
@ -89,7 +84,7 @@ func TestFSM_SnapshotRestore_OSS(t *testing.T) {
|
|
|
|
Syntax: acl.SyntaxCurrent,
|
|
|
|
Syntax: acl.SyntaxCurrent,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
policy.SetHash(true)
|
|
|
|
policy.SetHash(true)
|
|
|
|
require.NoError(fsm.state.ACLPolicySet(1, policy))
|
|
|
|
require.NoError(t, fsm.state.ACLPolicySet(1, policy))
|
|
|
|
|
|
|
|
|
|
|
|
role := &structs.ACLRole{
|
|
|
|
role := &structs.ACLRole{
|
|
|
|
ID: "86dedd19-8fae-4594-8294-4e6948a81f9a",
|
|
|
|
ID: "86dedd19-8fae-4594-8294-4e6948a81f9a",
|
|
|
@ -102,7 +97,7 @@ func TestFSM_SnapshotRestore_OSS(t *testing.T) {
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
role.SetHash(true)
|
|
|
|
role.SetHash(true)
|
|
|
|
require.NoError(fsm.state.ACLRoleSet(1, role))
|
|
|
|
require.NoError(t, fsm.state.ACLRoleSet(1, role))
|
|
|
|
|
|
|
|
|
|
|
|
token := &structs.ACLToken{
|
|
|
|
token := &structs.ACLToken{
|
|
|
|
AccessorID: "30fca056-9fbb-4455-b94a-bf0e2bc575d6",
|
|
|
|
AccessorID: "30fca056-9fbb-4455-b94a-bf0e2bc575d6",
|
|
|
@ -118,7 +113,7 @@ func TestFSM_SnapshotRestore_OSS(t *testing.T) {
|
|
|
|
// DEPRECATED (ACL-Legacy-Compat) - This is used so that the bootstrap token is still visible via the v1 acl APIs
|
|
|
|
// DEPRECATED (ACL-Legacy-Compat) - This is used so that the bootstrap token is still visible via the v1 acl APIs
|
|
|
|
Type: structs.ACLTokenTypeManagement,
|
|
|
|
Type: structs.ACLTokenTypeManagement,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
require.NoError(fsm.state.ACLBootstrap(10, 0, token, false))
|
|
|
|
require.NoError(t, fsm.state.ACLBootstrap(10, 0, token, false))
|
|
|
|
|
|
|
|
|
|
|
|
method := &structs.ACLAuthMethod{
|
|
|
|
method := &structs.ACLAuthMethod{
|
|
|
|
Name: "some-method",
|
|
|
|
Name: "some-method",
|
|
|
@ -128,7 +123,7 @@ func TestFSM_SnapshotRestore_OSS(t *testing.T) {
|
|
|
|
"SessionID": "952ebfa8-2a42-46f0-bcd3-fd98a842000e",
|
|
|
|
"SessionID": "952ebfa8-2a42-46f0-bcd3-fd98a842000e",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
require.NoError(fsm.state.ACLAuthMethodSet(1, method))
|
|
|
|
require.NoError(t, fsm.state.ACLAuthMethodSet(1, method))
|
|
|
|
|
|
|
|
|
|
|
|
bindingRule := &structs.ACLBindingRule{
|
|
|
|
bindingRule := &structs.ACLBindingRule{
|
|
|
|
ID: "85184c52-5997-4a84-9817-5945f2632a17",
|
|
|
|
ID: "85184c52-5997-4a84-9817-5945f2632a17",
|
|
|
@ -138,7 +133,7 @@ func TestFSM_SnapshotRestore_OSS(t *testing.T) {
|
|
|
|
BindType: structs.BindingRuleBindTypeService,
|
|
|
|
BindType: structs.BindingRuleBindTypeService,
|
|
|
|
BindName: "${serviceaccount.name}",
|
|
|
|
BindName: "${serviceaccount.name}",
|
|
|
|
}
|
|
|
|
}
|
|
|
|
require.NoError(fsm.state.ACLBindingRuleSet(1, bindingRule))
|
|
|
|
require.NoError(t, fsm.state.ACLBindingRuleSet(1, bindingRule))
|
|
|
|
|
|
|
|
|
|
|
|
fsm.state.KVSSet(11, &structs.DirEntry{
|
|
|
|
fsm.state.KVSSet(11, &structs.DirEntry{
|
|
|
|
Key: "/remove",
|
|
|
|
Key: "/remove",
|
|
|
@ -146,12 +141,8 @@ func TestFSM_SnapshotRestore_OSS(t *testing.T) {
|
|
|
|
})
|
|
|
|
})
|
|
|
|
fsm.state.KVSDelete(12, "/remove", nil)
|
|
|
|
fsm.state.KVSDelete(12, "/remove", nil)
|
|
|
|
idx, _, err := fsm.state.KVSList(nil, "/remove", nil)
|
|
|
|
idx, _, err := fsm.state.KVSList(nil, "/remove", nil)
|
|
|
|
if err != nil {
|
|
|
|
require.NoError(t, err)
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
require.EqualValues(t, 12, idx, "bad index")
|
|
|
|
}
|
|
|
|
|
|
|
|
if idx != 12 {
|
|
|
|
|
|
|
|
t.Fatalf("bad index: %d", idx)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
updates := structs.Coordinates{
|
|
|
|
updates := structs.Coordinates{
|
|
|
|
&structs.Coordinate{
|
|
|
|
&structs.Coordinate{
|
|
|
@ -163,9 +154,7 @@ func TestFSM_SnapshotRestore_OSS(t *testing.T) {
|
|
|
|
Coord: generateRandomCoordinate(),
|
|
|
|
Coord: generateRandomCoordinate(),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if err := fsm.state.CoordinateBatchUpdate(13, updates); err != nil {
|
|
|
|
require.NoError(t, fsm.state.CoordinateBatchUpdate(13, updates))
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
query := structs.PreparedQuery{
|
|
|
|
query := structs.PreparedQuery{
|
|
|
|
ID: generateUUID(),
|
|
|
|
ID: generateUUID(),
|
|
|
@ -177,18 +166,14 @@ func TestFSM_SnapshotRestore_OSS(t *testing.T) {
|
|
|
|
ModifyIndex: 14,
|
|
|
|
ModifyIndex: 14,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if err := fsm.state.PreparedQuerySet(14, &query); err != nil {
|
|
|
|
require.NoError(t, fsm.state.PreparedQuerySet(14, &query))
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
autopilotConf := &autopilot.Config{
|
|
|
|
autopilotConf := &autopilot.Config{
|
|
|
|
CleanupDeadServers: true,
|
|
|
|
CleanupDeadServers: true,
|
|
|
|
LastContactThreshold: 100 * time.Millisecond,
|
|
|
|
LastContactThreshold: 100 * time.Millisecond,
|
|
|
|
MaxTrailingLogs: 222,
|
|
|
|
MaxTrailingLogs: 222,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if err := fsm.state.AutopilotSetConfig(15, autopilotConf); err != nil {
|
|
|
|
require.NoError(t, fsm.state.AutopilotSetConfig(15, autopilotConf))
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Intentions
|
|
|
|
// Intentions
|
|
|
|
ixn := structs.TestIntention(t)
|
|
|
|
ixn := structs.TestIntention(t)
|
|
|
@ -197,7 +182,7 @@ func TestFSM_SnapshotRestore_OSS(t *testing.T) {
|
|
|
|
CreateIndex: 14,
|
|
|
|
CreateIndex: 14,
|
|
|
|
ModifyIndex: 14,
|
|
|
|
ModifyIndex: 14,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
require.NoError(fsm.state.IntentionSet(14, ixn))
|
|
|
|
require.NoError(t, fsm.state.IntentionSet(14, ixn))
|
|
|
|
|
|
|
|
|
|
|
|
// CA Roots
|
|
|
|
// CA Roots
|
|
|
|
roots := []*structs.CARoot{
|
|
|
|
roots := []*structs.CARoot{
|
|
|
@ -208,16 +193,16 @@ func TestFSM_SnapshotRestore_OSS(t *testing.T) {
|
|
|
|
r.Active = false
|
|
|
|
r.Active = false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ok, err := fsm.state.CARootSetCAS(15, 0, roots)
|
|
|
|
ok, err := fsm.state.CARootSetCAS(15, 0, roots)
|
|
|
|
require.NoError(err)
|
|
|
|
require.NoError(t, err)
|
|
|
|
assert.True(ok)
|
|
|
|
require.True(t, ok)
|
|
|
|
|
|
|
|
|
|
|
|
ok, err = fsm.state.CASetProviderState(16, &structs.CAConsulProviderState{
|
|
|
|
ok, err = fsm.state.CASetProviderState(16, &structs.CAConsulProviderState{
|
|
|
|
ID: "asdf",
|
|
|
|
ID: "asdf",
|
|
|
|
PrivateKey: "foo",
|
|
|
|
PrivateKey: "foo",
|
|
|
|
RootCert: "bar",
|
|
|
|
RootCert: "bar",
|
|
|
|
})
|
|
|
|
})
|
|
|
|
require.NoError(err)
|
|
|
|
require.NoError(t, err)
|
|
|
|
assert.True(ok)
|
|
|
|
require.True(t, ok)
|
|
|
|
|
|
|
|
|
|
|
|
// CA Config
|
|
|
|
// CA Config
|
|
|
|
caConfig := &structs.CAConfiguration{
|
|
|
|
caConfig := &structs.CAConfiguration{
|
|
|
@ -229,7 +214,7 @@ func TestFSM_SnapshotRestore_OSS(t *testing.T) {
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
err = fsm.state.CASetConfig(17, caConfig)
|
|
|
|
err = fsm.state.CASetConfig(17, caConfig)
|
|
|
|
require.NoError(err)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
|
|
|
|
// Config entries
|
|
|
|
// Config entries
|
|
|
|
serviceConfig := &structs.ServiceConfigEntry{
|
|
|
|
serviceConfig := &structs.ServiceConfigEntry{
|
|
|
@ -241,8 +226,8 @@ func TestFSM_SnapshotRestore_OSS(t *testing.T) {
|
|
|
|
Kind: structs.ProxyDefaults,
|
|
|
|
Kind: structs.ProxyDefaults,
|
|
|
|
Name: "global",
|
|
|
|
Name: "global",
|
|
|
|
}
|
|
|
|
}
|
|
|
|
require.NoError(fsm.state.EnsureConfigEntry(18, serviceConfig, structs.DefaultEnterpriseMeta()))
|
|
|
|
require.NoError(t, fsm.state.EnsureConfigEntry(18, serviceConfig, structs.DefaultEnterpriseMeta()))
|
|
|
|
require.NoError(fsm.state.EnsureConfigEntry(19, proxyConfig, structs.DefaultEnterpriseMeta()))
|
|
|
|
require.NoError(t, fsm.state.EnsureConfigEntry(19, proxyConfig, structs.DefaultEnterpriseMeta()))
|
|
|
|
|
|
|
|
|
|
|
|
ingress := &structs.IngressGatewayConfigEntry{
|
|
|
|
ingress := &structs.IngressGatewayConfigEntry{
|
|
|
|
Kind: structs.IngressGateway,
|
|
|
|
Kind: structs.IngressGateway,
|
|
|
@ -259,9 +244,9 @@ func TestFSM_SnapshotRestore_OSS(t *testing.T) {
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
require.NoError(fsm.state.EnsureConfigEntry(20, ingress, structs.DefaultEnterpriseMeta()))
|
|
|
|
require.NoError(t, fsm.state.EnsureConfigEntry(20, ingress, structs.DefaultEnterpriseMeta()))
|
|
|
|
_, gatewayServices, err := fsm.state.GatewayServices(nil, "ingress", structs.DefaultEnterpriseMeta())
|
|
|
|
_, gatewayServices, err := fsm.state.GatewayServices(nil, "ingress", structs.DefaultEnterpriseMeta())
|
|
|
|
require.NoError(err)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
|
|
|
|
// Raft Chunking
|
|
|
|
// Raft Chunking
|
|
|
|
chunkState := &raftchunking.State{
|
|
|
|
chunkState := &raftchunking.State{
|
|
|
@ -292,7 +277,7 @@ func TestFSM_SnapshotRestore_OSS(t *testing.T) {
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
err = fsm.chunker.RestoreState(chunkState)
|
|
|
|
err = fsm.chunker.RestoreState(chunkState)
|
|
|
|
require.NoError(err)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
|
|
|
|
// Federation states
|
|
|
|
// Federation states
|
|
|
|
fedState1 := &structs.FederationState{
|
|
|
|
fedState1 := &structs.FederationState{
|
|
|
@ -395,267 +380,269 @@ func TestFSM_SnapshotRestore_OSS(t *testing.T) {
|
|
|
|
},
|
|
|
|
},
|
|
|
|
UpdatedAt: time.Now().UTC(),
|
|
|
|
UpdatedAt: time.Now().UTC(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
require.NoError(fsm.state.FederationStateSet(21, fedState1))
|
|
|
|
require.NoError(t, fsm.state.FederationStateSet(21, fedState1))
|
|
|
|
require.NoError(fsm.state.FederationStateSet(22, fedState2))
|
|
|
|
require.NoError(t, fsm.state.FederationStateSet(22, fedState2))
|
|
|
|
|
|
|
|
|
|
|
|
// Snapshot
|
|
|
|
// Snapshot
|
|
|
|
snap, err := fsm.Snapshot()
|
|
|
|
snap, err := fsm.Snapshot()
|
|
|
|
if err != nil {
|
|
|
|
require.NoError(t, err)
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
defer snap.Release()
|
|
|
|
defer snap.Release()
|
|
|
|
|
|
|
|
|
|
|
|
// Persist
|
|
|
|
// Persist
|
|
|
|
buf := bytes.NewBuffer(nil)
|
|
|
|
buf := bytes.NewBuffer(nil)
|
|
|
|
sink := &MockSink{buf, false}
|
|
|
|
sink := &MockSink{buf, false}
|
|
|
|
if err := snap.Persist(sink); err != nil {
|
|
|
|
require.NoError(t, snap.Persist(sink))
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
|
|
|
|
|
|
|
|
// create an encoder to handle some custom persisted data
|
|
|
|
|
|
|
|
// this is mainly to inject data that would no longer ever
|
|
|
|
|
|
|
|
// be persisted but that we still need to be able to restore
|
|
|
|
|
|
|
|
encoder := codec.NewEncoder(sink, structs.MsgpackHandle)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Persist a legacy ACL token - this is not done in newer code
|
|
|
|
|
|
|
|
// but we want to ensure that restoring legacy tokens works as
|
|
|
|
|
|
|
|
// expected so we must inject one here manually
|
|
|
|
|
|
|
|
_, err = sink.Write([]byte{byte(structs.ACLRequestType)})
|
|
|
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
acl := structs.ACL{
|
|
|
|
|
|
|
|
ID: "1057354f-69ef-4487-94ab-aead3c755445",
|
|
|
|
|
|
|
|
Name: "test-legacy",
|
|
|
|
|
|
|
|
Type: "client",
|
|
|
|
|
|
|
|
Rules: `operator = "read"`,
|
|
|
|
|
|
|
|
RaftIndex: structs.RaftIndex{CreateIndex: 1, ModifyIndex: 2},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
require.NoError(t, encoder.Encode(&acl))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Persist a ACLToken without a Hash - the state store will
|
|
|
|
|
|
|
|
// now tack these on but we want to ensure we can restore
|
|
|
|
|
|
|
|
// tokens without a hash and have the hash be set.
|
|
|
|
|
|
|
|
token2 := &structs.ACLToken{
|
|
|
|
|
|
|
|
AccessorID: "4464e4c2-1c55-4c37-978a-66cb3abe6587",
|
|
|
|
|
|
|
|
SecretID: "fc8708dc-c5ae-4bb2-a9af-a1ca456548fb",
|
|
|
|
|
|
|
|
Description: "Test No Hash",
|
|
|
|
|
|
|
|
CreateTime: time.Now(),
|
|
|
|
|
|
|
|
Local: false,
|
|
|
|
|
|
|
|
Rules: `operator = "read"`,
|
|
|
|
|
|
|
|
RaftIndex: structs.RaftIndex{CreateIndex: 1, ModifyIndex: 2},
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
_, err = sink.Write([]byte{byte(structs.ACLTokenSetRequestType)})
|
|
|
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
require.NoError(t, encoder.Encode(&token2))
|
|
|
|
|
|
|
|
|
|
|
|
// Try to restore on a new FSM
|
|
|
|
// Try to restore on a new FSM
|
|
|
|
fsm2, err := New(nil, logger)
|
|
|
|
fsm2, err := New(nil, logger)
|
|
|
|
if err != nil {
|
|
|
|
require.NoError(t, err)
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Do a restore
|
|
|
|
// Do a restore
|
|
|
|
if err := fsm2.Restore(sink); err != nil {
|
|
|
|
require.NoError(t, fsm2.Restore(sink))
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Verify the contents
|
|
|
|
// Verify the contents
|
|
|
|
_, nodes, err := fsm2.state.Nodes(nil)
|
|
|
|
_, nodes, err := fsm2.state.Nodes(nil)
|
|
|
|
if err != nil {
|
|
|
|
require.NoError(t, err)
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
require.Len(t, nodes, 2, "incorect number of nodes: %v", nodes)
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(nodes) != 2 {
|
|
|
|
// validate the first node. Note that this test relies on stable
|
|
|
|
t.Fatalf("bad: %v", nodes)
|
|
|
|
// iteration through the memdb index and the fact that node2 has
|
|
|
|
}
|
|
|
|
// a name of "baz" so it should be indexed before node1 with a
|
|
|
|
if nodes[0].ID != node2.ID ||
|
|
|
|
// name of "foo". If memdb our our indexing changes this is likely
|
|
|
|
nodes[0].Node != "baz" ||
|
|
|
|
// to break.
|
|
|
|
nodes[0].Datacenter != "dc1" ||
|
|
|
|
require.Equal(t, node2.ID, nodes[0].ID)
|
|
|
|
nodes[0].Address != "127.0.0.2" ||
|
|
|
|
require.Equal(t, "baz", nodes[0].Node)
|
|
|
|
len(nodes[0].Meta) != 1 ||
|
|
|
|
require.Equal(t, "dc1", nodes[0].Datacenter)
|
|
|
|
nodes[0].Meta["testMeta"] != "testing123" ||
|
|
|
|
require.Equal(t, "127.0.0.2", nodes[0].Address)
|
|
|
|
len(nodes[0].TaggedAddresses) != 1 ||
|
|
|
|
require.Len(t, nodes[0].Meta, 1)
|
|
|
|
nodes[0].TaggedAddresses["hello"] != "1.2.3.4" {
|
|
|
|
require.Equal(t, "testing123", nodes[0].Meta["testMeta"])
|
|
|
|
t.Fatalf("bad: %v", nodes[0])
|
|
|
|
require.Len(t, nodes[0].TaggedAddresses, 1)
|
|
|
|
}
|
|
|
|
require.Equal(t, "1.2.3.4", nodes[0].TaggedAddresses["hello"])
|
|
|
|
if nodes[1].ID != node1.ID ||
|
|
|
|
|
|
|
|
nodes[1].Node != "foo" ||
|
|
|
|
require.Equal(t, node1.ID, nodes[1].ID)
|
|
|
|
nodes[1].Datacenter != "dc1" ||
|
|
|
|
require.Equal(t, "foo", nodes[1].Node)
|
|
|
|
nodes[1].Address != "127.0.0.1" ||
|
|
|
|
require.Equal(t, "dc1", nodes[1].Datacenter)
|
|
|
|
len(nodes[1].TaggedAddresses) != 0 {
|
|
|
|
require.Equal(t, "127.0.0.1", nodes[1].Address)
|
|
|
|
t.Fatalf("bad: %v", nodes[1])
|
|
|
|
require.Empty(t, nodes[1].TaggedAddresses)
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
_, fooSrv, err := fsm2.state.NodeServices(nil, "foo", nil)
|
|
|
|
_, fooSrv, err := fsm2.state.NodeServices(nil, "foo", nil)
|
|
|
|
if err != nil {
|
|
|
|
require.NoError(t, err)
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
require.Len(t, fooSrv.Services, 2)
|
|
|
|
}
|
|
|
|
require.Contains(t, fooSrv.Services["db"].Tags, "primary")
|
|
|
|
if len(fooSrv.Services) != 2 {
|
|
|
|
require.True(t, stringslice.Contains(fooSrv.Services["db"].Tags, "primary"))
|
|
|
|
t.Fatalf("Bad: %v", fooSrv)
|
|
|
|
require.Equal(t, 5000, fooSrv.Services["db"].Port)
|
|
|
|
}
|
|
|
|
|
|
|
|
if !stringslice.Contains(fooSrv.Services["db"].Tags, "primary") {
|
|
|
|
|
|
|
|
t.Fatalf("Bad: %v", fooSrv)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if fooSrv.Services["db"].Port != 5000 {
|
|
|
|
|
|
|
|
t.Fatalf("Bad: %v", fooSrv)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
connectSrv := fooSrv.Services["web"]
|
|
|
|
connectSrv := fooSrv.Services["web"]
|
|
|
|
if !reflect.DeepEqual(connectSrv.Connect, connectConf) {
|
|
|
|
require.Equal(t, connectConf, connectSrv.Connect)
|
|
|
|
t.Fatalf("got: %v, want: %v", connectSrv.Connect, connectConf)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
_, checks, err := fsm2.state.NodeChecks(nil, "foo", nil)
|
|
|
|
_, checks, err := fsm2.state.NodeChecks(nil, "foo", nil)
|
|
|
|
if err != nil {
|
|
|
|
require.NoError(t, err)
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
require.Len(t, checks, 1)
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(checks) != 1 {
|
|
|
|
|
|
|
|
t.Fatalf("Bad: %v", checks)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Verify key is set
|
|
|
|
// Verify key is set
|
|
|
|
_, d, err := fsm2.state.KVSGet(nil, "/test", nil)
|
|
|
|
_, d, err := fsm2.state.KVSGet(nil, "/test", nil)
|
|
|
|
if err != nil {
|
|
|
|
require.NoError(t, err)
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
require.EqualValues(t, "foo", d.Value)
|
|
|
|
}
|
|
|
|
|
|
|
|
if string(d.Value) != "foo" {
|
|
|
|
|
|
|
|
t.Fatalf("bad: %v", d)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Verify session is restored
|
|
|
|
// Verify session is restored
|
|
|
|
idx, s, err := fsm2.state.SessionGet(nil, session.ID, nil)
|
|
|
|
idx, s, err := fsm2.state.SessionGet(nil, session.ID, nil)
|
|
|
|
if err != nil {
|
|
|
|
require.NoError(t, err)
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
require.Equal(t, "foo", s.Node)
|
|
|
|
}
|
|
|
|
require.EqualValues(t, 9, idx)
|
|
|
|
if s.Node != "foo" {
|
|
|
|
|
|
|
|
t.Fatalf("bad: %v", s)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if idx <= 1 {
|
|
|
|
|
|
|
|
t.Fatalf("bad index: %d", idx)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Verify ACL Binding Rule is restored
|
|
|
|
// Verify ACL Binding Rule is restored
|
|
|
|
_, bindingRule2, err := fsm2.state.ACLBindingRuleGetByID(nil, bindingRule.ID, nil)
|
|
|
|
_, bindingRule2, err := fsm2.state.ACLBindingRuleGetByID(nil, bindingRule.ID, nil)
|
|
|
|
require.NoError(err)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(bindingRule, bindingRule2)
|
|
|
|
require.Equal(t, bindingRule, bindingRule2)
|
|
|
|
|
|
|
|
|
|
|
|
// Verify ACL Auth Method is restored
|
|
|
|
// Verify ACL Auth Method is restored
|
|
|
|
_, method2, err := fsm2.state.ACLAuthMethodGetByName(nil, method.Name, nil)
|
|
|
|
_, method2, err := fsm2.state.ACLAuthMethodGetByName(nil, method.Name, nil)
|
|
|
|
require.NoError(err)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(method, method2)
|
|
|
|
require.Equal(t, method, method2)
|
|
|
|
|
|
|
|
|
|
|
|
// Verify ACL Token is restored
|
|
|
|
// Verify ACL Token is restored
|
|
|
|
_, token2, err := fsm2.state.ACLTokenGetByAccessor(nil, token.AccessorID, nil)
|
|
|
|
_, rtoken, err := fsm2.state.ACLTokenGetByAccessor(nil, token.AccessorID, nil)
|
|
|
|
require.NoError(err)
|
|
|
|
require.NoError(t, err)
|
|
|
|
{
|
|
|
|
require.NotNil(t, rtoken)
|
|
|
|
// time.Time is tricky to compare generically when it takes a ser/deserialization round trip.
|
|
|
|
// the state store function will add on the Hash if its empty
|
|
|
|
require.True(token.CreateTime.Equal(token2.CreateTime))
|
|
|
|
require.NotEmpty(t, rtoken.Hash)
|
|
|
|
token2.CreateTime = token.CreateTime
|
|
|
|
token.CreateTime = token.CreateTime.Round(0)
|
|
|
|
}
|
|
|
|
rtoken.CreateTime = rtoken.CreateTime.Round(0)
|
|
|
|
require.Equal(token, token2)
|
|
|
|
|
|
|
|
|
|
|
|
// note that this can work because the state store will add the Hash to the token before
|
|
|
|
|
|
|
|
// storing. That token just happens to be a pointer to the one in this function so it
|
|
|
|
|
|
|
|
// adds the Hash to our local var.
|
|
|
|
|
|
|
|
require.Equal(t, token, rtoken)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Verify legacy ACL is restored
|
|
|
|
|
|
|
|
_, rtoken, err = fsm2.state.ACLTokenGetBySecret(nil, acl.ID, nil)
|
|
|
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
require.NotNil(t, rtoken)
|
|
|
|
|
|
|
|
require.NotEmpty(t, rtoken.Hash)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
restoredACL, err := rtoken.Convert()
|
|
|
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
require.Equal(t, &acl, restoredACL)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Verify ACLToken without hash computes the Hash during restoration
|
|
|
|
|
|
|
|
_, rtoken, err = fsm2.state.ACLTokenGetByAccessor(nil, token2.AccessorID, nil)
|
|
|
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
require.NotNil(t, rtoken)
|
|
|
|
|
|
|
|
require.NotEmpty(t, rtoken.Hash)
|
|
|
|
|
|
|
|
// nil the Hash so we can compare them
|
|
|
|
|
|
|
|
rtoken.Hash = nil
|
|
|
|
|
|
|
|
token2.CreateTime = token2.CreateTime.Round(0)
|
|
|
|
|
|
|
|
rtoken.CreateTime = rtoken.CreateTime.Round(0)
|
|
|
|
|
|
|
|
require.Equal(t, token2, rtoken)
|
|
|
|
|
|
|
|
|
|
|
|
// Verify the acl-token-bootstrap index was restored
|
|
|
|
// Verify the acl-token-bootstrap index was restored
|
|
|
|
canBootstrap, index, err := fsm2.state.CanBootstrapACLToken()
|
|
|
|
canBootstrap, index, err := fsm2.state.CanBootstrapACLToken()
|
|
|
|
require.False(canBootstrap)
|
|
|
|
require.False(t, canBootstrap)
|
|
|
|
require.True(index > 0)
|
|
|
|
require.True(t, index > 0)
|
|
|
|
|
|
|
|
|
|
|
|
// Verify ACL Role is restored
|
|
|
|
// Verify ACL Role is restored
|
|
|
|
_, role2, err := fsm2.state.ACLRoleGetByID(nil, role.ID, nil)
|
|
|
|
_, role2, err := fsm2.state.ACLRoleGetByID(nil, role.ID, nil)
|
|
|
|
require.NoError(err)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(role, role2)
|
|
|
|
require.Equal(t, role, role2)
|
|
|
|
|
|
|
|
|
|
|
|
// Verify ACL Policy is restored
|
|
|
|
// Verify ACL Policy is restored
|
|
|
|
_, policy2, err := fsm2.state.ACLPolicyGetByID(nil, structs.ACLPolicyGlobalManagementID, nil)
|
|
|
|
_, policy2, err := fsm2.state.ACLPolicyGetByID(nil, structs.ACLPolicyGlobalManagementID, nil)
|
|
|
|
require.NoError(err)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(policy, policy2)
|
|
|
|
require.Equal(t, policy, policy2)
|
|
|
|
|
|
|
|
|
|
|
|
// Verify tombstones are restored
|
|
|
|
// Verify tombstones are restored
|
|
|
|
func() {
|
|
|
|
func() {
|
|
|
|
snap := fsm2.state.Snapshot()
|
|
|
|
snap := fsm2.state.Snapshot()
|
|
|
|
defer snap.Close()
|
|
|
|
defer snap.Close()
|
|
|
|
stones, err := snap.Tombstones()
|
|
|
|
stones, err := snap.Tombstones()
|
|
|
|
if err != nil {
|
|
|
|
require.NoError(t, err)
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
stone := stones.Next().(*state.Tombstone)
|
|
|
|
stone := stones.Next().(*state.Tombstone)
|
|
|
|
if stone == nil {
|
|
|
|
require.NotNil(t, stone)
|
|
|
|
t.Fatalf("missing tombstone")
|
|
|
|
require.Equal(t, "/remove", stone.Key)
|
|
|
|
}
|
|
|
|
require.Nil(t, stones.Next())
|
|
|
|
if stone.Key != "/remove" || stone.Index != 12 {
|
|
|
|
|
|
|
|
t.Fatalf("bad: %v", stone)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if stones.Next() != nil {
|
|
|
|
|
|
|
|
t.Fatalf("unexpected extra tombstones")
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}()
|
|
|
|
}()
|
|
|
|
|
|
|
|
|
|
|
|
// Verify coordinates are restored
|
|
|
|
// Verify coordinates are restored
|
|
|
|
_, coords, err := fsm2.state.Coordinates(nil)
|
|
|
|
_, coords, err := fsm2.state.Coordinates(nil)
|
|
|
|
if err != nil {
|
|
|
|
require.NoError(t, err)
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
require.Equal(t, updates, coords)
|
|
|
|
}
|
|
|
|
|
|
|
|
if !reflect.DeepEqual(coords, updates) {
|
|
|
|
|
|
|
|
t.Fatalf("bad: %#v", coords)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Verify queries are restored.
|
|
|
|
// Verify queries are restored.
|
|
|
|
_, queries, err := fsm2.state.PreparedQueryList(nil)
|
|
|
|
_, queries, err := fsm2.state.PreparedQueryList(nil)
|
|
|
|
if err != nil {
|
|
|
|
require.NoError(t, err)
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
require.Len(t, queries, 1)
|
|
|
|
}
|
|
|
|
require.Equal(t, &query, queries[0])
|
|
|
|
if len(queries) != 1 {
|
|
|
|
|
|
|
|
t.Fatalf("bad: %#v", queries)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if !reflect.DeepEqual(queries[0], &query) {
|
|
|
|
|
|
|
|
t.Fatalf("bad: %#v", queries[0])
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Verify autopilot config is restored.
|
|
|
|
// Verify autopilot config is restored.
|
|
|
|
_, restoredConf, err := fsm2.state.AutopilotConfig()
|
|
|
|
_, restoredConf, err := fsm2.state.AutopilotConfig()
|
|
|
|
if err != nil {
|
|
|
|
require.NoError(t, err)
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
require.Equal(t, autopilotConf, restoredConf)
|
|
|
|
}
|
|
|
|
|
|
|
|
if !reflect.DeepEqual(restoredConf, autopilotConf) {
|
|
|
|
|
|
|
|
t.Fatalf("bad: %#v, %#v", restoredConf, autopilotConf)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Verify intentions are restored.
|
|
|
|
// Verify intentions are restored.
|
|
|
|
_, ixns, err := fsm2.state.Intentions(nil)
|
|
|
|
_, ixns, err := fsm2.state.Intentions(nil)
|
|
|
|
require.NoError(err)
|
|
|
|
require.NoError(t, err)
|
|
|
|
assert.Len(ixns, 1)
|
|
|
|
require.Len(t, ixns, 1)
|
|
|
|
assert.Equal(ixn, ixns[0])
|
|
|
|
require.Equal(t, ixn, ixns[0])
|
|
|
|
|
|
|
|
|
|
|
|
// Verify CA roots are restored.
|
|
|
|
// Verify CA roots are restored.
|
|
|
|
_, roots, err = fsm2.state.CARoots(nil)
|
|
|
|
_, roots, err = fsm2.state.CARoots(nil)
|
|
|
|
require.NoError(err)
|
|
|
|
require.NoError(t, err)
|
|
|
|
assert.Len(roots, 2)
|
|
|
|
require.Len(t, roots, 2)
|
|
|
|
|
|
|
|
|
|
|
|
// Verify provider state is restored.
|
|
|
|
// Verify provider state is restored.
|
|
|
|
_, state, err := fsm2.state.CAProviderState("asdf")
|
|
|
|
_, state, err := fsm2.state.CAProviderState("asdf")
|
|
|
|
require.NoError(err)
|
|
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal("foo", state.PrivateKey)
|
|
|
|
require.Equal(t, "foo", state.PrivateKey)
|
|
|
|
assert.Equal("bar", state.RootCert)
|
|
|
|
require.Equal(t, "bar", state.RootCert)
|
|
|
|
|
|
|
|
|
|
|
|
// Verify CA configuration is restored.
|
|
|
|
// Verify CA configuration is restored.
|
|
|
|
_, caConf, err := fsm2.state.CAConfig(nil)
|
|
|
|
_, caConf, err := fsm2.state.CAConfig(nil)
|
|
|
|
require.NoError(err)
|
|
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(caConfig, caConf)
|
|
|
|
require.Equal(t, caConfig, caConf)
|
|
|
|
|
|
|
|
|
|
|
|
// Verify config entries are restored
|
|
|
|
// Verify config entries are restored
|
|
|
|
_, serviceConfEntry, err := fsm2.state.ConfigEntry(nil, structs.ServiceDefaults, "foo", structs.DefaultEnterpriseMeta())
|
|
|
|
_, serviceConfEntry, err := fsm2.state.ConfigEntry(nil, structs.ServiceDefaults, "foo", structs.DefaultEnterpriseMeta())
|
|
|
|
require.NoError(err)
|
|
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(serviceConfig, serviceConfEntry)
|
|
|
|
require.Equal(t, serviceConfig, serviceConfEntry)
|
|
|
|
|
|
|
|
|
|
|
|
_, proxyConfEntry, err := fsm2.state.ConfigEntry(nil, structs.ProxyDefaults, "global", structs.DefaultEnterpriseMeta())
|
|
|
|
_, proxyConfEntry, err := fsm2.state.ConfigEntry(nil, structs.ProxyDefaults, "global", structs.DefaultEnterpriseMeta())
|
|
|
|
require.NoError(err)
|
|
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(proxyConfig, proxyConfEntry)
|
|
|
|
require.Equal(t, proxyConfig, proxyConfEntry)
|
|
|
|
|
|
|
|
|
|
|
|
_, ingressRestored, err := fsm2.state.ConfigEntry(nil, structs.IngressGateway, "ingress", structs.DefaultEnterpriseMeta())
|
|
|
|
_, ingressRestored, err := fsm2.state.ConfigEntry(nil, structs.IngressGateway, "ingress", structs.DefaultEnterpriseMeta())
|
|
|
|
require.NoError(err)
|
|
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(ingress, ingressRestored)
|
|
|
|
require.Equal(t, ingress, ingressRestored)
|
|
|
|
|
|
|
|
|
|
|
|
_, restoredGatewayServices, err := fsm2.state.GatewayServices(nil, "ingress", structs.DefaultEnterpriseMeta())
|
|
|
|
_, restoredGatewayServices, err := fsm2.state.GatewayServices(nil, "ingress", structs.DefaultEnterpriseMeta())
|
|
|
|
require.NoError(err)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(gatewayServices, restoredGatewayServices)
|
|
|
|
require.Equal(t, gatewayServices, restoredGatewayServices)
|
|
|
|
|
|
|
|
|
|
|
|
newChunkState, err := fsm2.chunker.CurrentState()
|
|
|
|
newChunkState, err := fsm2.chunker.CurrentState()
|
|
|
|
require.NoError(err)
|
|
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(newChunkState, chunkState)
|
|
|
|
require.Equal(t, newChunkState, chunkState)
|
|
|
|
|
|
|
|
|
|
|
|
// Verify federation states are restored.
|
|
|
|
// Verify federation states are restored.
|
|
|
|
_, fedStateLoaded1, err := fsm2.state.FederationStateGet(nil, "dc1")
|
|
|
|
_, fedStateLoaded1, err := fsm2.state.FederationStateGet(nil, "dc1")
|
|
|
|
require.NoError(err)
|
|
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(fedState1, fedStateLoaded1)
|
|
|
|
require.Equal(t, fedState1, fedStateLoaded1)
|
|
|
|
_, fedStateLoaded2, err := fsm2.state.FederationStateGet(nil, "dc2")
|
|
|
|
_, fedStateLoaded2, err := fsm2.state.FederationStateGet(nil, "dc2")
|
|
|
|
require.NoError(err)
|
|
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(fedState2, fedStateLoaded2)
|
|
|
|
require.Equal(t, fedState2, fedStateLoaded2)
|
|
|
|
|
|
|
|
|
|
|
|
// Snapshot
|
|
|
|
// Snapshot
|
|
|
|
snap, err = fsm2.Snapshot()
|
|
|
|
snap, err = fsm2.Snapshot()
|
|
|
|
if err != nil {
|
|
|
|
require.NoError(t, err)
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
defer snap.Release()
|
|
|
|
defer snap.Release()
|
|
|
|
|
|
|
|
|
|
|
|
// Persist
|
|
|
|
// Persist
|
|
|
|
buf = bytes.NewBuffer(nil)
|
|
|
|
buf = bytes.NewBuffer(nil)
|
|
|
|
sink = &MockSink{buf, false}
|
|
|
|
sink = &MockSink{buf, false}
|
|
|
|
if err := snap.Persist(sink); err != nil {
|
|
|
|
require.NoError(t, snap.Persist(sink))
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Try to restore on the old FSM and make sure it abandons the old state
|
|
|
|
// Try to restore on the old FSM and make sure it abandons the old state
|
|
|
|
// store.
|
|
|
|
// store.
|
|
|
|
abandonCh := fsm.state.AbandonCh()
|
|
|
|
abandonCh := fsm.state.AbandonCh()
|
|
|
|
if err := fsm.Restore(sink); err != nil {
|
|
|
|
require.NoError(t, fsm.Restore(sink))
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
select {
|
|
|
|
select {
|
|
|
|
case <-abandonCh:
|
|
|
|
case <-abandonCh:
|
|
|
|
default:
|
|
|
|
default:
|
|
|
|
t.Fatalf("bad")
|
|
|
|
require.Fail(t, "Old state not abandoned")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -664,37 +651,27 @@ func TestFSM_BadRestore_OSS(t *testing.T) {
|
|
|
|
// Create an FSM with some state.
|
|
|
|
// Create an FSM with some state.
|
|
|
|
logger := testutil.Logger(t)
|
|
|
|
logger := testutil.Logger(t)
|
|
|
|
fsm, err := New(nil, logger)
|
|
|
|
fsm, err := New(nil, logger)
|
|
|
|
if err != nil {
|
|
|
|
require.NoError(t, err)
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
fsm.state.EnsureNode(1, &structs.Node{Node: "foo", Address: "127.0.0.1"})
|
|
|
|
fsm.state.EnsureNode(1, &structs.Node{Node: "foo", Address: "127.0.0.1"})
|
|
|
|
abandonCh := fsm.state.AbandonCh()
|
|
|
|
abandonCh := fsm.state.AbandonCh()
|
|
|
|
|
|
|
|
|
|
|
|
// Do a bad restore.
|
|
|
|
// Do a bad restore.
|
|
|
|
buf := bytes.NewBuffer([]byte("bad snapshot"))
|
|
|
|
buf := bytes.NewBuffer([]byte("bad snapshot"))
|
|
|
|
sink := &MockSink{buf, false}
|
|
|
|
sink := &MockSink{buf, false}
|
|
|
|
if err := fsm.Restore(sink); err == nil {
|
|
|
|
require.Error(t, fsm.Restore(sink))
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Verify the contents didn't get corrupted.
|
|
|
|
// Verify the contents didn't get corrupted.
|
|
|
|
_, nodes, err := fsm.state.Nodes(nil)
|
|
|
|
_, nodes, err := fsm.state.Nodes(nil)
|
|
|
|
if err != nil {
|
|
|
|
require.NoError(t, err)
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
require.Len(t, nodes, 1)
|
|
|
|
}
|
|
|
|
require.Equal(t, "foo", nodes[0].Node)
|
|
|
|
if len(nodes) != 1 {
|
|
|
|
require.Equal(t, "127.0.0.1", nodes[0].Address)
|
|
|
|
t.Fatalf("bad: %v", nodes)
|
|
|
|
require.Empty(t, nodes[0].TaggedAddresses)
|
|
|
|
}
|
|
|
|
|
|
|
|
if nodes[0].Node != "foo" ||
|
|
|
|
|
|
|
|
nodes[0].Address != "127.0.0.1" ||
|
|
|
|
|
|
|
|
len(nodes[0].TaggedAddresses) != 0 {
|
|
|
|
|
|
|
|
t.Fatalf("bad: %v", nodes[0])
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Verify the old state store didn't get abandoned.
|
|
|
|
// Verify the old state store didn't get abandoned.
|
|
|
|
select {
|
|
|
|
select {
|
|
|
|
case <-abandonCh:
|
|
|
|
case <-abandonCh:
|
|
|
|
t.Fatalf("bad")
|
|
|
|
require.FailNow(t, "FSM state was abandoned when it should not have been")
|
|
|
|
default:
|
|
|
|
default:
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -702,46 +679,32 @@ func TestFSM_BadRestore_OSS(t *testing.T) {
|
|
|
|
func TestFSM_BadSnapshot_NilCAConfig(t *testing.T) {
|
|
|
|
func TestFSM_BadSnapshot_NilCAConfig(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
|
|
|
|
require := require.New(t)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Create an FSM with no config entry.
|
|
|
|
// Create an FSM with no config entry.
|
|
|
|
logger := testutil.Logger(t)
|
|
|
|
logger := testutil.Logger(t)
|
|
|
|
fsm, err := New(nil, logger)
|
|
|
|
fsm, err := New(nil, logger)
|
|
|
|
if err != nil {
|
|
|
|
require.NoError(t, err)
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Snapshot
|
|
|
|
// Snapshot
|
|
|
|
snap, err := fsm.Snapshot()
|
|
|
|
snap, err := fsm.Snapshot()
|
|
|
|
if err != nil {
|
|
|
|
require.NoError(t, err)
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
defer snap.Release()
|
|
|
|
defer snap.Release()
|
|
|
|
|
|
|
|
|
|
|
|
// Persist
|
|
|
|
// Persist
|
|
|
|
buf := bytes.NewBuffer(nil)
|
|
|
|
buf := bytes.NewBuffer(nil)
|
|
|
|
sink := &MockSink{buf, false}
|
|
|
|
sink := &MockSink{buf, false}
|
|
|
|
if err := snap.Persist(sink); err != nil {
|
|
|
|
require.NoError(t, snap.Persist(sink))
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Try to restore on a new FSM
|
|
|
|
// Try to restore on a new FSM
|
|
|
|
fsm2, err := New(nil, logger)
|
|
|
|
fsm2, err := New(nil, logger)
|
|
|
|
if err != nil {
|
|
|
|
require.NoError(t, err)
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Do a restore
|
|
|
|
// Do a restore
|
|
|
|
if err := fsm2.Restore(sink); err != nil {
|
|
|
|
require.NoError(t, fsm2.Restore(sink))
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Make sure there's no entry in the CA config table.
|
|
|
|
// Make sure there's no entry in the CA config table.
|
|
|
|
state := fsm2.State()
|
|
|
|
state := fsm2.State()
|
|
|
|
idx, config, err := state.CAConfig(nil)
|
|
|
|
idx, config, err := state.CAConfig(nil)
|
|
|
|
require.NoError(err)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(uint64(0), idx)
|
|
|
|
require.EqualValues(t, 0, idx)
|
|
|
|
if config != nil {
|
|
|
|
require.Nil(t, config)
|
|
|
|
t.Fatalf("config should be nil")
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|