From 3ea71c1d5a0805ea5198c4b057e846b1bf3d9392 Mon Sep 17 00:00:00 2001 From: divolgin Date: Thu, 24 Oct 2019 18:27:53 +0000 Subject: [PATCH] support multiple containers in pod logs --- cmd/troubleshoot/cli/run_nocrd.go | 38 +++++++++------ .../troubleshoot/v1beta1/collector_shared.go | 1 + .../v1beta1/zz_generated.deepcopy.go | 5 ++ pkg/collect/logs.go | 48 ++++++++++++++----- pkg/collect/run.go | 2 +- 5 files changed, 65 insertions(+), 29 deletions(-) diff --git a/cmd/troubleshoot/cli/run_nocrd.go b/cmd/troubleshoot/cli/run_nocrd.go index 4748ab95..4f4e5d55 100644 --- a/cmd/troubleshoot/cli/run_nocrd.go +++ b/cmd/troubleshoot/cli/run_nocrd.go @@ -179,18 +179,21 @@ func runCollectors(v *viper.Viper, collector troubleshootv1beta1.Collector, prog continue } - collectorDir, err := parseAndSaveCollectorOutput(string(result), bundlePath) + newCollectorDirs, err := parseAndSaveCollectorOutput(string(result), bundlePath) if err != nil { progressChan <- fmt.Errorf("failed to parse collector spec %q: %v", collector.GetDisplayName(), err) continue } - if collectorDir == "" { + if len(newCollectorDirs) == 0 { continue } - progressChan <- collectorDir - collectorDirs = append(collectorDirs, collectorDir) + // TODO: better progress.... + for _, d := range newCollectorDirs { + progressChan <- d + } + collectorDirs = append(collectorDirs, newCollectorDirs...) } tarGz := archiver.TarGz{ @@ -219,53 +222,58 @@ func runCollectors(v *viper.Viper, collector troubleshootv1beta1.Collector, prog return filename, nil } -func parseAndSaveCollectorOutput(output string, bundlePath string) (string, error) { - dir := "" +func parseAndSaveCollectorOutput(output string, bundlePath string) ([]string, error) { + rootDirs := make(map[string]bool) input := make(map[string]interface{}) if err := json.Unmarshal([]byte(output), &input); err != nil { - return "", errors.Wrap(err, "unmarshal output") + return nil, errors.Wrap(err, "unmarshal output") } for filename, maybeContents := range input { fileDir, fileName := filepath.Split(filename) outPath := filepath.Join(bundlePath, fileDir) - dir = outPath + rootDirs[outPath] = true if err := os.MkdirAll(outPath, 0777); err != nil { - return "", errors.Wrap(err, "create output file") + return nil, errors.Wrap(err, "create output file") } switch maybeContents.(type) { case string: decoded, err := base64.StdEncoding.DecodeString(maybeContents.(string)) if err != nil { - return "", errors.Wrap(err, "decode collector output") + return nil, errors.Wrap(err, "decode collector output") } if err := writeFile(filepath.Join(outPath, fileName), decoded); err != nil { - return "", errors.Wrap(err, "write collector output") + return nil, errors.Wrap(err, "write collector output") } case map[string]interface{}: for k, v := range maybeContents.(map[string]interface{}) { s, _ := filepath.Split(filepath.Join(outPath, fileName, k)) if err := os.MkdirAll(s, 0777); err != nil { - return "", errors.Wrap(err, "write output directories") + return nil, errors.Wrap(err, "write output directories") } decoded, err := base64.StdEncoding.DecodeString(v.(string)) if err != nil { - return "", errors.Wrap(err, "decode output") + return nil, errors.Wrap(err, "decode output") } if err := writeFile(filepath.Join(outPath, fileName, k), decoded); err != nil { - return "", errors.Wrap(err, "write output") + return nil, errors.Wrap(err, "write output") } } } } - return dir, nil + dirs := make([]string, 0) + for dir := range rootDirs { + dirs = append(dirs, dir) + } + + return dirs, nil } func uploadSupportBundle(r *troubleshootv1beta1.ResultRequest, archivePath string) error { diff --git a/pkg/apis/troubleshoot/v1beta1/collector_shared.go b/pkg/apis/troubleshoot/v1beta1/collector_shared.go index d0a8dc5f..1feea1d3 100644 --- a/pkg/apis/troubleshoot/v1beta1/collector_shared.go +++ b/pkg/apis/troubleshoot/v1beta1/collector_shared.go @@ -27,6 +27,7 @@ type Logs struct { CollectorMeta `json:",inline" yaml:",inline"` Selector []string `json:"selector" yaml:"selector"` Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"` + Containers []string `json:"containers,omitempty" yaml:"containers,omitempty"` Limits *LogLimits `json:"limits,omitempty" yaml:"omitempty"` } diff --git a/pkg/apis/troubleshoot/v1beta1/zz_generated.deepcopy.go b/pkg/apis/troubleshoot/v1beta1/zz_generated.deepcopy.go index 67e7c0ac..32aff21d 100644 --- a/pkg/apis/troubleshoot/v1beta1/zz_generated.deepcopy.go +++ b/pkg/apis/troubleshoot/v1beta1/zz_generated.deepcopy.go @@ -882,6 +882,11 @@ func (in *Logs) DeepCopyInto(out *Logs) { *out = make([]string, len(*in)) copy(*out, *in) } + if in.Containers != nil { + in, out := &in.Containers, &out.Containers + *out = make([]string, len(*in)) + copy(*out, *in) + } if in.Limits != nil { in, out := &in.Limits, &out.Limits *out = new(LogLimits) diff --git a/pkg/collect/logs.go b/pkg/collect/logs.go index 3a66b8ff..ed4cd2c2 100644 --- a/pkg/collect/logs.go +++ b/pkg/collect/logs.go @@ -42,18 +42,34 @@ func Logs(ctx *Context, logsCollector *troubleshootv1beta1.Logs) ([]byte, error) if len(pods) > 0 { for _, pod := range pods { - podLogs, err := getPodLogs(client, pod, logsCollector.Limits, false) - if err != nil { - key := fmt.Sprintf("%s/%s-errors.json", pod.Namespace, pod.Name) - logsOutput.Errors[key], err = marshalNonNil([]string{err.Error()}) + if len(logsCollector.Containers) == 0 { + podLogs, err := getPodLogs(client, pod, "", logsCollector.Limits, false) if err != nil { - return nil, err + key := fmt.Sprintf("%s/%s-errors.json", pod.Namespace, pod.Name) + logsOutput.Errors[key], err = marshalNonNil([]string{err.Error()}) + if err != nil { + return nil, err + } + continue + } + for k, v := range podLogs { + logsOutput.PodLogs[k] = v + } + } else { + for _, container := range logsCollector.Containers { + containerLogs, err := getPodLogs(client, pod, container, logsCollector.Limits, false) + if err != nil { + key := fmt.Sprintf("%s/%s/%s-errors.json", pod.Namespace, pod.Name, container) + logsOutput.Errors[key], err = marshalNonNil([]string{err.Error()}) + if err != nil { + return nil, err + } + continue + } + for k, v := range containerLogs { + logsOutput.PodLogs[k] = v + } } - continue - } - - for k, v := range podLogs { - logsOutput.PodLogs[k] = v } } @@ -88,9 +104,10 @@ func listPodsInSelectors(client *kubernetes.Clientset, namespace string, selecto return pods.Items, nil } -func getPodLogs(client *kubernetes.Clientset, pod corev1.Pod, limits *troubleshootv1beta1.LogLimits, follow bool) (map[string][]byte, error) { +func getPodLogs(client *kubernetes.Clientset, pod corev1.Pod, container string, limits *troubleshootv1beta1.LogLimits, follow bool) (map[string][]byte, error) { podLogOpts := corev1.PodLogOptions{ - Follow: follow, + Follow: follow, + Container: container, } defaultMaxLines := int64(10000) @@ -126,8 +143,13 @@ func getPodLogs(client *kubernetes.Clientset, pod corev1.Pod, limits *troublesho return nil, err } + fileKey := fmt.Sprintf("%s/%s.txt", pod.Namespace, pod.Name) + if container != "" { + fileKey = fmt.Sprintf("%s/%s/%s.txt", pod.Namespace, pod.Name, container) + } + return map[string][]byte{ - fmt.Sprintf("%s/%s.txt", pod.Namespace, pod.Name): buf.Bytes(), + fileKey: buf.Bytes(), }, nil } diff --git a/pkg/collect/run.go b/pkg/collect/run.go index 58ab7d8e..7063aeb0 100644 --- a/pkg/collect/run.go +++ b/pkg/collect/run.go @@ -89,7 +89,7 @@ func runWithoutTimeout(ctx *Context, pod *corev1.Pod, runCollector *troubleshoot limits := troubleshootv1beta1.LogLimits{ MaxLines: 10000, } - podLogs, err := getPodLogs(client, *pod, &limits, true) + podLogs, err := getPodLogs(client, *pod, "", &limits, true) for k, v := range podLogs { runOutput.PodLogs[k] = v