cmd/buildlet: add healthz endpoint

This adds a healthz endpoint to buildlets. For reverse buildlets, it
also listens for healthz requests on a private port for a monitoring
process.

For golang/go#47018

Change-Id: I100a8939c5752664afb80472e567ab05a80649d7
Reviewed-on: https://go-review.googlesource.com/c/build/+/334373
Trust: Alexander Rakoczy <alex@golang.org>
Run-TryBot: Alexander Rakoczy <alex@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Heschi Kreinick <heschi@google.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org>
diff --git a/cmd/buildlet/buildlet.go b/cmd/buildlet/buildlet.go
index aa991f2..910ff6c 100644
--- a/cmd/buildlet/buildlet.go
+++ b/cmd/buildlet/buildlet.go
@@ -57,6 +57,7 @@
 	reverseType  = flag.String("reverse-type", "", "if non-empty, go into reverse mode where the buildlet dials the coordinator instead of listening for connections. The value is the dashboard/builders.go Hosts map key, naming a HostConfig. This buildlet will receive work for any BuildConfig specifying this named HostConfig.")
 	coordinator  = flag.String("coordinator", "localhost:8119", "address of coordinator, in production use farmer.golang.org. Only used in reverse mode.")
 	hostname     = flag.String("hostname", "", "hostname to advertise to coordinator for reverse mode; default is actual hostname")
+	healthAddr   = flag.String("health-addr", "localhost:8080", "For reverse buildlets, address to listen for /healthz requests separately from the reverse dialer to the coordinator.")
 )
 
 // Bump this whenever something notable happens, or when another
@@ -242,10 +243,16 @@
 	http.Handle("/status", requireAuth(handleStatus))
 	http.Handle("/ls", requireAuth(handleLs))
 	http.Handle("/connect-ssh", requireAuth(handleConnectSSH))
+	http.HandleFunc("/healthz", handleHealthz)
 
 	if !isReverse {
 		listenForCoordinator()
 	} else {
+		go func() {
+			if err := serveReverseHealth(); err != nil {
+				log.Printf("Error in serveReverseHealth: %v", err)
+			}
+		}()
 		if err := dialCoordinator(); err != nil {
 			log.Fatalf("Error dialing coordinator: %v", err)
 		}
@@ -2003,3 +2010,19 @@
 		log.Printf("failed to run %s: %v, %s", cmd.Args, err, out)
 	}
 }
+
+// handleHealthz always returns 200 OK.
+func handleHealthz(w http.ResponseWriter, _ *http.Request) {
+	w.Write([]byte("ok"))
+}
+
+// serveReverseHealth serves /healthz requests on healthAddr for
+// reverse buildlets.
+//
+// This can be used to monitor the health of guest buildlets, such as
+// the Windows ARM64 qemu guest buildlet.
+func serveReverseHealth() error {
+	m := &http.ServeMux{}
+	m.HandleFunc("/healthz", handleHealthz)
+	return http.ListenAndServe(*healthAddr, m)
+}