consul: Adding flag to support future incompatible commands. Future self will thank me.

This commit is contained in:
Armon Dadgar 2015-05-05 19:44:21 -07:00
parent 27a820d611
commit 35744c7210
3 changed files with 57 additions and 2 deletions

View File

@ -75,7 +75,18 @@ func (c *consulFSM) State() *StateStore {
func (c *consulFSM) Apply(log *raft.Log) interface{} {
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:
return c.decodeRegister(buf[1:], log.Index)
case structs.DeregisterRequestType:
@ -89,7 +100,12 @@ func (c *consulFSM) Apply(log *raft.Log) interface{} {
case structs.TombstoneRequestType:
return c.applyTombstoneOperation(buf[1:], log.Index)
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))
}
}
}

View File

@ -1059,3 +1059,33 @@ func TestFSM_TombstoneReap(t *testing.T) {
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)
}
}

View File

@ -26,6 +26,15 @@ const (
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 (
// HealthAny is special, and is used as a wild card,
// not as a specific state.