Add VM infrastructure smoke test

This adds an E2E test which exercises the VM infrastructure (Kubernetes, KVM device plugin and QEMU).
This test should ensure that nobody breaks the core infrastructure Metropolis VMs rely on.

Test Plan: This is a test

X-Origin-Diff: phab/D740
GitOrigin-RevId: ddf629725dfb664ace5a50efee9ed9442962d6f7
diff --git a/metropolis/test/e2e/main_test.go b/metropolis/test/e2e/main_test.go
index 3e4ffb0..46e5c72 100644
--- a/metropolis/test/e2e/main_test.go
+++ b/metropolis/test/e2e/main_test.go
@@ -32,6 +32,7 @@
 
 	"google.golang.org/grpc"
 	corev1 "k8s.io/api/core/v1"
+	"k8s.io/apimachinery/pkg/api/resource"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	podv1 "k8s.io/kubernetes/pkg/api/v1/pod"
 
@@ -242,6 +243,46 @@
 					return fmt.Errorf("pod is not ready: %v", events.Items[len(events.Items)-1].Message)
 				}
 			})
+			if os.Getenv("HAVE_NESTED_KVM") != "" {
+				testEventual(t, "Pod for KVM/QEMU smoke test", ctx, smallTestTimeout, func(ctx context.Context) error {
+					runcRuntimeClass := "runc"
+					_, err := clientSet.CoreV1().Pods("default").Create(ctx, &corev1.Pod{
+						ObjectMeta: metav1.ObjectMeta{
+							Name: "vm-smoketest",
+						},
+						Spec: corev1.PodSpec{
+							Containers: []corev1.Container{{
+								Name:            "vm-smoketest",
+								ImagePullPolicy: corev1.PullNever,
+								Image:           "bazel/metropolis/vm/smoketest:smoketest_container",
+								Resources: corev1.ResourceRequirements{
+									Limits: corev1.ResourceList{
+										"devices.monogon.dev/kvm": *resource.NewQuantity(1, ""),
+									},
+								},
+							}},
+							RuntimeClassName: &runcRuntimeClass,
+							RestartPolicy:    corev1.RestartPolicyNever,
+						},
+					}, metav1.CreateOptions{})
+					return err
+				})
+				testEventual(t, "KVM/QEMU smoke test completion", ctx, smallTestTimeout, func(ctx context.Context) error {
+					pod, err := clientSet.CoreV1().Pods("default").Get(ctx, "vm-smoketest", metav1.GetOptions{})
+					if err != nil {
+						return fmt.Errorf("failed to get pod: %w", err)
+					}
+					if pod.Status.Phase == corev1.PodSucceeded {
+						return nil
+					}
+					events, err := clientSet.CoreV1().Events("default").List(ctx, metav1.ListOptions{FieldSelector: fmt.Sprintf("involvedObject.name=%s,involvedObject.namespace=default", pod.Name)})
+					if err != nil || len(events.Items) == 0 {
+						return fmt.Errorf("pod is not ready: %v", pod.Status.Phase)
+					} else {
+						return fmt.Errorf("pod is not ready: %v", events.Items[len(events.Items)-1].Message)
+					}
+				})
+			}
 		})
 	})