metropolis/test/e2e: add self-test image for networking

We don't have any networking tests in our E2E tests. This adds an image
which de-facto implements one. Or at least, will implement one once we
move to split workers/controllers and contacting a Kubernetes apiserver
from a pod will mean we're actually testing cross-node traffic.

Change-Id: I3d7be3824ac041d72e1c19cd468d30dbcb71fa03
Reviewed-on: https://review.monogon.dev/c/monogon/+/1481
Reviewed-by: Lorenz Brun <lorenz@monogon.tech>
Tested-by: Jenkins CI
diff --git a/metropolis/test/e2e/kubernetes_helpers.go b/metropolis/test/e2e/kubernetes_helpers.go
index dec7363..066c1c2 100644
--- a/metropolis/test/e2e/kubernetes_helpers.go
+++ b/metropolis/test/e2e/kubernetes_helpers.go
@@ -17,11 +17,16 @@
 package e2e
 
 import (
+	"bytes"
+	"context"
 	"crypto/x509"
 	"encoding/pem"
 	"fmt"
+	"io"
+	"strings"
 
 	appsv1 "k8s.io/api/apps/v1"
+	batchv1 "k8s.io/api/batch/v1"
 	corev1 "k8s.io/api/core/v1"
 	"k8s.io/apimachinery/pkg/api/resource"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -91,6 +96,34 @@
 	}
 }
 
+// makeSelftestSpec generates a Job spec for the E2E self-test image.
+func makeSelftestSpec(name string) *batchv1.Job {
+	one := int32(1)
+	return &batchv1.Job{
+		ObjectMeta: metav1.ObjectMeta{Name: name},
+		Spec: batchv1.JobSpec{
+			BackoffLimit: &one,
+			Template: corev1.PodTemplateSpec{
+				ObjectMeta: metav1.ObjectMeta{
+					Labels: map[string]string{
+						"job-name": name,
+					},
+				},
+				Spec: corev1.PodSpec{
+					Containers: []corev1.Container{
+						{
+							Name:            "test",
+							ImagePullPolicy: corev1.PullNever,
+							Image:           "bazel/metropolis/test/e2e/selftest:selftest_image",
+						},
+					},
+					RestartPolicy: corev1.RestartPolicyOnFailure,
+				},
+			},
+		},
+	}
+}
+
 // makeTestStatefulSet generates a StatefulSet spec
 func makeTestStatefulSet(name string, volumeMode corev1.PersistentVolumeMode) *appsv1.StatefulSet {
 	return &appsv1.StatefulSet{
@@ -135,3 +168,22 @@
 		},
 	}
 }
+
+func getPodLogLines(ctx context.Context, cs kubernetes.Interface, podName string, nlines int64) ([]string, error) {
+	logsR := cs.CoreV1().Pods("default").GetLogs(podName, &corev1.PodLogOptions{
+		TailLines: &nlines,
+	})
+	logs, err := logsR.Stream(ctx)
+	if err != nil {
+		return nil, fmt.Errorf("stream failed: %w", err)
+	}
+	var buf bytes.Buffer
+	_, err = io.Copy(&buf, logs)
+	if err != nil {
+		return nil, fmt.Errorf("copy failed: %w", err)
+	}
+	lineStr := strings.Trim(buf.String(), "\n")
+	lines := strings.Split(lineStr, "\n")
+	lines = lines[len(lines)-int(nlines):]
+	return lines, nil
+}