github.com/dkerwin/nomad@v0.3.3-0.20160525181927-74554135514b/scheduler/annotate.go (about) 1 package scheduler 2 3 import ( 4 "strconv" 5 6 "github.com/hashicorp/nomad/nomad/structs" 7 ) 8 9 const ( 10 AnnotationForcesCreate = "forces create" 11 AnnotationForcesDestroy = "forces destroy" 12 AnnotationForcesInplaceUpdate = "forces in-place update" 13 AnnotationForcesDestructiveUpdate = "forces create/destroy update" 14 ) 15 16 // UpdateTypes denote the type of update to occur against the task group. 17 const ( 18 UpdateTypeIgnore = "ignore" 19 UpdateTypeCreate = "create" 20 UpdateTypeDestroy = "destroy" 21 UpdateTypeMigrate = "migrate" 22 UpdateTypeInplaceUpdate = "in-place update" 23 UpdateTypeDestructiveUpdate = "create/destroy update" 24 ) 25 26 // Annotate takes the diff between the old and new version of a Job, the 27 // scheduler's plan annotations and will add annotations to the diff to aide 28 // human understanding of the plan. 29 // 30 // Currently the things that are annotated are: 31 // * Task group changes will be annotated with: 32 // * Count up and count down changes 33 // * Update counts (creates, destroys, migrates, etc) 34 // * Task changes will be annotated with: 35 // * forces create/destroy update 36 // * forces in-place update 37 func Annotate(diff *structs.JobDiff, annotations *structs.PlanAnnotations) error { 38 tgDiffs := diff.TaskGroups 39 if len(tgDiffs) == 0 { 40 return nil 41 } 42 43 for _, tgDiff := range tgDiffs { 44 if err := annotateTaskGroup(tgDiff, annotations); err != nil { 45 return err 46 } 47 } 48 49 return nil 50 } 51 52 // annotateTaskGroup takes a task group diff and annotates it. 53 func annotateTaskGroup(diff *structs.TaskGroupDiff, annotations *structs.PlanAnnotations) error { 54 // Annotate the updates 55 if annotations != nil { 56 tg, ok := annotations.DesiredTGUpdates[diff.Name] 57 if ok { 58 if diff.Updates == nil { 59 diff.Updates = make(map[string]uint64, 6) 60 } 61 62 if tg.Ignore != 0 { 63 diff.Updates[UpdateTypeIgnore] = tg.Ignore 64 } 65 if tg.Place != 0 { 66 diff.Updates[UpdateTypeCreate] = tg.Place 67 } 68 if tg.Migrate != 0 { 69 diff.Updates[UpdateTypeMigrate] = tg.Migrate 70 } 71 if tg.Stop != 0 { 72 diff.Updates[UpdateTypeDestroy] = tg.Stop 73 } 74 if tg.InPlaceUpdate != 0 { 75 diff.Updates[UpdateTypeInplaceUpdate] = tg.InPlaceUpdate 76 } 77 if tg.DestructiveUpdate != 0 { 78 diff.Updates[UpdateTypeDestructiveUpdate] = tg.DestructiveUpdate 79 } 80 } 81 } 82 83 // Annotate the count 84 if err := annotateCountChange(diff); err != nil { 85 return err 86 } 87 88 // Annotate the tasks. 89 taskDiffs := diff.Tasks 90 if len(taskDiffs) == 0 { 91 return nil 92 } 93 94 for _, taskDiff := range taskDiffs { 95 annotateTask(taskDiff, diff) 96 } 97 98 return nil 99 } 100 101 // annotateCountChange takes a task group diff and annotates the count 102 // parameter. 103 func annotateCountChange(diff *structs.TaskGroupDiff) error { 104 var countDiff *structs.FieldDiff 105 for _, diff := range diff.Fields { 106 if diff.Name == "Count" { 107 countDiff = diff 108 break 109 } 110 } 111 112 // Didn't find 113 if countDiff == nil { 114 return nil 115 } 116 var oldV, newV int 117 var err error 118 if countDiff.Old == "" { 119 oldV = 0 120 } else { 121 oldV, err = strconv.Atoi(countDiff.Old) 122 if err != nil { 123 return err 124 } 125 } 126 127 if countDiff.New == "" { 128 newV = 0 129 } else { 130 newV, err = strconv.Atoi(countDiff.New) 131 if err != nil { 132 return err 133 } 134 } 135 136 if oldV < newV { 137 countDiff.Annotations = append(countDiff.Annotations, AnnotationForcesCreate) 138 } else if newV < oldV { 139 countDiff.Annotations = append(countDiff.Annotations, AnnotationForcesDestroy) 140 } 141 142 return nil 143 } 144 145 // annotateCountChange takes a task diff and annotates it. 146 func annotateTask(diff *structs.TaskDiff, parent *structs.TaskGroupDiff) { 147 if diff.Type == structs.DiffTypeNone { 148 return 149 } 150 151 // The whole task group is changing 152 if parent.Type == structs.DiffTypeAdded || parent.Type == structs.DiffTypeDeleted { 153 if diff.Type == structs.DiffTypeAdded { 154 diff.Annotations = append(diff.Annotations, AnnotationForcesCreate) 155 return 156 } else if diff.Type == structs.DiffTypeDeleted { 157 diff.Annotations = append(diff.Annotations, AnnotationForcesDestroy) 158 return 159 } 160 } 161 162 // All changes to primitive fields result in a destructive update. 163 destructive := false 164 if len(diff.Fields) != 0 { 165 destructive = true 166 } 167 168 // Changes that can be done in-place are log configs, services and 169 // constraints. 170 for _, oDiff := range diff.Objects { 171 switch oDiff.Name { 172 case "LogConfig", "Service", "Constraint": 173 continue 174 default: 175 destructive = true 176 break 177 } 178 } 179 180 if destructive { 181 diff.Annotations = append(diff.Annotations, AnnotationForcesDestructiveUpdate) 182 } else { 183 diff.Annotations = append(diff.Annotations, AnnotationForcesInplaceUpdate) 184 } 185 }