Merge pull request #6541 from hashicorp/release-0100-net-panic
core: fix panic when AllocatedResources is nil
This commit is contained in:
parent
be337960fd
commit
3354d5d715
|
@ -2164,6 +2164,92 @@ func TestServiceSched_JobModify_InPlace(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestServiceSched_JobModify_InPlace08 asserts that inplace updates of
|
||||||
|
// allocations created with Nomad 0.8 do not cause panics.
|
||||||
|
//
|
||||||
|
// COMPAT(0.11) - While we do not guarantee that upgrades from 0.8 -> 0.10
|
||||||
|
// (skipping 0.9) are safe, we do want to avoid panics in the scheduler which
|
||||||
|
// cause unrecoverable server outages with no chance of recovery.
|
||||||
|
//
|
||||||
|
// Safe to remove in 0.11.0 as no one should ever be trying to upgrade from 0.8
|
||||||
|
// to 0.11!
|
||||||
|
func TestServiceSched_JobModify_InPlace08(t *testing.T) {
|
||||||
|
h := NewHarness(t)
|
||||||
|
|
||||||
|
// Create node
|
||||||
|
node := mock.Node()
|
||||||
|
noErr(t, h.State.UpsertNode(h.NextIndex(), node))
|
||||||
|
|
||||||
|
// Generate a fake job with 0.8 allocations
|
||||||
|
job := mock.Job()
|
||||||
|
job.TaskGroups[0].Count = 1
|
||||||
|
noErr(t, h.State.UpsertJob(h.NextIndex(), job))
|
||||||
|
|
||||||
|
// Create 0.8 alloc
|
||||||
|
alloc := mock.Alloc()
|
||||||
|
alloc.Job = job.Copy()
|
||||||
|
alloc.JobID = job.ID
|
||||||
|
alloc.NodeID = node.ID
|
||||||
|
alloc.AllocatedResources = nil // 0.8 didn't have this
|
||||||
|
noErr(t, h.State.UpsertAllocs(h.NextIndex(), []*structs.Allocation{alloc}))
|
||||||
|
|
||||||
|
// Update the job inplace
|
||||||
|
job2 := job.Copy()
|
||||||
|
|
||||||
|
job2.TaskGroups[0].Tasks[0].Services[0].Tags[0] = "newtag"
|
||||||
|
noErr(t, h.State.UpsertJob(h.NextIndex(), job2))
|
||||||
|
|
||||||
|
// Create a mock evaluation
|
||||||
|
eval := &structs.Evaluation{
|
||||||
|
Namespace: structs.DefaultNamespace,
|
||||||
|
ID: uuid.Generate(),
|
||||||
|
Priority: 50,
|
||||||
|
TriggeredBy: structs.EvalTriggerJobRegister,
|
||||||
|
JobID: job.ID,
|
||||||
|
Status: structs.EvalStatusPending,
|
||||||
|
}
|
||||||
|
noErr(t, h.State.UpsertEvals(h.NextIndex(), []*structs.Evaluation{eval}))
|
||||||
|
|
||||||
|
// Process the evaluation
|
||||||
|
err := h.Process(NewServiceScheduler, eval)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// Ensure a single plan
|
||||||
|
require.Len(t, h.Plans, 1)
|
||||||
|
plan := h.Plans[0]
|
||||||
|
|
||||||
|
// Ensure the plan did not evict any allocs
|
||||||
|
var update []*structs.Allocation
|
||||||
|
for _, updateList := range plan.NodeUpdate {
|
||||||
|
update = append(update, updateList...)
|
||||||
|
}
|
||||||
|
require.Zero(t, update)
|
||||||
|
|
||||||
|
// Ensure the plan updated the existing alloc
|
||||||
|
var planned []*structs.Allocation
|
||||||
|
for _, allocList := range plan.NodeAllocation {
|
||||||
|
planned = append(planned, allocList...)
|
||||||
|
}
|
||||||
|
require.Len(t, planned, 1)
|
||||||
|
for _, p := range planned {
|
||||||
|
require.Equal(t, job2, p.Job)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lookup the allocations by JobID
|
||||||
|
ws := memdb.NewWatchSet()
|
||||||
|
out, err := h.State.AllocsByJob(ws, job.Namespace, job.ID, false)
|
||||||
|
noErr(t, err)
|
||||||
|
|
||||||
|
// Ensure all allocations placed
|
||||||
|
require.Len(t, out, 1)
|
||||||
|
h.AssertEvalStatus(t, structs.EvalStatusComplete)
|
||||||
|
|
||||||
|
newAlloc := out[0]
|
||||||
|
|
||||||
|
// Verify AllocatedResources was set
|
||||||
|
require.NotNil(t, newAlloc.AllocatedResources)
|
||||||
|
}
|
||||||
|
|
||||||
func TestServiceSched_JobModify_DistinctProperty(t *testing.T) {
|
func TestServiceSched_JobModify_DistinctProperty(t *testing.T) {
|
||||||
h := NewHarness(t)
|
h := NewHarness(t)
|
||||||
|
|
||||||
|
|
|
@ -838,13 +838,19 @@ func genericAllocUpdateFn(ctx Context, stack Stack, evalID string) allocUpdateTy
|
||||||
Tasks: option.TaskResources,
|
Tasks: option.TaskResources,
|
||||||
Shared: structs.AllocatedSharedResources{
|
Shared: structs.AllocatedSharedResources{
|
||||||
DiskMB: int64(newTG.EphemeralDisk.SizeMB),
|
DiskMB: int64(newTG.EphemeralDisk.SizeMB),
|
||||||
// Since this is an inplace update, we should copy network
|
|
||||||
// information from the original alloc. This is similar to
|
|
||||||
// how we copy network info for task level networks above.
|
|
||||||
Networks: existing.AllocatedResources.Shared.Networks,
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Since this is an inplace update, we should copy network
|
||||||
|
// information from the original alloc. This is similar to how
|
||||||
|
// we copy network info for task level networks above.
|
||||||
|
//
|
||||||
|
// existing.AllocatedResources is nil on Allocations created by
|
||||||
|
// Nomad v0.8 or earlier.
|
||||||
|
if existing.AllocatedResources != nil {
|
||||||
|
newAlloc.AllocatedResources.Shared.Networks = existing.AllocatedResources.Shared.Networks
|
||||||
|
}
|
||||||
|
|
||||||
// Use metrics from existing alloc for in place upgrade
|
// Use metrics from existing alloc for in place upgrade
|
||||||
// This is because if the inplace upgrade succeeded, any scoring metadata from
|
// This is because if the inplace upgrade succeeded, any scoring metadata from
|
||||||
// when it first went through the scheduler should still be preserved. Using scoring
|
// when it first went through the scheduler should still be preserved. Using scoring
|
||||||
|
|
Loading…
Reference in a new issue