diff --git a/nomad/plan_apply.go b/nomad/plan_apply.go index 73761d860..8721b339a 100644 --- a/nomad/plan_apply.go +++ b/nomad/plan_apply.go @@ -655,6 +655,11 @@ func evaluateNodePlan(snap *state.StateSnapshot, plan *structs.Plan, nodeID stri // the Raft commit happens. if node == nil { return false, "node does not exist", nil + } else if node.Status == structs.NodeStatusDisconnected { + if isValidForDisconnectedNode(plan, node.ID) { + return true, "", nil + } + return false, "node is disconnected and contains invalid updates", nil } else if node.Status != structs.NodeStatusReady { return false, "node is not ready for placements", nil } else if node.SchedulingEligibility == structs.NodeSchedulingIneligible { @@ -690,6 +695,22 @@ func evaluateNodePlan(snap *state.StateSnapshot, plan *structs.Plan, nodeID stri return fit, reason, err } +// The plan is only valid for disconnected nodes if it only contains +// updates to mark allocations as unknown. +func isValidForDisconnectedNode(plan *structs.Plan, nodeID string) bool { + if len(plan.NodeUpdate[nodeID]) != 0 || len(plan.NodePreemptions[nodeID]) != 0 { + return false + } + + for _, alloc := range plan.NodeAllocation[nodeID] { + if alloc.ClientStatus != structs.AllocClientStatusUnknown { + return false + } + } + + return true +} + func max(a, b uint64) uint64 { if a > b { return a