scheduler: create allocs for failed placements

This commit is contained in:
Armon Dadgar 2015-08-15 13:40:13 -07:00
parent cabefa46bf
commit 9fd8049e16
4 changed files with 70 additions and 14 deletions

View File

@ -870,9 +870,13 @@ func (p *Plan) AppendAlloc(alloc *Allocation) {
p.NodeAllocation[node] = append(existing, alloc)
}
func (p *Plan) AppendFailed(alloc *Allocation) {
p.FailedAllocs = append(p.FailedAllocs, alloc)
}
// IsNoOp checks if this plan would do nothing
func (p *Plan) IsNoOp() bool {
return len(p.NodeEvict) == 0 && len(p.NodeAllocation) == 0
return len(p.NodeEvict) == 0 && len(p.NodeAllocation) == 0 && len(p.FailedAllocs) == 0
}
// PlanResult is the result of a plan submitted to the leader.

View File

@ -196,25 +196,33 @@ func (s *GenericScheduler) computePlacements(job *structs.Job, place []allocTupl
for _, missing := range place {
option, size := stack.Select(missing.TaskGroup)
var nodeID, status, desc string
if option == nil {
s.logger.Printf("[DEBUG] sched: %#v: failed to place alloc %s: %#v",
s.eval, missing.Name, ctx.Metrics())
continue
status = structs.AllocStatusFailed
desc = "failed to find a node for placement"
} else {
nodeID = option.Node.ID
status = structs.AllocStatusPending
}
// Create an allocation for this
alloc := &structs.Allocation{
ID: mock.GenerateUUID(),
EvalID: s.eval.ID,
Name: missing.Name,
NodeID: option.Node.ID,
JobID: job.ID,
Job: job,
Resources: size,
Metrics: ctx.Metrics(),
Status: structs.AllocStatusPending,
ID: mock.GenerateUUID(),
EvalID: s.eval.ID,
Name: missing.Name,
NodeID: nodeID,
JobID: job.ID,
Job: job,
Resources: size,
Metrics: ctx.Metrics(),
Status: status,
StatusDescription: desc,
}
if nodeID != "" {
s.plan.AppendAlloc(alloc)
} else {
s.plan.AppendFailed(alloc)
}
s.plan.AppendAlloc(alloc)
}
return nil
}

View File

@ -59,6 +59,49 @@ func TestServiceSched_JobRegister(t *testing.T) {
}
}
func TestServiceSched_JobRegister_AllocFail(t *testing.T) {
h := NewHarness(t)
// Create NO nodes
// Create a job
job := mock.Job()
noErr(t, h.State.RegisterJob(h.NextIndex(), job))
// Create a mock evaluation to deregister the job
eval := &structs.Evaluation{
ID: mock.GenerateUUID(),
Priority: job.Priority,
TriggeredBy: structs.EvalTriggerJobRegister,
JobID: job.ID,
}
// Process the evaluation
err := h.Process(NewServiceScheduler, eval)
if err != nil {
t.Fatalf("err: %v", err)
}
// Ensure a single plan
if len(h.Plans) != 1 {
t.Fatalf("bad: %#v", h.Plans)
}
plan := h.Plans[0]
// Ensure the plan failed to alloc
if len(plan.FailedAllocs) != 10 {
t.Fatalf("bad: %#v", plan)
}
// Lookup the allocations by JobID
out, err := h.State.AllocsByJob(job.ID)
noErr(t, err)
// Ensure all allocations placed
if len(out) != 10 {
t.Fatalf("bad: %#v", out)
}
}
func TestServiceSched_JobModify(t *testing.T) {
h := NewHarness(t)

View File

@ -71,6 +71,7 @@ func (h *Harness) SubmitPlan(plan *structs.Plan) (*structs.PlanResult, State, er
for _, allocList := range plan.NodeAllocation {
allocs = append(allocs, allocList...)
}
allocs = append(allocs, plan.FailedAllocs...)
// Apply the full plan
err := h.State.UpdateAllocations(index, evicts, allocs)