diff --git a/scheduler/util.go b/scheduler/util.go index 1069b5a331f..90993d56940 100644 --- a/scheduler/util.go +++ b/scheduler/util.go @@ -341,15 +341,6 @@ func tasksUpdated(jobA, jobB *structs.Job, taskGroup string) bool { a := jobA.LookupTaskGroup(taskGroup) b := jobB.LookupTaskGroup(taskGroup) - // Check Job level Affinities and Constraints - if !reflect.DeepEqual(jobA.Affinities, jobB.Affinities) { - return true - } - - if !reflect.DeepEqual(jobA.Constraints, jobB.Constraints) { - return true - } - // If the number of tasks do not match, clearly there is an update if len(a.Tasks) != len(b.Tasks) { return true @@ -365,13 +356,13 @@ func tasksUpdated(jobA, jobB *structs.Job, taskGroup string) bool { return true } - // Check that the task group affinities haven't changed - if !reflect.DeepEqual(a.Affinities, b.Affinities) { + // Check Affinities + if affinitiesUpdated(jobA, jobB, taskGroup) { return true } - // Check that the task group constraints haven't changed - if !reflect.DeepEqual(a.Constraints, b.Constraints) { + // Check Constraints + if constraintsUpdated(jobA, jobB, taskGroup) { return true } @@ -403,14 +394,6 @@ func tasksUpdated(jobA, jobB *structs.Job, taskGroup string) bool { return true } - if !reflect.DeepEqual(at.Affinities, bt.Affinities) { - return true - } - - if !reflect.DeepEqual(at.Constraints, bt.Constraints) { - return true - } - // Check the metadata if !reflect.DeepEqual( jobA.CombinedTaskMeta(taskGroup, at.Name), @@ -469,6 +452,70 @@ func networkPortMap(n *structs.NetworkResource) map[string]int { return m } +func affinitiesUpdated(jobA, jobB *structs.Job, taskGroup string) bool { + var aAffinities []*structs.Affinity + var bAffinities []*structs.Affinity + + tgA := jobA.LookupTaskGroup(taskGroup) + tgB := jobB.LookupTaskGroup(taskGroup) + + // append job level affinities + aAffinities = append(aAffinities, jobA.Affinities...) + aAffinities = append(aAffinities, tgA.Affinities...) + + // append task group affinities + bAffinities = append(bAffinities, jobB.Affinities...) + bAffinities = append(bAffinities, tgB.Affinities...) + + // append task affinities + for _, task := range tgA.Tasks { + aAffinities = append(aAffinities, task.Affinities...) + } + + // append task affinities + for _, task := range tgB.Tasks { + bAffinities = append(bAffinities, task.Affinities...) + } + + if len(aAffinities) != len(bAffinities) { + return true + } + + return !reflect.DeepEqual(aAffinities, bAffinities) +} + +func constraintsUpdated(jobA, jobB *structs.Job, taskGroup string) bool { + var aConstraints []*structs.Constraint + var bConstraints []*structs.Constraint + + tgA := jobA.LookupTaskGroup(taskGroup) + tgB := jobB.LookupTaskGroup(taskGroup) + + // append job level constraints + aConstraints = append(aConstraints, jobA.Constraints...) + aConstraints = append(aConstraints, tgA.Constraints...) + + // append task group constraints + bConstraints = append(bConstraints, jobB.Constraints...) + bConstraints = append(bConstraints, tgB.Constraints...) + + // append task constraints + for _, task := range tgA.Tasks { + aConstraints = append(aConstraints, task.Constraints...) + } + + // append task constraints + for _, task := range tgB.Tasks { + bConstraints = append(bConstraints, task.Constraints...) + } + + if len(aConstraints) != len(bConstraints) { + return true + } + + return !reflect.DeepEqual(aConstraints, bConstraints) +} + // setStatus is used to update the status of the evaluation func setStatus(logger log.Logger, planner Planner, eval, nextEval, spawnedBlocked *structs.Evaluation, diff --git a/scheduler/util_test.go b/scheduler/util_test.go index ab214d4f1ca..a5e117cabad 100644 --- a/scheduler/util_test.go +++ b/scheduler/util_test.go @@ -394,9 +394,9 @@ func TestTaskUpdatedAffinity(t *testing.T) { // TaskGroup Affinity j2.TaskGroups[0].Affinities = []*structs.Affinity{ { - LTarget: "", - RTarget: "", - Operand: "", + LTarget: "node.datacenter", + RTarget: "dc1", + Operand: "=", Weight: 100, }, } @@ -406,9 +406,9 @@ func TestTaskUpdatedAffinity(t *testing.T) { j3 := mock.Job() j3.TaskGroups[0].Tasks[0].Affinities = []*structs.Affinity{ { - LTarget: "", - RTarget: "", - Operand: "", + LTarget: "node.datacenter", + RTarget: "dc1", + Operand: "=", Weight: 100, }, } @@ -418,19 +418,47 @@ func TestTaskUpdatedAffinity(t *testing.T) { j4 := mock.Job() j4.TaskGroups[0].Tasks[0].Affinities = []*structs.Affinity{ { - LTarget: "", - RTarget: "", - Operand: "", + LTarget: "node.datacenter", + RTarget: "dc1", + Operand: "=", Weight: 100, }, } require.True(t, tasksUpdated(j1, j4, name)) + + // check different level of same constraint + j5 := mock.Job() + j5.Affinities = []*structs.Affinity{ + { + LTarget: "node.datacenter", + RTarget: "dc1", + Operand: "=", + Weight: 100, + }, + } + + j6 := mock.Job() + j6.Affinities = make([]*structs.Affinity, 0) + j6.TaskGroups[0].Affinities = []*structs.Affinity{ + { + LTarget: "node.datacenter", + RTarget: "dc1", + Operand: "=", + Weight: 100, + }, + } + + require.False(t, tasksUpdated(j5, j6, name)) } func TestTaskUpdated_Constraint(t *testing.T) { j1 := mock.Job() + j1.Constraints = make([]*structs.Constraint, 0) + j2 := mock.Job() + j2.Constraints = make([]*structs.Constraint, 0) + name := j1.TaskGroups[0].Name require.False(t, tasksUpdated(j1, j2, name)) @@ -445,6 +473,8 @@ func TestTaskUpdated_Constraint(t *testing.T) { // TaskGroup Task Constraint j3 := mock.Job() + j3.Constraints = make([]*structs.Constraint, 0) + j3.TaskGroups[0].Tasks[0].Constraints = []*structs.Constraint{ { LTarget: "kernel", @@ -456,6 +486,8 @@ func TestTaskUpdated_Constraint(t *testing.T) { require.True(t, tasksUpdated(j1, j3, name)) j4 := mock.Job() + j4.Constraints = make([]*structs.Constraint, 0) + j4.TaskGroups[0].Tasks[0].Constraints = []*structs.Constraint{ { LTarget: "kernel", @@ -465,6 +497,28 @@ func TestTaskUpdated_Constraint(t *testing.T) { } require.True(t, tasksUpdated(j1, j4, name)) + + // check different level of same constraint + j5 := mock.Job() + j5.Constraints = []*structs.Constraint{ + { + LTarget: "kernel", + RTarget: "linux", + Operand: "=", + }, + } + + j6 := mock.Job() + j6.Constraints = make([]*structs.Constraint, 0) + j6.TaskGroups[0].Constraints = []*structs.Constraint{ + { + LTarget: "kernel", + RTarget: "linux", + Operand: "=", + }, + } + + require.False(t, tasksUpdated(j5, j6, name)) } func TestTasksUpdated(t *testing.T) {