mirror of https://github.com/status-im/consul.git
Merge branch 'main' of ssh://github.com/hashicorp/consul
This commit is contained in:
commit
d68c8f9cab
|
@ -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)]
|
||||||
|
```
|
|
@ -1,8 +1,12 @@
|
||||||
package fsm
|
package fsm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
|
||||||
"github.com/hashicorp/consul-net-rpc/go-msgpack/codec"
|
"github.com/hashicorp/consul-net-rpc/go-msgpack/codec"
|
||||||
"github.com/hashicorp/raft"
|
"github.com/hashicorp/raft"
|
||||||
|
"github.com/mitchellh/mapstructure"
|
||||||
|
|
||||||
"github.com/hashicorp/consul/agent/consul/state"
|
"github.com/hashicorp/consul/agent/consul/state"
|
||||||
"github.com/hashicorp/consul/agent/structs"
|
"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 {
|
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 {
|
if err := decoder.Decode(&req); err != nil {
|
||||||
return err
|
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 err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -3,6 +3,7 @@ package fsm
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -962,3 +963,66 @@ func TestFSM_BadSnapshot_NilCAConfig(t *testing.T) {
|
||||||
require.EqualValues(t, 0, idx)
|
require.EqualValues(t, 0, idx)
|
||||||
require.Nil(t, config)
|
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{},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
@ -2211,8 +2211,8 @@ type PeeredServiceName struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type ServiceName struct {
|
type ServiceName struct {
|
||||||
Name string
|
Name string
|
||||||
acl.EnterpriseMeta
|
acl.EnterpriseMeta `mapstructure:",squash"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewServiceName(name string, entMeta *acl.EnterpriseMeta) ServiceName {
|
func NewServiceName(name string, entMeta *acl.EnterpriseMeta) ServiceName {
|
||||||
|
|
Loading…
Reference in New Issue