From dceda9a6a16a914b916c478ecd0b4c8ed0e19c40 Mon Sep 17 00:00:00 2001
From: gossion <guwe@microsoft.com>
Date: Tue, 8 Apr 2025 17:49:53 +0800
Subject: [PATCH] fix: pod analyzer catches errors when containers are in
 Terminated state (#1438)

Signed-off-by: Guoxun Wei <guwe@microsoft.com>
Co-authored-by: Alex Jones <alexsimonjones@gmail.com>
---
 pkg/analyzer/pod.go      | 14 +++++++++++
 pkg/analyzer/pod_test.go | 51 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 65 insertions(+)

diff --git a/pkg/analyzer/pod.go b/pkg/analyzer/pod.go
index 8bc037d..369ffad 100644
--- a/pkg/analyzer/pod.go
+++ b/pkg/analyzer/pod.go
@@ -123,6 +123,20 @@ func analyzeContainerStatusFailures(a common.Analyzer, statuses []v1.ContainerSt
 					Sensitive: []common.Sensitive{},
 				})
 			}
+		} else if containerStatus.State.Terminated != nil {
+			if containerStatus.State.Terminated.ExitCode != 0 {
+				// This represents a container that is terminated abnormally
+				// https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#container-state-terminated
+				exitCode := containerStatus.State.Terminated.ExitCode
+				reason := containerStatus.State.Terminated.Reason
+				if reason == "" {
+					reason = "Unknown"
+				}
+				failures = append(failures, common.Failure{
+					Text:      fmt.Sprintf("the termination reason is %s exitCode=%d container=%s pod=%s", reason, exitCode, containerStatus.Name, name),
+					Sensitive: []common.Sensitive{},
+				})
+			}
 		} else {
 			// when pod is Running but its ReadinessProbe fails
 			if !containerStatus.Ready && statusPhase == "Running" {
diff --git a/pkg/analyzer/pod_test.go b/pkg/analyzer/pod_test.go
index b9973a3..6f7e19e 100644
--- a/pkg/analyzer/pod_test.go
+++ b/pkg/analyzer/pod_test.go
@@ -343,6 +343,57 @@ func TestPodAnalyzer(t *testing.T) {
 				},
 			},
 		},
+		{
+			name: "Terminated container with non-zero exit code",
+			config: common.Analyzer{
+				Client: &kubernetes.Client{
+					Client: fake.NewSimpleClientset(
+						&v1.Pod{
+							ObjectMeta: metav1.ObjectMeta{
+								Name:      "Pod1",
+								Namespace: "default",
+							},
+							Status: v1.PodStatus{
+								Phase: v1.PodFailed,
+								ContainerStatuses: []v1.ContainerStatus{
+									{
+										Name:  "Container1",
+										Ready: false,
+										State: v1.ContainerState{
+											Terminated: &v1.ContainerStateTerminated{
+												ExitCode: 1,
+												Reason:   "Error",
+											},
+										},
+									},
+									{
+										Name:  "Container2",
+										Ready: false,
+										State: v1.ContainerState{
+											Terminated: &v1.ContainerStateTerminated{
+												ExitCode: 2,
+												Reason:   "",
+											},
+										},
+									},
+								},
+							},
+						},
+					),
+				},
+				Context:   context.Background(),
+				Namespace: "default",
+			},
+			expectations: []struct {
+				name          string
+				failuresCount int
+			}{
+				{
+					name:          "default/Pod1",
+					failuresCount: 2,
+				},
+			},
+		},
 	}
 
 	podAnalyzer := PodAnalyzer{}