@@ -18,6 +18,8 @@ import (
18
18
"fmt"
19
19
"strings"
20
20
21
+ "k8s.io/apimachinery/pkg/fields"
22
+
21
23
"github.com/devfile/devworkspace-operator/apis/controller/v1alpha1"
22
24
"github.com/devfile/devworkspace-operator/controllers/workspace/env"
23
25
maputils "github.com/devfile/devworkspace-operator/internal/map"
@@ -41,13 +43,21 @@ import (
41
43
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
42
44
)
43
45
44
- var ContainerFailureStateReasons = []string {
46
+ var containerFailureStateReasons = []string {
45
47
"CrashLoopBackOff" ,
46
48
"ImagePullBackOff" ,
47
49
"CreateContainerError" ,
48
50
"RunContainerError" ,
49
51
}
50
52
53
+ var unrecoverablePodEventReasons = []string {
54
+ "FailedMount" ,
55
+ "FailedScheduling" ,
56
+ "MountVolume.SetUp failed" ,
57
+ "FailedCreate" ,
58
+ "ReplicaSetCreateError" ,
59
+ }
60
+
51
61
type DeploymentProvisioningStatus struct {
52
62
ProvisioningStatus
53
63
}
@@ -163,21 +173,24 @@ func SyncDeploymentToCluster(
163
173
}
164
174
}
165
175
166
- failureMsg , checkErr := checkFailedPods (workspace , clusterAPI )
176
+ failureMsg , checkErr := checkPodsState (workspace , clusterAPI )
167
177
if checkErr != nil {
168
178
return DeploymentProvisioningStatus {
169
179
ProvisioningStatus : ProvisioningStatus {
170
180
Err : checkErr ,
171
181
},
172
182
}
173
183
}
174
-
175
- return DeploymentProvisioningStatus {
176
- ProvisioningStatus : ProvisioningStatus {
177
- FailStartup : failureMsg != "" ,
178
- Message : failureMsg ,
179
- },
184
+ if failureMsg != "" {
185
+ return DeploymentProvisioningStatus {
186
+ ProvisioningStatus {
187
+ FailStartup : true ,
188
+ Message : failureMsg ,
189
+ },
190
+ }
180
191
}
192
+
193
+ return DeploymentProvisioningStatus {}
181
194
}
182
195
183
196
// DeleteWorkspaceDeployment deletes the deployment for the DevWorkspace
@@ -369,10 +382,12 @@ func getPods(workspace *dw.DevWorkspace, client runtimeClient.Client) (*corev1.P
369
382
return pods , nil
370
383
}
371
384
372
- // checkFailedPods check if related pods has unrecoverable states: CrashLoopBackOffReason, ImagePullErr
385
+ // checkPodsState checks if workspace-related pods are in an unrecoverable state. A pod is considered to be unrecoverable
386
+ // if it has a container with one of the containerStateFailureReasons states, or if an unrecoverable event (with reason
387
+ // matching unrecoverablePodEventReasons) has the pod as the involved object.
373
388
// Returns optional message with detected unrecoverable state details
374
- // error is any happens during check
375
- func checkFailedPods (workspace * dw.DevWorkspace ,
389
+ // error if any happens during check
390
+ func checkPodsState (workspace * dw.DevWorkspace ,
376
391
clusterAPI ClusterAPI ) (stateMsg string , checkFailure error ) {
377
392
podList , err := getPods (workspace , clusterAPI .Client )
378
393
if err != nil {
@@ -390,6 +405,31 @@ func checkFailedPods(workspace *dw.DevWorkspace,
390
405
return fmt .Sprintf ("Init Container %s has state %s" , initContainerStatus .Name , initContainerStatus .State .Waiting .Reason ), nil
391
406
}
392
407
}
408
+ if msg , err := checkPodEvents (& pod , clusterAPI ); err != nil || msg != "" {
409
+ return msg , err
410
+ }
411
+ }
412
+ return "" , nil
413
+ }
414
+
415
+ func checkPodEvents (pod * corev1.Pod , clusterAPI ClusterAPI ) (msg string , err error ) {
416
+ evs := & corev1.EventList {}
417
+ selector , err := fields .ParseSelector (fmt .Sprintf ("involvedObject.name=%s" , pod .Name ))
418
+ if err != nil {
419
+ return "" , fmt .Errorf ("failed to parse field selector: %s" , err )
420
+ }
421
+ if err := clusterAPI .Client .List (clusterAPI .Ctx , evs , k8sclient .InNamespace (pod .Namespace ), k8sclient.MatchingFieldsSelector {Selector : selector }); err != nil {
422
+ return "" , fmt .Errorf ("failed to list events in namespace %s: %w" , pod .Namespace , err )
423
+ }
424
+ for _ , ev := range evs .Items {
425
+ if ev .InvolvedObject .Kind != "Pod" {
426
+ continue
427
+ }
428
+ for _ , fatalEv := range unrecoverablePodEventReasons {
429
+ if ev .Reason == fatalEv {
430
+ return fmt .Sprintf ("Detected unrecoverable event %s: %s" , ev .Reason , ev .Message ), nil
431
+ }
432
+ }
393
433
}
394
434
return "" , nil
395
435
}
@@ -477,7 +517,7 @@ func needsPVCWorkaround(podAdditions *v1alpha1.PodAdditions) bool {
477
517
478
518
func checkContainerStatusForFailure (containerStatus * corev1.ContainerStatus ) (ok bool ) {
479
519
if containerStatus .State .Waiting != nil {
480
- for _ , failureReason := range ContainerFailureStateReasons {
520
+ for _ , failureReason := range containerFailureStateReasons {
481
521
if containerStatus .State .Waiting .Reason == failureReason {
482
522
return false
483
523
}
0 commit comments