mirror of
https://github.com/status-im/consul.git
synced 2025-02-18 00:27:04 +00:00
consul: Adding flag to support future incompatible commands. Future self will thank me.
This commit is contained in:
parent
27a820d611
commit
35744c7210
@ -75,7 +75,18 @@ func (c *consulFSM) State() *StateStore {
|
|||||||
|
|
||||||
func (c *consulFSM) Apply(log *raft.Log) interface{} {
|
func (c *consulFSM) Apply(log *raft.Log) interface{} {
|
||||||
buf := log.Data
|
buf := log.Data
|
||||||
switch structs.MessageType(buf[0]) {
|
msgType := structs.MessageType(buf[0])
|
||||||
|
|
||||||
|
// Check if this message type should be ignored when unknown. This is
|
||||||
|
// used so that new commands can be added with developer control if older
|
||||||
|
// versions can safely ignore the command, or if they should crash.
|
||||||
|
ignoreUnknown := false
|
||||||
|
if msgType&structs.IgnoreUnknownTypeFlag == structs.IgnoreUnknownTypeFlag {
|
||||||
|
msgType &= ^structs.IgnoreUnknownTypeFlag
|
||||||
|
ignoreUnknown = true
|
||||||
|
}
|
||||||
|
|
||||||
|
switch msgType {
|
||||||
case structs.RegisterRequestType:
|
case structs.RegisterRequestType:
|
||||||
return c.decodeRegister(buf[1:], log.Index)
|
return c.decodeRegister(buf[1:], log.Index)
|
||||||
case structs.DeregisterRequestType:
|
case structs.DeregisterRequestType:
|
||||||
@ -89,7 +100,12 @@ func (c *consulFSM) Apply(log *raft.Log) interface{} {
|
|||||||
case structs.TombstoneRequestType:
|
case structs.TombstoneRequestType:
|
||||||
return c.applyTombstoneOperation(buf[1:], log.Index)
|
return c.applyTombstoneOperation(buf[1:], log.Index)
|
||||||
default:
|
default:
|
||||||
panic(fmt.Errorf("failed to apply request: %#v", buf))
|
if ignoreUnknown {
|
||||||
|
c.logger.Printf("[WARN] consul.fsm: ignoring unknown message type (%d), upgrade to newer version", msgType)
|
||||||
|
return nil
|
||||||
|
} else {
|
||||||
|
panic(fmt.Errorf("failed to apply request: %#v", buf))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1059,3 +1059,33 @@ func TestFSM_TombstoneReap(t *testing.T) {
|
|||||||
t.Fatalf("bad: %v", res)
|
t.Fatalf("bad: %v", res)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestFSM_IgnoreUnknown(t *testing.T) {
|
||||||
|
path, err := ioutil.TempDir("", "fsm")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("err: %v", err)
|
||||||
|
}
|
||||||
|
defer os.RemoveAll(path)
|
||||||
|
fsm, err := NewFSM(nil, path, os.Stderr)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("err: %v", err)
|
||||||
|
}
|
||||||
|
defer fsm.Close()
|
||||||
|
|
||||||
|
// Create a new reap request
|
||||||
|
type UnknownRequest struct {
|
||||||
|
Foo string
|
||||||
|
}
|
||||||
|
req := UnknownRequest{Foo: "bar"}
|
||||||
|
msgType := structs.IgnoreUnknownTypeFlag | 64
|
||||||
|
buf, err := structs.Encode(msgType, req)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("err: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply should work, even though not supported
|
||||||
|
resp := fsm.Apply(makeLog(buf))
|
||||||
|
if err, ok := resp.(error); ok {
|
||||||
|
t.Fatalf("resp: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -26,6 +26,15 @@ const (
|
|||||||
TombstoneRequestType
|
TombstoneRequestType
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// IgnoreUnknownTypeFlag is set along with a MessageType
|
||||||
|
// to indicate that the message type can be safely ignored
|
||||||
|
// if it is not recognized. This is for future proofing, so
|
||||||
|
// that new commands can be added in a way that won't cause
|
||||||
|
// old servers to crash when the FSM attempts to process them.
|
||||||
|
IgnoreUnknownTypeFlag MessageType = 128
|
||||||
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// HealthAny is special, and is used as a wild card,
|
// HealthAny is special, and is used as a wild card,
|
||||||
// not as a specific state.
|
// not as a specific state.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user