m/node/kubernetes: fix PV mount flags and add e2e test

Mount flags did not work because of two problems:
- The provisioner did not copy them from the StorageClass to the
  PersistentVolume.
- The CSI server used = instead of |= when adding flags, so only one of
  the flags was added or removed.

There was an existing e2e test for PVs, however this only created the
PVC/PV without even attaching it to a container. I extended this test to
attach the PV and check from inside the container that it has the
expected mount flags and quota.

The existing e2e test also created a block PV, however attaching a block
PV to a container was not tested and is apparently broken, so I removed
this test for now.

Change-Id: Ie14adfafd333eab38d2b5f1b4ce8a2aa8795eae0
Reviewed-on: https://review.monogon.dev/c/monogon/+/3613
Reviewed-by: Lorenz Brun <lorenz@monogon.tech>
Tested-by: Jenkins CI
diff --git a/metropolis/test/e2e/suites/kubernetes/kubernetes_helpers.go b/metropolis/test/e2e/suites/kubernetes/kubernetes_helpers.go
index 60d611b..85f8909 100644
--- a/metropolis/test/e2e/suites/kubernetes/kubernetes_helpers.go
+++ b/metropolis/test/e2e/suites/kubernetes/kubernetes_helpers.go
@@ -30,6 +30,7 @@
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/util/intstr"
 	"k8s.io/client-go/kubernetes"
+	"k8s.io/utils/ptr"
 )
 
 // makeTestDeploymentSpec generates a Deployment spec for a single pod running
@@ -155,7 +156,7 @@
 }
 
 // makeTestStatefulSet generates a StatefulSet spec
-func makeTestStatefulSet(name string, volumeMode corev1.PersistentVolumeMode) *appsv1.StatefulSet {
+func makeTestStatefulSet(name string) *appsv1.StatefulSet {
 	return &appsv1.StatefulSet{
 		ObjectMeta: metav1.ObjectMeta{Name: name},
 		Spec: appsv1.StatefulSetSpec{
@@ -164,13 +165,34 @@
 			}},
 			VolumeClaimTemplates: []corev1.PersistentVolumeClaim{
 				{
-					ObjectMeta: metav1.ObjectMeta{Name: "www"},
+					ObjectMeta: metav1.ObjectMeta{Name: "vol-default"},
 					Spec: corev1.PersistentVolumeClaimSpec{
 						AccessModes: []corev1.PersistentVolumeAccessMode{corev1.ReadWriteOnce},
 						Resources: corev1.VolumeResourceRequirements{
-							Requests: map[corev1.ResourceName]resource.Quantity{corev1.ResourceStorage: resource.MustParse("50Mi")},
+							Requests: map[corev1.ResourceName]resource.Quantity{corev1.ResourceStorage: resource.MustParse("1Mi")},
 						},
-						VolumeMode: &volumeMode,
+						VolumeMode: ptr.To(corev1.PersistentVolumeFilesystem),
+					},
+				},
+				{
+					ObjectMeta: metav1.ObjectMeta{Name: "vol-local-strict"},
+					Spec: corev1.PersistentVolumeClaimSpec{
+						AccessModes: []corev1.PersistentVolumeAccessMode{corev1.ReadWriteOnce},
+						Resources: corev1.VolumeResourceRequirements{
+							Requests: map[corev1.ResourceName]resource.Quantity{corev1.ResourceStorage: resource.MustParse("5Mi")},
+						},
+						StorageClassName: ptr.To("local-strict"),
+						VolumeMode:       ptr.To(corev1.PersistentVolumeFilesystem),
+					},
+				},
+				{
+					ObjectMeta: metav1.ObjectMeta{Name: "vol-readonly"},
+					Spec: corev1.PersistentVolumeClaimSpec{
+						AccessModes: []corev1.PersistentVolumeAccessMode{corev1.ReadWriteOnce},
+						Resources: corev1.VolumeResourceRequirements{
+							Requests: map[corev1.ResourceName]resource.Quantity{corev1.ResourceStorage: resource.MustParse("1Mi")},
+						},
+						VolumeMode: ptr.To(corev1.PersistentVolumeFilesystem),
 					},
 				},
 			},
@@ -184,11 +206,21 @@
 					Containers: []corev1.Container{
 						{
 							Name:            "test",
-							ImagePullPolicy: corev1.PullNever,
-							Image:           "bazel/metropolis/test/e2e/preseedtest:preseedtest_image",
-							ReadinessProbe: &corev1.Probe{
-								ProbeHandler: corev1.ProbeHandler{
-									HTTPGet: &corev1.HTTPGetAction{Port: intstr.FromInt(80)},
+							ImagePullPolicy: corev1.PullIfNotPresent,
+							Image:           "test.monogon.internal/metropolis/test/e2e/persistentvolume/persistentvolume_image",
+							VolumeMounts: []corev1.VolumeMount{
+								corev1.VolumeMount{
+									Name:      "vol-default",
+									MountPath: "/vol/default",
+								},
+								corev1.VolumeMount{
+									Name:      "vol-local-strict",
+									MountPath: "/vol/local-strict",
+								},
+								corev1.VolumeMount{
+									Name:      "vol-readonly",
+									ReadOnly:  true,
+									MountPath: "/vol/readonly",
 								},
 							},
 						},
@@ -214,6 +246,8 @@
 	}
 	lineStr := strings.Trim(buf.String(), "\n")
 	lines := strings.Split(lineStr, "\n")
-	lines = lines[len(lines)-int(nlines):]
+	if len(lines) > int(nlines) {
+		lines = lines[len(lines)-int(nlines):]
+	}
 	return lines, nil
 }