m/n/installer: wait for ESP block device to show up

In real-world hardware disks do not always show up before the kernel
launches the init process. Wait up to 30s for the ESP to show up before
aborting because of that.

Change-Id: I3f7972e699a06d6f9d0333fe0ae3355ae3ce9c73
Reviewed-on: https://review.monogon.dev/c/monogon/+/513
Reviewed-by: Mateusz Zalega <mateusz@monogon.tech>
diff --git a/metropolis/installer/main.go b/metropolis/installer/main.go
index e3a4896..4e6d6e0 100644
--- a/metropolis/installer/main.go
+++ b/metropolis/installer/main.go
@@ -21,12 +21,14 @@
 
 import (
 	"archive/zip"
+	"errors"
 	"fmt"
 	"io"
 	"os"
 	"path/filepath"
 	"strings"
 	"syscall"
+	"time"
 
 	"golang.org/x/sys/unix"
 
@@ -203,12 +205,22 @@
 	if err != nil {
 		panicf("While reading the installer ESP UUID: %v", err)
 	}
-	// Look up the installer partition based on espUuid.
-	espDev, err := sysfs.DeviceByPartUUID(espUuid)
-	espPath := filepath.Join("/dev", espDev)
-	if err != nil {
-		panicf("While resolving the installer device handle: %v", err)
+	// Wait for up to 30 tries @ 1s (30s) for the ESP to show up
+	var espDev string
+	var retries = 30
+	for {
+		// Look up the installer partition based on espUuid.
+		espDev, err = sysfs.DeviceByPartUUID(espUuid)
+		if err == nil {
+			break
+		} else if errors.Is(err, sysfs.ErrDevNotFound) && retries > 0 {
+			time.Sleep(1 * time.Second)
+			retries--
+		} else {
+			panicf("While resolving the installer device handle: %v", err)
+		}
 	}
+	espPath := filepath.Join("/dev", espDev)
 	// Mount the installer partition. The installer bundle will be read from it.
 	if err := mountInstallerESP(espPath); err != nil {
 		panicf("While mounting the installer ESP: %v", err)