diff --git a/config/crds/troubleshoot.replicated.com_collectors.yaml b/config/crds/troubleshoot.replicated.com_collectors.yaml index 92b445cb9..baf8e13ac 100644 --- a/config/crds/troubleshoot.replicated.com_collectors.yaml +++ b/config/crds/troubleshoot.replicated.com_collectors.yaml @@ -427,6 +427,8 @@ spec: type: array image: type: string + imagePullPolicy: + type: string name: type: string namespace: diff --git a/config/crds/troubleshoot.replicated.com_preflights.yaml b/config/crds/troubleshoot.replicated.com_preflights.yaml index d3f82a8ba..5b830291f 100644 --- a/config/crds/troubleshoot.replicated.com_preflights.yaml +++ b/config/crds/troubleshoot.replicated.com_preflights.yaml @@ -649,6 +649,8 @@ spec: type: array image: type: string + imagePullPolicy: + type: string name: type: string namespace: diff --git a/config/samples/troubleshoot_v1beta1_collector.yaml b/config/samples/troubleshoot_v1beta1_collector.yaml index a189b0e7a..49b1f9bdf 100644 --- a/config/samples/troubleshoot_v1beta1_collector.yaml +++ b/config/samples/troubleshoot_v1beta1_collector.yaml @@ -19,7 +19,7 @@ spec: - run: name: ping-google namespace: default - image: ubuntu:latest + image: flungo/netutils command: ["ping"] args: ["www.google.com"] - timeout: 5s + # timeout: 5s diff --git a/pkg/apis/troubleshoot/v1beta1/collector_shared.go b/pkg/apis/troubleshoot/v1beta1/collector_shared.go index 7951b2304..73655818e 100644 --- a/pkg/apis/troubleshoot/v1beta1/collector_shared.go +++ b/pkg/apis/troubleshoot/v1beta1/collector_shared.go @@ -25,12 +25,13 @@ type Logs struct { } type Run struct { - Name string `json:"name" yaml:"name"` - Namespace string `json:"namespace" yaml:"namespace"` - Image string `json:"image" yaml:"image"` - Command []string `json:"command,omitempty" yaml:"command,omitempty"` - Args []string `json:"args,omitempty" yaml:"args,omitempty"` - Timeout string `json:"timeout,omitempty" yaml:"timeout,omitempty"` + Name string `json:"name" yaml:"name"` + Namespace string `json:"namespace" yaml:"namespace"` + Image string `json:"image" yaml:"image"` + Command []string `json:"command,omitempty" yaml:"command,omitempty"` + Args []string `json:"args,omitempty" yaml:"args,omitempty"` + Timeout string `json:"timeout,omitempty" yaml:"timeout,omitempty"` + ImagePullPolicy string `json:"imagePullPolicy,omitempty" yaml:"imagePullPolicy,omitempty"` } type Collect struct { diff --git a/pkg/collect/run.go b/pkg/collect/run.go index ae8390b54..d7b4a6bff 100644 --- a/pkg/collect/run.go +++ b/pkg/collect/run.go @@ -1,18 +1,15 @@ package collect import ( - // "bytes" - // "encoding/json" - // "fmt" - // "io" - // "strings" - // "time" + "encoding/json" + "fmt" + "time" troubleshootv1beta1 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta1" - // corev1 "k8s.io/api/core/v1" - // metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - // "k8s.io/client-go/kubernetes" - // "sigs.k8s.io/controller-runtime/pkg/client/config" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes" + "sigs.k8s.io/controller-runtime/pkg/client/config" ) type RunOutput struct { @@ -20,41 +17,126 @@ type RunOutput struct { } func Run(runCollector *troubleshootv1beta1.Run, redact bool) error { - // cfg, err := config.GetConfig() - // if err != nil { - // return err - // } - - // client, err := kubernetes.NewForConfig(cfg) - // if err != nil { - // return err - // } - - // pods, err := listPodsInSelectors(client, logsCollector.Namespace, logsCollector.Selector) - // if err != nil { - // return err - // } - - // logsOutput := LogsOutput{ - // PodLogs: make(map[string][]byte), - // } - // for _, pod := range pods { - // podLogs, err := getPodLogs(client, pod, logsCollector.Limits) - // if err != nil { - // return err - // } - - // for k, v := range podLogs { - // logsOutput.PodLogs[k] = v - // } - // } - - // b, err := json.MarshalIndent(logsOutput, "", " ") - // if err != nil { - // return err - // } - - // fmt.Printf("%s\n", b) + cfg, err := config.GetConfig() + if err != nil { + return err + } + + client, err := kubernetes.NewForConfig(cfg) + if err != nil { + return err + } + + pod, err := runPod(client, runCollector) + if err != nil { + return err + } + + runOutput := &RunOutput{ + PodLogs: make(map[string][]byte), + } + + now := time.Now() + then := now.Add(time.Duration(20 * time.Second)) + + if runCollector.Timeout != "" { + parsedDuration, err := time.ParseDuration(runCollector.Timeout) + if err != nil { + fmt.Printf("unable to parse time duration %s\n", runCollector.Timeout) + } else { + then = now.Add(parsedDuration) + } + } + + for { + if time.Now().After(then) { + break + } + + time.Sleep(time.Second) + } + + limits := troubleshootv1beta1.LogLimits{ + MaxLines: 10000, + } + podLogs, err := getPodLogs(client, *pod, &limits) + if err != nil { + return err + } + + for k, v := range podLogs { + runOutput.PodLogs[k] = v + } + + if err := client.CoreV1().Pods(pod.Namespace).Delete(pod.Name, &metav1.DeleteOptions{}); err != nil { + return err + } + + if redact { + runOutput, err = runOutput.Redact() + if err != nil { + return err + } + } + + b, err := json.MarshalIndent(runOutput, "", " ") + if err != nil { + return err + } + + fmt.Printf("%s\n", b) return nil } + +func runPod(client *kubernetes.Clientset, runCollector *troubleshootv1beta1.Run) (*corev1.Pod, error) { + podLabels := make(map[string]string) + podLabels["troubleshoot-role"] = "run-collector" + + pullPolicy := corev1.PullIfNotPresent + if runCollector.ImagePullPolicy != "" { + pullPolicy = corev1.PullPolicy(runCollector.ImagePullPolicy) + } + + pod := corev1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Name: runCollector.Name, + Namespace: runCollector.Namespace, + Labels: podLabels, + }, + TypeMeta: metav1.TypeMeta{ + APIVersion: "v1", + Kind: "Pod", + }, + Spec: corev1.PodSpec{ + RestartPolicy: corev1.RestartPolicyNever, + Containers: []corev1.Container{ + { + Image: runCollector.Image, + ImagePullPolicy: pullPolicy, + Name: "collector", + Command: runCollector.Command, + Args: runCollector.Args, + }, + }, + }, + } + + created, err := client.CoreV1().Pods(runCollector.Namespace).Create(&pod) + if err != nil { + return nil, err + } + + return created, nil +} + +func (r *RunOutput) Redact() (*RunOutput, error) { + podLogs, err := redactMap(r.PodLogs) + if err != nil { + return nil, err + } + + return &RunOutput{ + PodLogs: podLogs, + }, nil +}