diff --git a/nomad/structs/funcs.go b/nomad/structs/funcs.go index 91298c97b45..5ace4bc8caa 100644 --- a/nomad/structs/funcs.go +++ b/nomad/structs/funcs.go @@ -111,6 +111,11 @@ func AllocsFit(node *Node, allocs []*Allocation, netIdx *NetworkIndex) (bool, st // For each alloc, add the resources for _, alloc := range allocs { + // Do not consider the resource impact of terminal allocations + if alloc.TerminalStatus() { + continue + } + if alloc.Resources != nil { if err := used.Add(alloc.Resources); err != nil { return false, "", nil, err diff --git a/nomad/structs/funcs_test.go b/nomad/structs/funcs_test.go index 7c0ba5dcab1..cbda393c64a 100644 --- a/nomad/structs/funcs_test.go +++ b/nomad/structs/funcs_test.go @@ -216,6 +216,91 @@ func TestAllocsFit(t *testing.T) { } +func TestAllocsFit_TerminalAlloc(t *testing.T) { + n := &Node{ + Resources: &Resources{ + CPU: 2000, + MemoryMB: 2048, + DiskMB: 10000, + IOPS: 100, + Networks: []*NetworkResource{ + { + Device: "eth0", + CIDR: "10.0.0.0/8", + MBits: 100, + }, + }, + }, + Reserved: &Resources{ + CPU: 1000, + MemoryMB: 1024, + DiskMB: 5000, + IOPS: 50, + Networks: []*NetworkResource{ + { + Device: "eth0", + IP: "10.0.0.1", + MBits: 50, + ReservedPorts: []Port{{"main", 80}}, + }, + }, + }, + } + + a1 := &Allocation{ + Resources: &Resources{ + CPU: 1000, + MemoryMB: 1024, + DiskMB: 5000, + IOPS: 50, + Networks: []*NetworkResource{ + { + Device: "eth0", + IP: "10.0.0.1", + MBits: 50, + ReservedPorts: []Port{{"main", 8000}}, + }, + }, + }, + } + + // Should fit one allocation + fit, _, used, err := AllocsFit(n, []*Allocation{a1}, nil) + if err != nil { + t.Fatalf("err: %v", err) + } + if !fit { + t.Fatalf("Bad") + } + + // Sanity check the used resources + if used.CPU != 2000 { + t.Fatalf("bad: %#v", used) + } + if used.MemoryMB != 2048 { + t.Fatalf("bad: %#v", used) + } + + // Should fit second allocation since it is terminal + a2 := a1.Copy() + a2.DesiredStatus = AllocDesiredStatusStop + fit, _, used, err = AllocsFit(n, []*Allocation{a1, a2}, nil) + if err != nil { + t.Fatalf("err: %v", err) + } + if !fit { + t.Fatalf("Bad") + } + + // Sanity check the used resources + if used.CPU != 2000 { + t.Fatalf("bad: %#v", used) + } + if used.MemoryMB != 2048 { + t.Fatalf("bad: %#v", used) + } +} + func TestScoreFit(t *testing.T) { node := &Node{} node.Resources = &Resources{ diff --git a/nomad/structs/structs.go b/nomad/structs/structs.go index 1588cc101ba..d4ea11036c3 100644 --- a/nomad/structs/structs.go +++ b/nomad/structs/structs.go @@ -6882,8 +6882,11 @@ type Evaluation struct { LeaderACL string // SnapshotIndex is the Raft index of the snapshot used to process the - // evaluation. As such it will only be set once it has gone through the - // scheduler. + // evaluation. The index will either be set when it has gone through the + // scheduler or if a blocked evaluation is being created. The index is set + // in this case so we can determine if an early unblocking is required since + // capacity has changed since the evaluation was created. This can result in + // the SnapshotIndex being less than the CreateIndex. SnapshotIndex uint64 // Raft Indexes @@ -7138,6 +7141,10 @@ func (p *Plan) PopUpdate(alloc *Allocation) { func (p *Plan) AppendAlloc(alloc *Allocation) { node := alloc.NodeID existing := p.NodeAllocation[node] + + // Normalize the job + alloc.Job = nil + p.NodeAllocation[node] = append(existing, alloc) } diff --git a/nomad/worker.go b/nomad/worker.go index b6bab0bbc94..911f4ee3a40 100644 --- a/nomad/worker.go +++ b/nomad/worker.go @@ -326,7 +326,7 @@ SUBMIT: } return nil, nil, err } else { - w.logger.Debug("submitted plan for evaluation", "plan_resp_index", resp.Index, "eval_id", plan.EvalID) + w.logger.Debug("submitted plan for evaluation", "eval_id", plan.EvalID) w.backoffReset() }