@@ -5,8 +5,6 @@ package reconciler
55
66import (
77 "fmt"
8- "maps"
9- "math"
108 "slices"
119 "time"
1210
@@ -61,19 +59,14 @@ func (nr *NodeReconciler) Compute(
6159 // Create the required task groups.
6260 required := materializeSystemTaskGroups (job )
6361
64- // Canary deployments deploy to the TaskGroup.UpdateStrategy.Canary
65- // percentage of eligible nodes, so we create a mapping of task group name
66- // to a list of nodes that canaries should be placed on.
67- canaryNodes , canariesPerTG := nr .computeCanaryNodes (required , nodeAllocs , terminal , eligibleNodes )
68-
6962 compatHadExistingDeployment := nr .DeploymentCurrent != nil
7063
7164 result := new (NodeReconcileResult )
7265 var deploymentComplete bool
7366 for nodeID , allocs := range nodeAllocs {
7467 diff , deploymentCompleteForNode := nr .computeForNode (job , nodeID , eligibleNodes ,
75- notReadyNodes , taintedNodes , canaryNodes [ nodeID ], canariesPerTG , required ,
76- allocs , terminal , serverSupportsDisconnectedClients )
68+ notReadyNodes , taintedNodes , required , allocs , terminal ,
69+ serverSupportsDisconnectedClients )
7770 result .Append (diff )
7871
7972 deploymentComplete = deploymentCompleteForNode
@@ -95,88 +88,6 @@ func (nr *NodeReconciler) Compute(
9588 return result
9689}
9790
98- // computeCanaryNodes is a helper function that, given required task groups,
99- // mappings of nodes to their live allocs and terminal allocs, and a map of
100- // eligible nodes, outputs a map[nodeID] -> map[TG] -> bool which indicates
101- // which TGs this node is a canary for, and a map[TG] -> int to indicate how
102- // many total canaries are to be placed for a TG.
103- func (nr * NodeReconciler ) computeCanaryNodes (required map [string ]* structs.TaskGroup ,
104- liveAllocs map [string ][]* structs.Allocation , terminalAllocs structs.TerminalByNodeByName ,
105- eligibleNodes map [string ]* structs.Node ) (map [string ]map [string ]bool , map [string ]int ) {
106-
107- canaryNodes := map [string ]map [string ]bool {}
108- eligibleNodesList := slices .Collect (maps .Values (eligibleNodes ))
109- canariesPerTG := map [string ]int {}
110-
111- for _ , tg := range required {
112- if tg .Update .IsEmpty () || tg .Update .Canary == 0 {
113- continue
114- }
115-
116- // round up to the nearest integer
117- numberOfCanaryNodes := int (math .Ceil (float64 (tg .Update .Canary ) * float64 (len (eligibleNodes )) / 100 ))
118- canariesPerTG [tg .Name ] = numberOfCanaryNodes
119-
120- // check if there are any live allocations on any nodes that are/were
121- // canaries.
122- for nodeID , allocs := range liveAllocs {
123- for _ , a := range allocs {
124- eligibleNodesList , numberOfCanaryNodes = nr .findOldCanaryNodes (
125- eligibleNodesList , numberOfCanaryNodes , a , tg , canaryNodes , nodeID )
126- }
127- }
128-
129- // check if there are any terminal allocations that were canaries
130- for nodeID , terminalAlloc := range terminalAllocs {
131- for _ , a := range terminalAlloc {
132- eligibleNodesList , numberOfCanaryNodes = nr .findOldCanaryNodes (
133- eligibleNodesList , numberOfCanaryNodes , a , tg , canaryNodes , nodeID )
134- }
135- }
136-
137- for i , n := range eligibleNodesList {
138- if i > numberOfCanaryNodes - 1 {
139- break
140- }
141-
142- if _ , ok := canaryNodes [n .ID ]; ! ok {
143- canaryNodes [n .ID ] = map [string ]bool {}
144- }
145-
146- canaryNodes [n.ID ][tg.Name ] = true
147- }
148- }
149-
150- return canaryNodes , canariesPerTG
151- }
152-
153- func (nr * NodeReconciler ) findOldCanaryNodes (nodesList []* structs.Node , numberOfCanaryNodes int ,
154- a * structs.Allocation , tg * structs.TaskGroup , canaryNodes map [string ]map [string ]bool , nodeID string ) ([]* structs.Node , int ) {
155-
156- if a .DeploymentStatus == nil || a .DeploymentStatus .Canary == false ||
157- nr .DeploymentCurrent == nil {
158- return nodesList , numberOfCanaryNodes
159- }
160-
161- nodes := nodesList
162- numberOfCanaries := numberOfCanaryNodes
163- if a .TaskGroup == tg .Name {
164- if _ , ok := canaryNodes [nodeID ]; ! ok {
165- canaryNodes [nodeID ] = map [string ]bool {}
166- }
167- canaryNodes [nodeID ][tg.Name ] = true
168-
169- // this node should no longer be considered when searching
170- // for canary nodes
171- numberOfCanaries -= 1
172- nodes = slices .DeleteFunc (
173- nodes ,
174- func (n * structs.Node ) bool { return n .ID == nodeID },
175- )
176- }
177- return nodes , numberOfCanaries
178- }
179-
18091// computeForNode is used to do a set difference between the target
18192// allocations and the existing allocations for a particular node. This returns
18293// 8 sets of results:
@@ -199,8 +110,6 @@ func (nr *NodeReconciler) computeForNode(
199110 eligibleNodes map [string ]* structs.Node ,
200111 notReadyNodes map [string ]struct {}, // nodes that are not ready, e.g. draining
201112 taintedNodes map [string ]* structs.Node , // nodes which are down (by node id)
202- canaryNode map [string ]bool , // indicates whether this node is a canary node for tg
203- canariesPerTG map [string ]int , // indicates how many canary placements we expect per tg
204113 required map [string ]* structs.TaskGroup , // set of allocations that must exist
205114 liveAllocs []* structs.Allocation , // non-terminal allocations that exist
206115 terminal structs.TerminalByNodeByName , // latest terminal allocations (by node, id)
@@ -225,9 +134,6 @@ func (nr *NodeReconciler) computeForNode(
225134 deploymentFailed = nr .DeploymentCurrent .Status == structs .DeploymentStatusFailed
226135 }
227136
228- // Track desired total and desired canaries across all loops
229- desiredCanaries := map [string ]int {}
230-
231137 // Track whether we're during a canary update
232138 isCanarying := map [string ]bool {}
233139
@@ -388,17 +294,14 @@ func (nr *NodeReconciler) computeForNode(
388294
389295 // If the definition is updated we need to update
390296 if job .JobModifyIndex != alloc .Job .JobModifyIndex {
391- if canariesPerTG [ tg .Name ] > 0 && dstate != nil && ! dstate .Promoted {
297+ if ! tg .Update . IsEmpty () && tg . Update . Canary > 0 && dstate != nil && ! dstate .Promoted {
392298 isCanarying [tg .Name ] = true
393- if canaryNode [tg .Name ] {
394- result .Update = append (result .Update , AllocTuple {
395- Name : name ,
396- TaskGroup : tg ,
397- Alloc : alloc ,
398- Canary : true ,
399- })
400- desiredCanaries [tg .Name ] += 1
401- }
299+ result .Update = append (result .Update , AllocTuple {
300+ Name : name ,
301+ TaskGroup : tg ,
302+ Alloc : alloc ,
303+ Canary : true ,
304+ })
402305 } else {
403306 result .Update = append (result .Update , AllocTuple {
404307 Name : name ,
@@ -443,10 +346,6 @@ func (nr *NodeReconciler) computeForNode(
443346 dstate .DesiredTotal = len (eligibleNodes )
444347 }
445348
446- if isCanarying [tg .Name ] && ! dstate .Promoted {
447- dstate .DesiredCanaries = canariesPerTG [tg .Name ]
448- }
449-
450349 // Check for an existing allocation
451350 if _ , ok := existing [name ]; ! ok {
452351
0 commit comments