cmd/buildlet: use a high ssh port on Linux when running under COS

When running in GCE's Container-Optimized OS (COS), we can't use
port 22, as the system's sshd is already using it. Our container
runs in the system network namespace, not isolated as is typical
in Docker or Kubernetes. So use port 2200 instead.

Remove an unnecessary type conversion.

Updates golang/go#26969.

Change-Id: Ic85e1f14529175106b9c7397186d3e9b5cb39c1c
Reviewed-on: https://go-review.googlesource.com/129356
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
diff --git a/cmd/buildlet/buildlet.go b/cmd/buildlet/buildlet.go
index 42921f0..296af9e 100644
--- a/cmd/buildlet/buildlet.go
+++ b/cmd/buildlet/buildlet.go
@@ -1334,10 +1334,10 @@
 		}
 	}
 
-	sshConn, err := net.Dial("tcp", "localhost:22")
+	sshConn, err := net.Dial("tcp", "localhost:"+sshPort())
 	if err != nil {
 		sshServerOnce.Do(startSSHServer)
-		sshConn, err = net.Dial("tcp", "localhost:22")
+		sshConn, err = net.Dial("tcp", "localhost:"+sshPort())
 		if err != nil {
 			http.Error(w, err.Error(), http.StatusBadGateway)
 			return
@@ -1370,8 +1370,23 @@
 	<-errc
 }
 
+// sshPort returns the port to use for the local SSH server.
+func sshPort() string {
+	// runningInCOS is whether we're running under GCE's Container-Optimized OS (COS).
+	const runningInCOS = runtime.GOOS == "linux" && runtime.GOARCH == "amd64"
+
+	if runningInCOS {
+		// If running in COS, we can't use port 22, as the system's sshd is already using it.
+		// Our container runs in the system network namespace, not isolated as is typical
+		// in Docker or Kubernetes. So use another high port. See https://golang.org/issue/26969.
+		return "2200"
+	}
+	return "22"
+}
+
 var sshServerOnce sync.Once
 
+// startSSHServer starts an SSH server.
 func startSSHServer() {
 	if inLinuxContainer() {
 		startSSHServerLinux()
@@ -1406,6 +1421,7 @@
 	return err == nil && fi.Mode().IsRegular()
 }
 
+// startSSHServerLinux starts an SSH server on a Linux system.
 func startSSHServerLinux() {
 	log.Printf("start ssh server for linux")
 
@@ -1431,7 +1447,7 @@
 		}
 	}
 
-	cmd := exec.Command("/usr/sbin/sshd", "-D")
+	cmd := exec.Command("/usr/sbin/sshd", "-D", "-p", sshPort())
 	err := cmd.Start()
 	if err != nil {
 		log.Printf("starting sshd: %v", err)
@@ -1452,10 +1468,11 @@
 	waitLocalSSH()
 }
 
+// waitLocalSSH waits for sshd to start accepting connections.
 func waitLocalSSH() {
 	for i := 0; i < 40; i++ {
 		time.Sleep(10 * time.Millisecond * time.Duration(i+1))
-		c, err := net.Dial("tcp", "localhost:22")
+		c, err := net.Dial("tcp", "localhost:"+sshPort())
 		if err == nil {
 			c.Close()
 			log.Printf("sshd connected.")
diff --git a/cmd/buildlet/reverse.go b/cmd/buildlet/reverse.go
index a217d20..7d1bee6 100644
--- a/cmd/buildlet/reverse.go
+++ b/cmd/buildlet/reverse.go
@@ -32,7 +32,7 @@
 // mode is either a BuildConfig or HostConfig name (map key in x/build/dashboard/builders.go)
 func keyForMode(mode string) (string, error) {
 	if isDevReverseMode() {
-		return string(devBuilderKey(mode)), nil
+		return devBuilderKey(mode), nil
 	}
 	if os.Getenv("GO_BUILDER_ENV") == "macstadium_vm" {
 		infoKey := "guestinfo.key-" + mode