open-nomad/scheduler/annotate.go

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

216 lines
5.1 KiB
Go
Raw Normal View History

// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package scheduler
2016-05-11 22:36:28 +00:00
import (
"strconv"
"github.com/hashicorp/nomad/nomad/structs"
)
const (
AnnotationForcesCreate = "forces create"
AnnotationForcesDestroy = "forces destroy"
AnnotationForcesInplaceUpdate = "forces in-place update"
AnnotationForcesDestructiveUpdate = "forces create/destroy update"
)
2016-05-11 22:36:28 +00:00
// UpdateTypes denote the type of update to occur against the task group.
const (
UpdateTypeIgnore = "ignore"
UpdateTypeCreate = "create"
UpdateTypeDestroy = "destroy"
UpdateTypeMigrate = "migrate"
2017-05-23 22:16:44 +00:00
UpdateTypeCanary = "canary"
2016-05-11 22:36:28 +00:00
UpdateTypeInplaceUpdate = "in-place update"
UpdateTypeDestructiveUpdate = "create/destroy update"
)
// Annotate takes the diff between the old and new version of a Job, the
2016-05-12 18:29:38 +00:00
// scheduler's plan annotations and will add annotations to the diff to aide
// human understanding of the plan.
//
// Currently the things that are annotated are:
2016-05-11 22:36:28 +00:00
// * Task group changes will be annotated with:
// - Count up and count down changes
// - Update counts (creates, destroys, migrates, etc)
//
// * Task changes will be annotated with:
// - forces create/destroy update
// - forces in-place update
2016-05-12 18:29:38 +00:00
func Annotate(diff *structs.JobDiff, annotations *structs.PlanAnnotations) error {
tgDiffs := diff.TaskGroups
2016-05-11 22:36:28 +00:00
if len(tgDiffs) == 0 {
return nil
}
2016-05-11 22:36:28 +00:00
for _, tgDiff := range tgDiffs {
2016-05-12 18:29:38 +00:00
if err := annotateTaskGroup(tgDiff, annotations); err != nil {
2016-05-11 22:36:28 +00:00
return err
}
}
2016-05-11 22:36:28 +00:00
return nil
}
// annotateTaskGroup takes a task group diff and annotates it.
2016-05-12 18:29:38 +00:00
func annotateTaskGroup(diff *structs.TaskGroupDiff, annotations *structs.PlanAnnotations) error {
2016-05-11 22:36:28 +00:00
// Annotate the updates
2016-05-12 18:29:38 +00:00
if annotations != nil {
tg, ok := annotations.DesiredTGUpdates[diff.Name]
2016-05-11 22:36:28 +00:00
if ok {
if diff.Updates == nil {
diff.Updates = make(map[string]uint64, 6)
}
if tg.Ignore != 0 {
diff.Updates[UpdateTypeIgnore] = tg.Ignore
}
if tg.Place != 0 {
diff.Updates[UpdateTypeCreate] = tg.Place
}
if tg.Migrate != 0 {
diff.Updates[UpdateTypeMigrate] = tg.Migrate
}
if tg.Stop != 0 {
diff.Updates[UpdateTypeDestroy] = tg.Stop
}
2017-05-23 22:16:44 +00:00
if tg.Canary != 0 {
diff.Updates[UpdateTypeCanary] = tg.Canary
}
2016-05-11 22:36:28 +00:00
if tg.InPlaceUpdate != 0 {
diff.Updates[UpdateTypeInplaceUpdate] = tg.InPlaceUpdate
}
if tg.DestructiveUpdate != 0 {
diff.Updates[UpdateTypeDestructiveUpdate] = tg.DestructiveUpdate
}
}
}
// Annotate the count
2016-05-11 22:36:28 +00:00
if err := annotateCountChange(diff); err != nil {
return err
}
// Annotate the tasks.
taskDiffs := diff.Tasks
2016-05-11 22:36:28 +00:00
if len(taskDiffs) == 0 {
return nil
}
2016-05-11 22:36:28 +00:00
for _, taskDiff := range taskDiffs {
2016-05-13 18:53:11 +00:00
annotateTask(taskDiff, diff)
}
2016-05-11 22:36:28 +00:00
return nil
}
// annotateCountChange takes a task group diff and annotates the count
// parameter.
2016-05-11 22:36:28 +00:00
func annotateCountChange(diff *structs.TaskGroupDiff) error {
var countDiff *structs.FieldDiff
for _, diff := range diff.Fields {
if diff.Name == "Count" {
countDiff = diff
break
}
}
// Didn't find
if countDiff == nil {
return nil
}
2016-05-13 18:53:11 +00:00
var oldV, newV int
var err error
if countDiff.Old == "" {
oldV = 0
} else {
oldV, err = strconv.Atoi(countDiff.Old)
if err != nil {
return err
}
2016-05-11 22:36:28 +00:00
}
2016-05-13 18:53:11 +00:00
if countDiff.New == "" {
newV = 0
} else {
newV, err = strconv.Atoi(countDiff.New)
if err != nil {
return err
}
}
if oldV < newV {
countDiff.Annotations = append(countDiff.Annotations, AnnotationForcesCreate)
} else if newV < oldV {
countDiff.Annotations = append(countDiff.Annotations, AnnotationForcesDestroy)
}
2016-05-11 22:36:28 +00:00
return nil
}
// annotateCountChange takes a task diff and annotates it.
2016-05-13 18:53:11 +00:00
func annotateTask(diff *structs.TaskDiff, parent *structs.TaskGroupDiff) {
if diff.Type == structs.DiffTypeNone {
return
}
2016-05-13 18:53:11 +00:00
// The whole task group is changing
if parent.Type == structs.DiffTypeAdded || parent.Type == structs.DiffTypeDeleted {
if diff.Type == structs.DiffTypeAdded {
diff.Annotations = append(diff.Annotations, AnnotationForcesCreate)
return
} else if diff.Type == structs.DiffTypeDeleted {
diff.Annotations = append(diff.Annotations, AnnotationForcesDestroy)
return
}
}
2016-08-02 03:19:12 +00:00
// All changes to primitive fields result in a destructive update except
// KillTimeout
destructive := false
FieldsLoop:
2016-08-02 03:19:12 +00:00
for _, fDiff := range diff.Fields {
switch fDiff.Name {
case "KillTimeout":
2016-05-11 22:36:28 +00:00
continue
default:
destructive = true
break FieldsLoop
2016-05-11 22:36:28 +00:00
}
}
2016-08-02 03:19:12 +00:00
// Object changes that can be done in-place are log configs, services,
// constraints.
2016-08-02 03:19:12 +00:00
if !destructive {
ObjectsLoop:
2016-08-02 03:19:12 +00:00
for _, oDiff := range diff.Objects {
switch oDiff.Name {
case "Service", "Constraint":
continue
case "LogConfig":
for _, fDiff := range oDiff.Fields {
switch fDiff.Name {
// force a destructive update if logger was enabled or disabled
case "Disabled":
destructive = true
break ObjectsLoop
}
}
2016-08-02 03:19:12 +00:00
continue
default:
destructive = true
break ObjectsLoop
2016-08-02 03:19:12 +00:00
}
}
}
if destructive {
diff.Annotations = append(diff.Annotations, AnnotationForcesDestructiveUpdate)
} else {
diff.Annotations = append(diff.Annotations, AnnotationForcesInplaceUpdate)
}
}