m/test: implement non-transient QEMU VMs

This patch reworks the launch code, enabling rebooting of cluster
member VMs, while precluding erasure of their transient state (disk
image, OVMF firmware variables, TPM state, MAC address).

RebootNode method included in this patch is cluster-aware in the sense
that it blocks until the node has re-joined the cluster.

Change-Id: Ie1236297d214399e927a67295200f8b8879a5b39
Reviewed-on: https://review.monogon.dev/c/monogon/+/664
Reviewed-by: Sergiusz Bazanski <serge@monogon.tech>
diff --git a/metropolis/test/e2e/main_test.go b/metropolis/test/e2e/main_test.go
index 51dbe4b..c0af1fd 100644
--- a/metropolis/test/e2e/main_test.go
+++ b/metropolis/test/e2e/main_test.go
@@ -142,6 +142,13 @@
 				}
 				return nil
 			})
+			testEventual(t, "Node rejoin successful", ctx, 60*time.Second, func(ctx context.Context) error {
+				// Ensure nodes rejoin the cluster after a reboot by reboting the 1st node.
+				if err := cluster.RebootNode(ctx, 1); err != nil {
+					return fmt.Errorf("while rebooting a node: %w", err)
+				}
+				return nil
+			})
 		})
 		t.Run("Kubernetes", func(t *testing.T) {
 			t.Parallel()