Merge branch 'main' of ssh://github.com/hashicorp/consul

This commit is contained in:
Tu Nguyen 2022-08-11 12:02:50 -07:00
commit d68c8f9cab
4 changed files with 107 additions and 4 deletions

3
.changelog/14149.txt Normal file
View File

@ -0,0 +1,3 @@
```release-note:bug
agent: Fixed a compatibility issue when restoring snapshots from pre-1.13.0 versions of Consul [[GH-14107](https://github.com/hashicorp/consul/issues/14107)]
```

View File

@ -1,8 +1,12 @@
package fsm
import (
"fmt"
"net"
"github.com/hashicorp/consul-net-rpc/go-msgpack/codec"
"github.com/hashicorp/raft"
"github.com/mitchellh/mapstructure"
"github.com/hashicorp/consul/agent/consul/state"
"github.com/hashicorp/consul/agent/structs"
@ -886,11 +890,43 @@ func restoreSystemMetadata(header *SnapshotHeader, restore *state.Restore, decod
}
func restoreServiceVirtualIP(header *SnapshotHeader, restore *state.Restore, decoder *codec.Decoder) error {
var req state.ServiceVirtualIP
// state.ServiceVirtualIP was changed in a breaking way in 1.13.0 (2e4cb6f77d2be36b02e9be0b289b24e5b0afb794).
// We attempt to reconcile the older type by decoding to a map then decoding that map into
// structs.PeeredServiceName first, and then structs.ServiceName.
var req struct {
Service map[string]interface{}
IP net.IP
structs.RaftIndex
}
if err := decoder.Decode(&req); err != nil {
return err
}
if err := restore.ServiceVirtualIP(req); err != nil {
vip := state.ServiceVirtualIP{
IP: req.IP,
RaftIndex: req.RaftIndex,
}
// PeeredServiceName is the expected primary key type.
var psn structs.PeeredServiceName
if err := mapstructure.Decode(req.Service, &psn); err != nil {
return fmt.Errorf("cannot decode to structs.PeeredServiceName: %w", err)
}
vip.Service = psn
// If the expected primary key field is empty, it must be the older ServiceName type.
if vip.Service.ServiceName.Name == "" {
var sn structs.ServiceName
if err := mapstructure.Decode(req.Service, &sn); err != nil {
return fmt.Errorf("cannot decode to structs.ServiceName: %w", err)
}
vip.Service = structs.PeeredServiceName{
ServiceName: sn,
}
}
if err := restore.ServiceVirtualIP(vip); err != nil {
return err
}
return nil

View File

@ -3,6 +3,7 @@ package fsm
import (
"bytes"
"fmt"
"net"
"testing"
"time"
@ -962,3 +963,66 @@ func TestFSM_BadSnapshot_NilCAConfig(t *testing.T) {
require.EqualValues(t, 0, idx)
require.Nil(t, config)
}
// This test asserts that ServiceVirtualIP, which made a breaking change
// in 1.13.0, can still restore from older snapshots which use the old
// state.ServiceVirtualIP type.
func Test_restoreServiceVirtualIP(t *testing.T) {
psn := structs.PeeredServiceName{
ServiceName: structs.ServiceName{
Name: "foo",
},
}
run := func(t *testing.T, input interface{}) {
t.Helper()
var b []byte
buf := bytes.NewBuffer(b)
// Encode input
encoder := codec.NewEncoder(buf, structs.MsgpackHandle)
require.NoError(t, encoder.Encode(input))
// Create a decoder
dec := codec.NewDecoder(buf, structs.MsgpackHandle)
logger := testutil.Logger(t)
fsm, err := New(nil, logger)
require.NoError(t, err)
restore := fsm.State().Restore()
// Call restore
require.NoError(t, restoreServiceVirtualIP(nil, restore, dec))
require.NoError(t, restore.Commit())
ip, err := fsm.State().VirtualIPForService(psn)
require.NoError(t, err)
// 240->224 due to addIPOffset
require.Equal(t, "224.0.0.2", ip)
}
t.Run("new ServiceVirtualIP with PeeredServiceName", func(t *testing.T) {
run(t, state.ServiceVirtualIP{
Service: psn,
IP: net.ParseIP("240.0.0.2"),
RaftIndex: structs.RaftIndex{},
})
})
t.Run("pre-1.13.0 ServiceVirtualIP with ServiceName", func(t *testing.T) {
type compatServiceVirtualIP struct {
Service structs.ServiceName
IP net.IP
RaftIndex structs.RaftIndex
}
run(t, compatServiceVirtualIP{
Service: structs.ServiceName{
Name: "foo",
},
IP: net.ParseIP("240.0.0.2"),
RaftIndex: structs.RaftIndex{},
})
})
}

View File

@ -2212,7 +2212,7 @@ type PeeredServiceName struct {
type ServiceName struct {
Name string
acl.EnterpriseMeta
acl.EnterpriseMeta `mapstructure:",squash"`
}
func NewServiceName(name string, entMeta *acl.EnterpriseMeta) ServiceName {