cloud/agent: migrate to bringup package

Change-Id: Ibe89c37cae058395723c9ed5ad5914d62a9af891
Reviewed-on: https://review.monogon.dev/c/monogon/+/3392
Tested-by: Jenkins CI
Reviewed-by: Lorenz Brun <lorenz@monogon.tech>
diff --git a/cloud/agent/BUILD.bazel b/cloud/agent/BUILD.bazel
index 2574ad4..db3ee51 100644
--- a/cloud/agent/BUILD.bazel
+++ b/cloud/agent/BUILD.bazel
@@ -6,7 +6,6 @@
         "agent.go",
         "hwreport.go",
         "install.go",
-        "main.go",
     ],
     embedsrcs = [
         "//metropolis/node/core/abloader",  #keep
@@ -19,7 +18,7 @@
         "//metropolis/node/core/devmgr",
         "//metropolis/node/core/network",
         "//osbase/blockdev",
-        "//osbase/bootparam",
+        "//osbase/bringup",
         "//osbase/build/mkimage/osimage",
         "//osbase/efivarfs",
         "//osbase/logtree",
diff --git a/cloud/agent/agent.go b/cloud/agent/agent.go
index 4430424..e0bfd81 100644
--- a/cloud/agent/agent.go
+++ b/cloud/agent/agent.go
@@ -20,12 +20,18 @@
 
 	apb "source.monogon.dev/cloud/agent/api"
 	bpb "source.monogon.dev/cloud/bmaas/server/api"
+
 	"source.monogon.dev/metropolis/node/core/devmgr"
 	"source.monogon.dev/metropolis/node/core/network"
+	"source.monogon.dev/osbase/bringup"
 	"source.monogon.dev/osbase/pki"
 	"source.monogon.dev/osbase/supervisor"
 )
 
+func main() {
+	bringup.Runnable(agentRunnable).Run()
+}
+
 // This is similar to rpc.NewEphemeralCredentials, but that only deals with
 // Metropolis-style certificate verification.
 func newEphemeralCert(private ed25519.PrivateKey) (*tls.Certificate, error) {
@@ -51,11 +57,6 @@
 // Main runnable for the agent.
 func agentRunnable(ctx context.Context) error {
 	l := supervisor.Logger(ctx)
-	// Mount this late so we don't just crash when not booted with EFI.
-	isEFIBoot := false
-	if err := mkdirAndMount("/sys/firmware/efi/efivars", "efivarfs", unix.MS_NOEXEC|unix.MS_NOSUID|unix.MS_NODEV); err == nil {
-		isEFIBoot = true
-	}
 	agentInitRaw, err := os.ReadFile("/init.pb")
 	if err != nil {
 		return fmt.Errorf("unable to read spec file from takeover: %w", err)
@@ -166,7 +167,7 @@
 			installationReport = &bpb.OSInstallationReport{
 				Generation: res.InstallationRequest.Generation,
 			}
-			if err := install(res.InstallationRequest, agentInit.NetworkConfig, l, isEFIBoot); err != nil {
+			if err := install(res.InstallationRequest, agentInit.NetworkConfig, l); err != nil {
 				l.Errorf("Installation failed: %v", err)
 				installationReport.Result = &bpb.OSInstallationReport_Error_{
 					Error: &bpb.OSInstallationReport_Error{
diff --git a/cloud/agent/install.go b/cloud/agent/install.go
index 7752517..29641bd 100644
--- a/cloud/agent/install.go
+++ b/cloud/agent/install.go
@@ -8,6 +8,7 @@
 	"fmt"
 	"io/fs"
 	"net/http"
+	"os"
 	"path/filepath"
 
 	"github.com/cenkalti/backoff/v4"
@@ -41,17 +42,18 @@
 
 // install dispatches OSInstallationRequests to the appropriate installer
 // method
-func install(req *bpb.OSInstallationRequest, netConfig *npb.Net, l logtree.LeveledLogger, isEFIBoot bool) error {
+func install(req *bpb.OSInstallationRequest, netConfig *npb.Net, l logtree.LeveledLogger) error {
 	switch reqT := req.Type.(type) {
 	case *bpb.OSInstallationRequest_Metropolis:
-		return installMetropolis(reqT.Metropolis, netConfig, l, isEFIBoot)
+		return installMetropolis(reqT.Metropolis, netConfig, l)
 	default:
 		return errors.New("unknown installation request type")
 	}
 }
 
-func installMetropolis(req *bpb.MetropolisInstallationRequest, netConfig *npb.Net, l logtree.LeveledLogger, isEFIBoot bool) error {
-	if !isEFIBoot {
+func installMetropolis(req *bpb.MetropolisInstallationRequest, netConfig *npb.Net, l logtree.LeveledLogger) error {
+	// Validate we are running via EFI.
+	if _, err := os.Stat("/sys/firmware/efi"); os.IsNotExist(err) {
 		//nolint:ST1005
 		return errors.New("Monogon OS can only be installed on EFI-booted machines, this one is not")
 	}
diff --git a/cloud/agent/main.go b/cloud/agent/main.go
deleted file mode 100644
index 511e688..0000000
--- a/cloud/agent/main.go
+++ /dev/null
@@ -1,89 +0,0 @@
-package main
-
-import (
-	"context"
-	"fmt"
-	"os"
-	"regexp"
-
-	"golang.org/x/sys/unix"
-
-	"source.monogon.dev/osbase/bootparam"
-	"source.monogon.dev/osbase/logtree"
-	"source.monogon.dev/osbase/supervisor"
-)
-
-var validTTYRegexp = regexp.MustCompile(`^[a-zA-Z0-9]+$`)
-
-func main() {
-	setupMounts()
-
-	// Set up logger for the Agent. Parse consoles from the kernel command line
-	// as well as adding the two standard tty0/ttyS0 consoles.
-	consoles := make(map[string]bool)
-	cmdline, err := os.ReadFile("/proc/cmdline")
-	if err == nil {
-		params, _, err := bootparam.Unmarshal(string(cmdline))
-		if err == nil {
-			consoles = params.Consoles()
-		}
-	}
-	consoles["tty0"] = true
-	consoles["ttyS0"] = true
-
-	lt := logtree.New()
-	for path := range consoles {
-		f, err := os.OpenFile("/dev/"+path, os.O_WRONLY, 0)
-		if err != nil {
-			continue
-		}
-		reader, err := lt.Read("", logtree.WithChildren(), logtree.WithStream())
-		if err != nil {
-			panic(fmt.Sprintf("could not set up root log reader: %v", err))
-		}
-		go func() {
-			for {
-				p := <-reader.Stream
-				fmt.Fprintf(f, "%s\n", p.String())
-			}
-		}()
-	}
-
-	sCtx := context.Background()
-	supervisor.New(sCtx, agentRunnable, supervisor.WithExistingLogtree(lt))
-	select {}
-}
-
-func mkdirAndMount(dir, fs string, flags uintptr) error {
-	if err := os.MkdirAll(dir, 0o755); err != nil {
-		return fmt.Errorf("could not make %s: %w", dir, err)
-	}
-	if err := unix.Mount(fs, dir, fs, flags, ""); err != nil {
-		return fmt.Errorf("could not mount %s on %s: %w", fs, dir, err)
-	}
-	return nil
-}
-
-// setupMounts sets up basic mounts like sysfs, procfs, devtmpfs and cgroups.
-// This should be called early during init as a lot of processes depend on this
-// being available.
-func setupMounts() error {
-	// Set up target filesystems.
-	for _, el := range []struct {
-		dir   string
-		fs    string
-		flags uintptr
-	}{
-		{"/sys", "sysfs", unix.MS_NOEXEC | unix.MS_NOSUID | unix.MS_NODEV},
-		{"/sys/kernel/tracing", "tracefs", unix.MS_NOEXEC | unix.MS_NOSUID | unix.MS_NODEV},
-		{"/sys/fs/pstore", "pstore", unix.MS_NOEXEC | unix.MS_NOSUID | unix.MS_NODEV},
-		{"/proc", "proc", unix.MS_NOEXEC | unix.MS_NOSUID | unix.MS_NODEV},
-		{"/dev", "devtmpfs", unix.MS_NOEXEC | unix.MS_NOSUID},
-		{"/dev/pts", "devpts", unix.MS_NOEXEC | unix.MS_NOSUID},
-	} {
-		if err := mkdirAndMount(el.dir, el.fs, el.flags); err != nil {
-			return err
-		}
-	}
-	return nil
-}