Handle upgrade where Node doesn't have eligiblity

This PR handles upgrading a node that has no scheduling eligiblity set.
This commit is contained in:
Alex Dadgar
2018-03-29 16:33:11 -07:00
committed by Alex Dadgar
parent f5efd5f620
commit 223c9c7948
4 changed files with 75 additions and 3 deletions

View File

@@ -269,6 +269,9 @@ func (n *nomadFSM) applyUpsertNode(buf []byte, index uint64) interface{} {
panic(fmt.Errorf("failed to decode request: %v", err))
}
// Handle upgrade paths
req.Node.Canonicalize()
if err := n.state.UpsertNode(index, req.Node); err != nil {
n.logger.Printf("[ERR] nomad.fsm: UpsertNode failed: %v", err)
return err
@@ -1048,6 +1051,10 @@ func (n *nomadFSM) Restore(old io.ReadCloser) error {
if err := dec.Decode(node); err != nil {
return err
}
// Handle upgrade paths
node.Canonicalize()
if err := restore.NodeRestore(node); err != nil {
return err
}

View File

@@ -176,6 +176,35 @@ func TestFSM_UpsertNode(t *testing.T) {
}
func TestFSM_UpsertNode_Canonicalize(t *testing.T) {
t.Parallel()
require := require.New(t)
fsm := testFSM(t)
fsm.blockedEvals.SetEnabled(true)
// Setup a node without eligiblity
node := mock.Node()
node.SchedulingEligibility = ""
req := structs.NodeRegisterRequest{
Node: node,
}
buf, err := structs.Encode(structs.NodeRegisterRequestType, req)
require.Nil(err)
resp := fsm.Apply(makeLog(buf))
require.Nil(resp)
// Verify we are registered
ws := memdb.NewWatchSet()
n, err := fsm.State().NodeByID(ws, req.Node.ID)
require.Nil(err)
require.NotNil(n)
require.EqualValues(1, n.CreateIndex)
require.Equal(structs.NodeSchedulingEligible, n.SchedulingEligibility)
}
func TestFSM_DeregisterNode(t *testing.T) {
t.Parallel()
fsm := testFSM(t)
@@ -2196,15 +2225,18 @@ func TestFSM_SnapshotRestore_Nodes(t *testing.T) {
state := fsm.State()
node1 := mock.Node()
state.UpsertNode(1000, node1)
// Upgrade this node
node2 := mock.Node()
node2.SchedulingEligibility = ""
state.UpsertNode(1001, node2)
// Verify the contents
fsm2 := testSnapshotRestore(t, fsm)
state2 := fsm2.State()
ws := memdb.NewWatchSet()
out1, _ := state2.NodeByID(ws, node1.ID)
out2, _ := state2.NodeByID(ws, node2.ID)
out1, _ := state2.NodeByID(nil, node1.ID)
out2, _ := state2.NodeByID(nil, node2.ID)
node2.SchedulingEligibility = structs.NodeSchedulingEligible
if !reflect.DeepEqual(node1, out1) {
t.Fatalf("bad: \n%#v\n%#v", out1, node1)
}

View File

@@ -1426,6 +1426,23 @@ func (n *Node) Ready() bool {
return n.Status == NodeStatusReady && !n.Drain && n.SchedulingEligibility == NodeSchedulingEligible
}
func (n *Node) Canonicalize() {
if n == nil {
return
}
// COMPAT Remove in 0.10
// In v0.8.0 we introduced scheduling eligibility, so we need to set it for
// upgrading nodes
if n.SchedulingEligibility == "" {
if n.Drain {
n.SchedulingEligibility = NodeSchedulingIneligible
} else {
n.SchedulingEligibility = NodeSchedulingEligible
}
}
}
func (n *Node) Copy() *Node {
if n == nil {
return nil

View File

@@ -3679,3 +3679,19 @@ func TestBatchFuture(t *testing.T) {
t.Fatalf("bad: %d", bf.Index())
}
}
func TestNode_Canonicalize(t *testing.T) {
t.Parallel()
require := require.New(t)
// Make sure the eligiblity is set properly
node := &Node{}
node.Canonicalize()
require.Equal(NodeSchedulingEligible, node.SchedulingEligibility)
node = &Node{
Drain: true,
}
node.Canonicalize()
require.Equal(NodeSchedulingIneligible, node.SchedulingEligibility)
}