package e2e import ( "bytes" "context" "fmt" "io" "sort" "github.com/onsi/ginkgo" corev1 "k8s.io/api/core/v1" eventsv1 "k8s.io/api/events/v1" "k8s.io/apimachinery/pkg/labels" "k8s.io/client-go/kubernetes" "sigs.k8s.io/controller-runtime/pkg/client" ) var ( podLogTailLimit int64 = 15 kubernetesEventsLimit int64 = 30 // MUST match the labels in the deployment manifest: deploy/operator.yaml operatorPodLabels = map[string]string{ "name": "jenkins-operator", } ) func getOperatorPod(namespace string) (*corev1.Pod, error) { lo := &client.ListOptions{ LabelSelector: labels.SelectorFromSet(operatorPodLabels), Namespace: namespace, } pods := &corev1.PodList{} err := K8sClient.List(context.TODO(), pods, lo) if err != nil { return nil, err } return &pods.Items[0], nil } func getOperatorLogs(namespace string) (string, error) { pod, err := getOperatorPod(namespace) if err != nil { return "Operator pod doesn't exist", err } logOptions := corev1.PodLogOptions{TailLines: &podLogTailLimit} // creates the clientset clientset, err := kubernetes.NewForConfig(Cfg) if err != nil { return "", err } req := clientset.CoreV1().Pods(pod.Namespace).GetLogs(pod.Name, &logOptions) podLogs, err := req.Stream(context.TODO()) if err != nil { return "", err } defer func() { if podLogs != nil { _ = podLogs.Close() } }() buf := new(bytes.Buffer) _, err = io.Copy(buf, podLogs) if err != nil { return "", err } logs := buf.String() return logs, nil } func printOperatorLogs(namespace string) { _, _ = fmt.Fprintf(ginkgo.GinkgoWriter, "Operator logs in '%s' namespace:\n", namespace) logs, err := getOperatorLogs(namespace) if err != nil { _, _ = fmt.Fprintf(ginkgo.GinkgoWriter, "Couldn't get the operator pod logs: %s", err) } else { _, _ = fmt.Fprintf(ginkgo.GinkgoWriter, "Last %d lines of log from operator:\n %s", podLogTailLimit, logs) } } func getKubernetesEvents(namespace string) ([]eventsv1.Event, error) { listOptions := &client.ListOptions{ Limit: kubernetesEventsLimit, Namespace: namespace, } events := &eventsv1.EventList{} err := K8sClient.List(context.TODO(), events, listOptions) if err != nil { return nil, err } sort.SliceStable(events.Items, func(i, j int) bool { return events.Items[i].CreationTimestamp.Unix() < events.Items[j].CreationTimestamp.Unix() }) return events.Items, nil } func printKubernetesEvents(namespace string) { _, _ = fmt.Fprintf(ginkgo.GinkgoWriter, "Kubernetes events in '%s' namespace:\n", namespace) events, err := getKubernetesEvents(namespace) if err != nil { _, _ = fmt.Fprintf(ginkgo.GinkgoWriter, "Couldn't get kubernetes events: %s", err) } else { _, _ = fmt.Fprintf(ginkgo.GinkgoWriter, "Last %d events from kubernetes:\n", kubernetesEventsLimit) for _, event := range events { _, _ = fmt.Fprintf(ginkgo.GinkgoWriter, "Event CreationTime: %s, Type: %s, Reason: %s, Object: %s %s/%s, Action: %s\n", event.CreationTimestamp, event.Type, event.Reason, event.Regarding.Kind, event.Regarding.Namespace, event.Regarding.Name, event.Note) } } } func printKubernetesPods(namespace string) { _, _ = fmt.Fprintf(ginkgo.GinkgoWriter, "\nAll pods in '%s' namespace:\n", namespace) pod, err := getOperatorPod(namespace) if err == nil { _, _ = fmt.Fprintf(ginkgo.GinkgoWriter, "%s: %+v \n", pod.Name, pod.Status.Conditions) } } func ShowLogsIfTestHasFailed(failed bool, namespace string) { if failed { const defaultNamespace = "default" _, _ = fmt.Fprintf(ginkgo.GinkgoWriter, "Test failed. Below here you can check logs:") printKubernetesEvents(namespace) printKubernetesEvents(defaultNamespace) printKubernetesPods(namespace) printOperatorLogs(namespace) } }