@@ -61,17 +61,19 @@ func (c *DeploymentController) Handle(deployment *kapi.ReplicationController) er
61
61
switch currentStatus {
62
62
case deployapi .DeploymentStatusNew :
63
63
// If the deployment has been cancelled, don't create a deployer pod.
64
- // Transition the deployment to Pending so that re-syncs will check
65
- // up on the deployer pods and so that the deployment config controller
66
- // continues to see the deployment as in-flight (which it is until we
67
- // have deployer pod outcomes).
64
+ // Instead try to delete any deployer pods found and transition the
65
+ // deployment to Pending so that the deployment config controller
66
+ // continues to see the deployment as in-flight. Eventually the deletion
67
+ // of the deployer pod should cause a requeue of this deployment and
68
+ // then it can be transitioned to Failed by this controller.
68
69
if deployutil .IsDeploymentCancelled (deployment ) {
69
70
nextStatus = deployapi .DeploymentStatusPending
70
- if err := c .cancelDeployerPods (deployment ); err != nil {
71
+ if err := c .cleanupDeployerPods (deployment ); err != nil {
71
72
return err
72
73
}
73
74
break
74
75
}
76
+
75
77
// If the pod already exists, it's possible that a previous CreatePod
76
78
// succeeded but the deployment state update failed and now we're re-
77
79
// entering. Ensure that the pod is the one we created by verifying the
@@ -126,29 +128,34 @@ func (c *DeploymentController) Handle(deployment *kapi.ReplicationController) er
126
128
case deployapi .DeploymentStatusPending , deployapi .DeploymentStatusRunning :
127
129
// If the deployer pod has vanished, consider the deployment a failure.
128
130
deployerPodName := deployutil .DeployerPodNameForDeployment (deployment .Name )
129
- if _ , err := c .podClient .getPod (deployment .Namespace , deployerPodName ); err != nil {
130
- if kerrors .IsNotFound (err ) {
131
- nextStatus = deployapi .DeploymentStatusFailed
131
+ _ , err := c .podClient .getPod (deployment .Namespace , deployerPodName )
132
+ switch {
133
+ case kerrors .IsNotFound (err ):
134
+ nextStatus = deployapi .DeploymentStatusFailed
135
+ // If the deployment is cancelled here then we deleted the deployer in a previous
136
+ // resync of the deployment.
137
+ if ! deployutil .IsDeploymentCancelled (deployment ) {
132
138
deployment .Annotations [deployapi .DeploymentStatusAnnotation ] = string (nextStatus )
133
139
deployment .Annotations [deployapi .DeploymentStatusReasonAnnotation ] = deployapi .DeploymentFailedDeployerPodNoLongerExists
134
140
c .emitDeploymentEvent (deployment , kapi .EventTypeWarning , "Failed" , fmt .Sprintf ("Deployer pod %q has gone missing" , deployerPodName ))
135
141
glog .V (4 ).Infof ("Failing deployment %q because its deployer pod %q disappeared" , deployutil .LabelForDeployment (deployment ), deployerPodName )
136
- break
137
- } else {
138
- // We'll try again later on resync. Continue to process cancellations.
139
- glog .V (2 ).Infof ("Error getting deployer pod %s for deployment %s: %#v" , deployerPodName , deployutil .LabelForDeployment (deployment ), err )
140
142
}
141
- }
142
143
143
- // If the deployment is cancelled, terminate any deployer/hook pods.
144
- // NOTE: Do not mark the deployment as Failed just yet.
145
- // The deployment will be marked as Failed by the deployer pod controller
146
- // when the deployer pod failure state is picked up.
147
- // Then, the deployment config controller will scale down the failed deployment
148
- // and scale back up the last successful completed deployment.
149
- if deployutil .IsDeploymentCancelled (deployment ) {
150
- if err := c .cancelDeployerPods (deployment ); err != nil {
151
- return err
144
+ case err != nil :
145
+ // We'll try again later on resync. Continue to process cancellations.
146
+ glog .V (4 ).Infof ("Error getting deployer pod %s for deployment %s: %#v" , deployerPodName , deployutil .LabelForDeployment (deployment ), err )
147
+
148
+ default : /* err == nil */
149
+ // If the deployment has been cancelled, delete any deployer pods
150
+ // found and transition the deployment to Pending so that the
151
+ // deployment config controller continues to see the deployment
152
+ // as in-flight. Eventually the deletion of the deployer pod should
153
+ // cause a requeue of this deployment and then it can be transitioned
154
+ // to Failed by this controller.
155
+ if deployutil .IsDeploymentCancelled (deployment ) {
156
+ if err := c .cleanupDeployerPods (deployment ); err != nil {
157
+ return err
158
+ }
152
159
}
153
160
}
154
161
case deployapi .DeploymentStatusFailed :
@@ -157,38 +164,22 @@ func (c *DeploymentController) Handle(deployment *kapi.ReplicationController) er
157
164
deploymentScaled = deployment .Spec .Replicas != 0
158
165
deployment .Spec .Replicas = 0
159
166
}
167
+ // Try to cleanup once more a cancelled deployment in case hook pods
168
+ // were created just after we issued the first cleanup request.
169
+ if deployutil .IsDeploymentCancelled (deployment ) {
170
+ if err := c .cleanupDeployerPods (deployment ); err != nil {
171
+ return err
172
+ }
173
+ }
160
174
case deployapi .DeploymentStatusComplete :
161
175
// Check for test deployment and ensure the deployment scale matches
162
176
if config , err := c .decodeConfig (deployment ); err == nil && config .Spec .Test {
163
177
deploymentScaled = deployment .Spec .Replicas != 0
164
178
deployment .Spec .Replicas = 0
165
179
}
166
180
167
- // now list any pods in the namespace that have the specified label
168
- deployerPods , err := c .podClient .getDeployerPodsFor (deployment .Namespace , deployment .Name )
169
- if err != nil {
170
- return fmt .Errorf ("couldn't fetch deployer pods for %s after successful completion: %v" , deployutil .LabelForDeployment (deployment ), err )
171
- }
172
- if len (deployerPods ) > 0 {
173
- glog .V (4 ).Infof ("Deleting %d deployer pods for deployment %s" , len (deployerPods ), deployutil .LabelForDeployment (deployment ))
174
- }
175
- cleanedAll := true
176
- for _ , deployerPod := range deployerPods {
177
- if err := c .podClient .deletePod (deployerPod .Namespace , deployerPod .Name ); err != nil {
178
- if ! kerrors .IsNotFound (err ) {
179
- // if the pod deletion failed, then log the error and continue
180
- // we will try to delete any remaining deployer pods and return an error later
181
- utilruntime .HandleError (fmt .Errorf ("couldn't delete completed deployer pod %s/%s for deployment %s: %v" , deployment .Namespace , deployerPod .Name , deployutil .LabelForDeployment (deployment ), err ))
182
- cleanedAll = false
183
- }
184
- // Already deleted
185
- } else {
186
- glog .V (4 ).Infof ("Deleted completed deployer pod %s/%s for deployment %s" , deployment .Namespace , deployerPod .Name , deployutil .LabelForDeployment (deployment ))
187
- }
188
- }
189
-
190
- if ! cleanedAll {
191
- return actionableError (fmt .Sprintf ("couldn't clean up all deployer pods for %s" , deployment .Name ))
181
+ if err := c .cleanupDeployerPods (deployment ); err != nil {
182
+ return err
192
183
}
193
184
}
194
185
@@ -264,27 +255,24 @@ func (c *DeploymentController) makeDeployerPod(deployment *kapi.ReplicationContr
264
255
return pod , nil
265
256
}
266
257
267
- func (c * DeploymentController ) cancelDeployerPods (deployment * kapi.ReplicationController ) error {
258
+ func (c * DeploymentController ) cleanupDeployerPods (deployment * kapi.ReplicationController ) error {
268
259
deployerPods , err := c .podClient .getDeployerPodsFor (deployment .Namespace , deployment .Name )
269
260
if err != nil {
270
- return fmt .Errorf ("couldn't fetch deployer pods for %s while trying to cancel deployment : %v" , deployutil .LabelForDeployment (deployment ), err )
261
+ return fmt .Errorf ("couldn't fetch deployer pods for %q : %v" , deployutil .LabelForDeployment (deployment ), err )
271
262
}
272
- glog .V (4 ).Infof ("Cancelling %d deployer pods for deployment %s" , len (deployerPods ), deployutil .LabelForDeployment (deployment ))
273
- zeroDelay := int64 (1 )
274
- cleanedAll := len (deployerPods ) > 0
263
+
264
+ cleanedAll := true
275
265
for _ , deployerPod := range deployerPods {
276
- // Set the ActiveDeadlineSeconds on the pod so it's terminated very soon.
277
- if deployerPod .Spec .ActiveDeadlineSeconds == nil || * deployerPod .Spec .ActiveDeadlineSeconds != zeroDelay {
278
- deployerPod .Spec .ActiveDeadlineSeconds = & zeroDelay
279
- if _ , err := c .podClient .updatePod (deployerPod .Namespace , & deployerPod ); err != nil {
280
- cleanedAll = false
281
- utilruntime .HandleError (fmt .Errorf ("couldn't cancel deployer pod %s for deployment %s: %v" , deployerPod .Name , deployutil .LabelForDeployment (deployment ), err ))
282
- }
283
- glog .V (4 ).Infof ("Cancelled deployer pod %s for deployment %s" , deployerPod .Name , deployutil .LabelForDeployment (deployment ))
266
+ if err := c .podClient .deletePod (deployerPod .Namespace , deployerPod .Name ); err != nil && ! kerrors .IsNotFound (err ) {
267
+ // if the pod deletion failed, then log the error and continue
268
+ // we will try to delete any remaining deployer pods and return an error later
269
+ utilruntime .HandleError (fmt .Errorf ("couldn't delete completed deployer pod %q for deployment %q: %v" , deployerPod .Name , deployutil .LabelForDeployment (deployment ), err ))
270
+ cleanedAll = false
284
271
}
285
272
}
286
- if cleanedAll {
287
- c .emitDeploymentEvent (deployment , kapi .EventTypeNormal , "Cancelled" , "Cancelled all deployer pods" )
273
+
274
+ if ! cleanedAll {
275
+ return actionableError (fmt .Sprintf ("couldn't clean up all deployer pods for %s" , deployment .Name ))
288
276
}
289
277
return nil
290
278
}
0 commit comments