github.com/maier/nomad@v0.4.1-0.20161110003312-a9e3d0b8549d/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 except 163 // KillTimeout 164 destructive := false 165 for _, fDiff := range diff.Fields { 166 switch fDiff.Name { 167 case "KillTimeout": 168 continue 169 default: 170 destructive = true 171 break 172 } 173 } 174 175 // Object changes that can be done in-place are log configs, services, 176 // constraints. 177 if !destructive { 178 for _, oDiff := range diff.Objects { 179 switch oDiff.Name { 180 case "LogConfig", "Service", "Constraint": 181 continue 182 default: 183 destructive = true 184 break 185 } 186 } 187 } 188 189 if destructive { 190 diff.Annotations = append(diff.Annotations, AnnotationForcesDestructiveUpdate) 191 } else { 192 diff.Annotations = append(diff.Annotations, AnnotationForcesInplaceUpdate) 193 } 194 }