m/test/launch: print qemu options at startup

Change-Id: I35b234301e7c06a910127a4cf2c1573d23af45a9
Reviewed-on: https://review.monogon.dev/c/monogon/+/1077
Tested-by: Leopold Schabel <leo@monogon.tech>
Reviewed-by: Serge Bazanski <serge@monogon.tech>
diff --git a/metropolis/test/ktest/main.go b/metropolis/test/ktest/main.go
index f082671..27cd919 100644
--- a/metropolis/test/ktest/main.go
+++ b/metropolis/test/ktest/main.go
@@ -56,6 +56,7 @@
 	}()
 
 	if err := launch.RunMicroVM(context.Background(), &launch.MicroVMOptions{
+		Name:                        "ktest",
 		KernelPath:                  *kernelPath,
 		InitramfsPath:               *initrdPath,
 		Cmdline:                     *cmdline,
diff --git a/metropolis/test/launch/cli/launch/main.go b/metropolis/test/launch/cli/launch/main.go
index b195ecf..53d6fab 100644
--- a/metropolis/test/launch/cli/launch/main.go
+++ b/metropolis/test/launch/cli/launch/main.go
@@ -49,6 +49,7 @@
 	}
 	ctx := clicontext.WithInterrupt(context.Background())
 	err = cluster.LaunchNode(ctx, ld, sd, &cluster.NodeOptions{
+		Name:       "test-node",
 		Ports:      launch.IdentityPortMap(ports),
 		SerialPort: os.Stdout,
 		NodeParameters: &apb.NodeParameters{
diff --git a/metropolis/test/launch/cluster/cluster.go b/metropolis/test/launch/cluster/cluster.go
index 010d47d..18cab25 100644
--- a/metropolis/test/launch/cluster/cluster.go
+++ b/metropolis/test/launch/cluster/cluster.go
@@ -40,6 +40,9 @@
 
 // NodeOptions contains all options that can be passed to Launch()
 type NodeOptions struct {
+	// Name is a human-readable identifier to be used in debug output.
+	Name string
+
 	// Ports contains the port mapping where to expose the internal ports of the VM to
 	// the host. See IdentityPortMap() and ConflictFreePortMap(). Ignored when
 	// ConnectToSocket is set.
@@ -330,6 +333,8 @@
 	systemCmd.Stderr = &stdErrBuf
 	systemCmd.Stdout = options.SerialPort
 
+	launch.PrettyPrintQemuArgs(options.Name, systemCmd.Args)
+
 	err = systemCmd.Run()
 
 	// Stop TPM emulator and wait for it to exit to properly reap the child process
@@ -638,6 +643,7 @@
 	// had bootstrapped the cluster.
 	nodeOpts := make([]NodeOptions, opts.NumNodes)
 	nodeOpts[0] = NodeOptions{
+		Name:            "node0",
 		ConnectToSocket: vmPorts[0],
 		NodeParameters: &apb.NodeParameters{
 			Cluster: &apb.NodeParameters_ClusterBootstrap_{
@@ -669,6 +675,7 @@
 
 	go func() {
 		if err := launch.RunMicroVM(ctxT, &launch.MicroVMOptions{
+			Name:                   "nanoswitch [99]",
 			KernelPath:             "metropolis/test/ktest/vmlinux",
 			InitramfsPath:          "metropolis/test/nanoswitch/initramfs.cpio.lz4",
 			ExtraNetworkInterfaces: switchPorts,
@@ -750,6 +757,7 @@
 	// Use the retrieved information to configure the rest of the node options.
 	for i := 1; i < opts.NumNodes; i++ {
 		nodeOpts[i] = NodeOptions{
+			Name:            fmt.Sprintf("node%d", i),
 			ConnectToSocket: vmPorts[i],
 			NodeParameters: &apb.NodeParameters{
 				Cluster: &apb.NodeParameters_ClusterRegister_{
diff --git a/metropolis/test/launch/launch.go b/metropolis/test/launch/launch.go
index 8f72434..daf2f4b 100644
--- a/metropolis/test/launch/launch.go
+++ b/metropolis/test/launch/launch.go
@@ -23,6 +23,7 @@
 	"errors"
 	"fmt"
 	"io"
+	"log"
 	"net"
 	"os"
 	"os/exec"
@@ -55,6 +56,20 @@
 	return strings.Join(optionValues, ",")
 }
 
+// PrettyPrintQemuArgs prints the given QEMU arguments to stderr.
+func PrettyPrintQemuArgs(name string, args []string) {
+	var argsFmt string
+	for _, arg := range args {
+		argsFmt += arg
+		if !strings.HasPrefix(arg, "-") {
+			argsFmt += "\n  "
+		} else {
+			argsFmt += " "
+		}
+	}
+	log.Printf("Running %s:\n  %s\n", name, argsFmt)
+}
+
 // PortMap represents where VM ports are mapped to on the host. It maps from the VM
 // port number to the host port number.
 type PortMap map[uint16]uint16
@@ -120,6 +135,9 @@
 
 // MicroVMOptions contains all options to start a MicroVM
 type MicroVMOptions struct {
+	// Name is a human-readable identifier to be used in debug output.
+	Name string
+
 	// Path to the ELF kernel binary
 	KernelPath string
 
@@ -247,6 +265,8 @@
 	cmd.ExtraFiles = append(cmd.ExtraFiles, opts.ExtraChardevs...)
 	cmd.ExtraFiles = append(cmd.ExtraFiles, opts.ExtraNetworkInterfaces...)
 
+	PrettyPrintQemuArgs(opts.Name, cmd.Args)
+
 	err := cmd.Run()
 	// If it's a context error, just quit. There's no way to tell a
 	// killed-due-to-context vs killed-due-to-external-reason error returned by Run,