playground: run in golang VPC network

Also:
* remove an outdated TODO.
* pre-pull untrusted environment docker image on start-up to avoid
  stderr spam (and latency) later
* update an ssh key for debugging (project-wide SSH keys are being ignored
  for some reason)
* add a healthchecking TODO

Updates golang/go#25224

Change-Id: I5a7e0c0f3d8f08c210783ecf4c1999586d13f576
Reviewed-on: https://go-review.googlesource.com/c/playground/+/214178
Reviewed-by: Alexander Rakoczy <alex@golang.org>
diff --git a/app.yaml b/app.yaml
index c6791f8..967b168 100644
--- a/app.yaml
+++ b/app.yaml
@@ -2,6 +2,9 @@
 runtime: custom
 env: flex
 
+network:
+  name: projects/golang-org/global/networks/golang
+
 resources:
   cpu: 2
   memory_gb: 2
@@ -14,4 +17,4 @@
   check_interval_sec: 10
 
 env_variables:
-  MEMCACHED_ADDR: 'memcached:11211'
+  MEMCACHED_ADDR: 'memcached-play-golang:11211'
diff --git a/sandbox/sandbox.go b/sandbox/sandbox.go
index 542e721..204fee4 100644
--- a/sandbox/sandbox.go
+++ b/sandbox/sandbox.go
@@ -38,6 +38,7 @@
 	mode       = flag.String("mode", "server", "Whether to run in \"server\" mode or \"contained\" mode. The contained mode is used internally by the server mode.")
 	dev        = flag.Bool("dev", false, "run in dev mode (show help messages)")
 	numWorkers = flag.Int("workers", runtime.NumCPU(), "number of parallel gvisor containers to pre-spin up & let run concurrently")
+	container  = flag.String("untrusted-container", "gcr.io/golang-org/playground-sandbox-gvisor:latest", "container image name that hosts the untrusted binary under gvisor")
 )
 
 const (
@@ -112,10 +113,11 @@
 	}
 	if *dev {
 		log.Printf("Running in dev mode; container published to host at: http://localhost:8080/")
-		// TODO: XXXX FIXME: this is no longer the protocol since the addition of the processMeta JSON header,
-		// so write a client program to do this instead?
 		log.Printf("Run a binary with: curl -v --data-binary @/home/bradfitz/hello http://localhost:8080/run\n")
 	} else {
+		if out, err := exec.Command("docker", "pull", *container).CombinedOutput(); err != nil {
+			log.Fatalf("error pulling %s: %v, %s", *container, err, out)
+		}
 		log.Printf("Listening on %s", *listenAddr)
 	}
 
@@ -135,6 +137,8 @@
 
 func healthHandler(w http.ResponseWriter, r *http.Request) {
 	io.WriteString(w, "OK\n")
+	// TODO: more? split into liveness & readiness checks? check
+	// number of active/stuck containers, memory?
 }
 
 func rootHandler(w http.ResponseWriter, r *http.Request) {
@@ -290,7 +294,7 @@
 		"--network=none",
 		"--memory="+fmt.Sprint(memoryLimitBytes),
 
-		"gcr.io/golang-org/playground-sandbox-gvisor:latest",
+		*container,
 		"--mode=contained")
 	stdin, err = cmd.StdinPipe()
 	if err != nil {
diff --git a/sandbox/sandbox.tf b/sandbox/sandbox.tf
index 61029c1..b13adef 100644
--- a/sandbox/sandbox.tf
+++ b/sandbox/sandbox.tf
@@ -37,7 +37,7 @@
   name         = "play-sandbox-tmpl"
   machine_type = "n1-standard-1"
   metadata = {
-    "ssh-keys"                  = "bradfitz:ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCtL4Di+zypBIRmvohzfC4mOzETaz/DtzANPKir/mUE1QiC8HuL8BDpIu3rZZY1gAnQf3IZMpgQYgx90TZskgWfi7xLN2mDh2iBZB0KUDlpNpwn1SzSUTQU10XV5mOLm1B7L+w3QXA1wz7kMjmztxZNli/tvZI5BtAX6c58c4Rn0pjQTPeEVPMMvEj6zPUy4QInWTgtrbTj3On/e95F3ZmUjEKFfjeFxVPh7fF6mSygzcxEyGYxTbMdUod/dNbZD/7HY5eTNQPSvjp+GaoodbFEdYWnk9vtoX/2VWYo0J/+w6oHprDzj7dPzKeJeCjpnKra7DyCS/RxIIPt5Giwdj2F bradfitz@bradfitz-glinux-desktop.sea.corp.google.com"
+    "ssh-keys"                  = "bradfitz:ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDaRpEbckQ+harGnrKUjk3JziwYqvz2bRNn0ngpzROaeCwm1XetDby/fgmQruZE/OBpbeOaCOd/yyP89Oer9CJx41AFEfHbudePZti/y+fmZ05N+QoBSAG0JtYWVydIjAjCenKBbNrYmwcQ840uNdIv9Ztqu3lbO/syMgcajappzdqMlwVZuHTJUe1JQD355PiinFHPTa7l0MrZPfiSsBdiTGmO39iVa312yshu6dZAvDgRL+bgIzTL6udPL/cVq+zlkvoZbzC4ajuZs4w2in+kqXHQSxbKHlXOhPrej1fwhspm+0Y7hEZOaN5Juc5GseNCHImtJh1rei1Qa4U/nTjt bradfitz@bradfitz-dev"
     "gce-container-declaration" = data.local_file.konlet.content
     "user-data"                 = data.local_file.cloud_init.content
   }