Skip to content

Commit e100e7c

Browse files
sgalsalehdivolgin
andauthored
get container logs for unhealthy pods (#469)
* get container logs for unhealthy pods Co-authored-by: divolgin <[email protected]> Co-authored-by: divolgin <[email protected]>
1 parent 1cb0dab commit e100e7c

File tree

4 files changed

+71
-18
lines changed

4 files changed

+71
-18
lines changed

pkg/analyze/cluster_pod_statuses.go

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,6 @@ func clusterPodStatuses(analyzer *troubleshootv1beta2.ClusterPodStatuses, getChi
4242
allResults := []*AnalyzeResult{}
4343

4444
for _, pod := range pods {
45-
podResults := []*AnalyzeResult{}
46-
4745
if pod.Status.Reason == "" {
4846
pod.Status.Reason = k8sutil.GetPodStatusReason(&pod)
4947
}
@@ -78,12 +76,23 @@ func clusterPodStatuses(analyzer *troubleshootv1beta2.ClusterPodStatuses, getChi
7876
continue
7977
}
8078

79+
operator := parts[0]
80+
reason := parts[1]
8181
match := false
82-
switch parts[0] {
82+
83+
switch operator {
8384
case "=", "==", "===":
84-
match = parts[1] == string(pod.Status.Phase) || parts[1] == string(pod.Status.Reason)
85+
if reason == "Healthy" {
86+
match = !k8sutil.IsPodUnhealthy(&pod)
87+
} else {
88+
match = reason == string(pod.Status.Phase) || reason == string(pod.Status.Reason)
89+
}
8590
case "!=", "!==":
86-
match = parts[1] != string(pod.Status.Phase) && parts[1] != string(pod.Status.Reason)
91+
if reason == "Healthy" {
92+
match = k8sutil.IsPodUnhealthy(&pod)
93+
} else {
94+
match = reason != string(pod.Status.Phase) && reason != string(pod.Status.Reason)
95+
}
8796
}
8897

8998
if !match {
@@ -132,10 +141,9 @@ func clusterPodStatuses(analyzer *troubleshootv1beta2.ClusterPodStatuses, getChi
132141
}
133142
r.Message = m.String()
134143

135-
podResults = append(podResults, &r)
144+
allResults = append(allResults, &r)
145+
break
136146
}
137-
138-
allResults = append(allResults, podResults...)
139147
}
140148

141149
return allResults, nil

pkg/collect/cluster_resources.go

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"strings"
1212

1313
troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
14+
"github.com/replicatedhq/troubleshoot/pkg/k8sutil"
1415
"gopkg.in/yaml.v2"
1516
authorizationv1 "k8s.io/api/authorization/v1"
1617
corev1 "k8s.io/api/core/v1"
@@ -67,16 +68,19 @@ func ClusterResources(c *Collector, clusterResourcesCollector *troubleshootv1bet
6768
}
6869

6970
// pods
70-
pods, podErrors, failedPods := pods(ctx, client, namespaceNames)
71+
pods, podErrors, unhealthyPods := pods(ctx, client, namespaceNames)
7172
for k, v := range pods {
7273
output.SaveResult(c.BundlePath, path.Join("cluster-resources/pods", k), bytes.NewBuffer(v))
7374
}
7475
output.SaveResult(c.BundlePath, "cluster-resources/pods-errors.json", marshalErrors(podErrors))
7576

76-
for _, pod := range failedPods {
77+
for _, pod := range unhealthyPods {
7778
allContainers := append(pod.Spec.InitContainers, pod.Spec.Containers...)
7879
for _, container := range allContainers {
79-
logsRoot := path.Join(c.BundlePath, "cluster-resources", "pods", pod.Namespace, "logs")
80+
logsRoot := ""
81+
if c.BundlePath != "" {
82+
logsRoot = path.Join(c.BundlePath, "cluster-resources", "pods", "logs", pod.Namespace)
83+
}
8084
limits := &troubleshootv1beta2.LogLimits{
8185
MaxLines: 500,
8286
}
@@ -86,7 +90,7 @@ func ClusterResources(c *Collector, clusterResourcesCollector *troubleshootv1bet
8690
output.SaveResult(c.BundlePath, errPath, bytes.NewBuffer([]byte(err.Error())))
8791
}
8892
for k, v := range podLogs {
89-
output[filepath.Join("cluster-resources", "pods", pod.Namespace, "logs", k)] = v
93+
output[filepath.Join("cluster-resources", "pods", "logs", pod.Namespace, k)] = v
9094
}
9195
}
9296
}
@@ -263,7 +267,7 @@ func getNamespace(ctx context.Context, client *kubernetes.Clientset, namespace s
263267
func pods(ctx context.Context, client *kubernetes.Clientset, namespaces []string) (map[string][]byte, map[string]string, []corev1.Pod) {
264268
podsByNamespace := make(map[string][]byte)
265269
errorsByNamespace := make(map[string]string)
266-
failedPods := []corev1.Pod{}
270+
unhealthyPods := []corev1.Pod{}
267271

268272
for _, namespace := range namespaces {
269273
pods, err := client.CoreV1().Pods(namespace).List(ctx, metav1.ListOptions{})
@@ -279,15 +283,15 @@ func pods(ctx context.Context, client *kubernetes.Clientset, namespaces []string
279283
}
280284

281285
for _, pod := range pods.Items {
282-
if pod.Status.Phase == corev1.PodFailed {
283-
failedPods = append(failedPods, pod)
286+
if k8sutil.IsPodUnhealthy(&pod) {
287+
unhealthyPods = append(unhealthyPods, pod)
284288
}
285289
}
286290

287291
podsByNamespace[namespace+".json"] = b
288292
}
289293

290-
return podsByNamespace, errorsByNamespace, failedPods
294+
return podsByNamespace, errorsByNamespace, unhealthyPods
291295
}
292296

293297
func services(ctx context.Context, client *kubernetes.Clientset, namespaces []string) (map[string][]byte, map[string]string) {

pkg/collect/result.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -131,8 +131,13 @@ func (r CollectorResult) CloseWriter(bundlePath string, relativePath string, wri
131131
return errors.Wrap(c.Close(), "failed to close writer")
132132
}
133133

134-
if b, ok := writer.(*bytes.Buffer); ok {
135-
r[relativePath] = b.Bytes()
134+
if buff, ok := writer.(*bytes.Buffer); ok {
135+
b := buff.Bytes()
136+
if b == nil {
137+
// nil means data is on disk, so make it an empty array
138+
b = []byte{}
139+
}
140+
r[relativePath] = b
136141
return nil
137142
}
138143

pkg/k8sutil/pod.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,25 @@ import (
66
corev1 "k8s.io/api/core/v1"
77
)
88

9+
type PodStatusReason string
10+
11+
const (
12+
PodStatusReasonRunning PodStatusReason = "Running"
13+
PodStatusReasonError PodStatusReason = "Error"
14+
PodStatusReasonNotReady PodStatusReason = "NotReady"
15+
PodStatusReasonUnknown PodStatusReason = "Unknown"
16+
PodStatusReasonShutdown PodStatusReason = "Shutdown"
17+
PodStatusReasonTerminating PodStatusReason = "Terminating"
18+
PodStatusReasonCrashLoopBackOff PodStatusReason = "CrashLoopBackOff"
19+
PodStatusReasonImagePullBackOff PodStatusReason = "ImagePullBackOff"
20+
PodStatusReasonContainerCreating PodStatusReason = "ContainerCreating"
21+
PodStatusReasonPending PodStatusReason = "Pending"
22+
PodStatusReasonCompleted PodStatusReason = "Completed"
23+
PodStatusReasonEvicted PodStatusReason = "Evicted"
24+
PodStatusReasonInitError PodStatusReason = "Init:Error"
25+
PodStatusReasonInitCrashLoopBackOff PodStatusReason = "Init:CrashLoopBackOff"
26+
)
27+
928
// reference: https://github.com/kubernetes/kubernetes/blob/e8fcd0de98d50f4019561a6b7a0287f5c059267a/pkg/printers/internalversion/printers.go#L741
1029
func GetPodStatusReason(pod *corev1.Pod) string {
1130
reason := string(pod.Status.Phase)
@@ -88,3 +107,20 @@ func hasPodReadyCondition(conditions []corev1.PodCondition) bool {
88107
}
89108
return false
90109
}
110+
111+
func IsPodUnhealthy(pod *corev1.Pod) bool {
112+
if pod.Status.Phase == corev1.PodFailed || pod.Status.Phase == corev1.PodPending || pod.Status.Phase == corev1.PodUnknown {
113+
return true
114+
}
115+
116+
reason := GetPodStatusReason(pod)
117+
118+
switch PodStatusReason(reason) {
119+
case PodStatusReasonRunning:
120+
fallthrough
121+
case PodStatusReasonCompleted:
122+
return false
123+
}
124+
125+
return true
126+
}

0 commit comments

Comments
 (0)