env/linux-ppc64/osuosl: upgrade linux/ppc64 hardware & OS, use Docker

Collaboration with @tiborvass at Docker who got Docker running on
big-endian PPC64. Go for ppc64 doesn't support cgo or external
linking, so runc doesn't work, but a new OCI-compliant runc
implementation written in C (https://github.com/containers/crun) means
we can run Docker after all. See NOTES & build-*.sh

Then add a Dockerfile & associated cleanup in buildlet & stage0 to use
rundockerbuildlet.

Once done, might help with golang/go#35188, golang/go#32613, etc.

Fixes golang/go#34830
Updates golang/go#21260

Change-Id: I43d7afa1d58bbdfa16e3c57670bc41f1d1932d80
Reviewed-on: https://go-review.googlesource.com/c/build/+/203886
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
diff --git a/cmd/buildlet/buildlet.go b/cmd/buildlet/buildlet.go
index 679a5ca..a9a3c75 100644
--- a/cmd/buildlet/buildlet.go
+++ b/cmd/buildlet/buildlet.go
@@ -14,7 +14,6 @@
 
 import (
 	"archive/tar"
-	"bufio"
 	"bytes"
 	"compress/gzip"
 	"context"
@@ -43,7 +42,6 @@
 
 	"cloud.google.com/go/compute/metadata"
 	"golang.org/x/build/buildlet"
-	"golang.org/x/build/internal/httpdl"
 	"golang.org/x/build/pargzip"
 )
 
@@ -257,45 +255,6 @@
 
 	// Default if not otherwise configured in dashboard/builders.go:
 	os.Setenv("GOROOT_BOOTSTRAP", filepath.Join(*workDir, "go1.4"))
-
-	if runtime.GOOS == "linux" && runtime.GOARCH == "ppc64" {
-		downloadBootstrapGoroot("/usr/local/go-bootstrap", "https://storage.googleapis.com/go-builder-data/gobootstrap-linux-ppc64.tar.gz")
-	}
-}
-
-func downloadBootstrapGoroot(destDir, url string) {
-	tarPath := destDir + ".tar.gz"
-	origInfo, err := os.Stat(tarPath)
-	if err != nil && !os.IsNotExist(err) {
-		log.Fatalf("Checking for tar existence: %v", err)
-	}
-	if err := httpdl.Download(tarPath, url); err != nil {
-		log.Fatalf("Downloading %s to %s: %v", url, tarPath, err)
-	}
-	newInfo, err := os.Stat(tarPath)
-	if err != nil {
-		log.Fatalf("Stat after download: %v", err)
-	}
-	if os.SameFile(origInfo, newInfo) {
-		// The file on disk was unmodified, so we probably untarred it already.
-		return
-	}
-	if err := os.RemoveAll(destDir); err != nil {
-		log.Fatal(err)
-	}
-	if err := os.MkdirAll(destDir, 0755); err != nil {
-		log.Fatal(err)
-	}
-	f, err := os.Open(tarPath)
-	if err != nil {
-		log.Fatalf("Opening after download: %v", err)
-	}
-	defer f.Close()
-	if err := untar(f, destDir); err != nil {
-		os.Remove(tarPath)
-		os.RemoveAll(destDir)
-		log.Fatalf("Untarring %s: %v", url, err)
-	}
 }
 
 func listenForCoordinator() {
@@ -1205,7 +1164,7 @@
 			err = errors.New("not respecting -halt flag on macOS in unknown environment")
 		}
 	default:
-		err = errors.New("No system-specific halt command run; will just end buildlet process.")
+		err = errors.New("no system-specific halt command run; will just end buildlet process")
 	}
 	log.Printf("Shutdown: %v", err)
 	log.Printf("Ending buildlet process post-halt")
@@ -1614,15 +1573,6 @@
 	return pw.w.Write(pw.buf[:n+1])
 }
 
-func requireTrailerSupport() {
-	// Depend on a symbol that was added after HTTP Trailer support was
-	// implemented (4b96409 Dec 29 2014) so that this function will fail
-	// to compile without Trailer support.
-	// bufio.Reader.Discard was added by ee2ecc4 Jan 7 2015.
-	var r bufio.Reader
-	_ = r.Discard
-}
-
 var killProcessTree = killProcessTreeUnix
 
 func killProcessTreeUnix(p *os.Process) error {
@@ -1804,7 +1754,7 @@
 	}
 	if runtime.GOOS == "windows" {
 		if res, err := exec.Command("icacls.exe", authFile, "/grant", `NT SERVICE\sshd:(R)`).CombinedOutput(); err != nil {
-			return fmt.Errorf("setting permissions on authorized_keys with: %v\n%s.", err, res)
+			return fmt.Errorf("setting permissions on authorized_keys with: %v\n%s", err, res)
 		}
 	}
 	return nil
diff --git a/cmd/buildlet/stage0/stage0.go b/cmd/buildlet/stage0/stage0.go
index 90788c0..5030f19 100644
--- a/cmd/buildlet/stage0/stage0.go
+++ b/cmd/buildlet/stage0/stage0.go
@@ -90,8 +90,6 @@
 		default:
 			panic(fmt.Sprintf("unknown/unspecified $GO_BUILDER_ENV value %q", env))
 		}
-	case "linux/ppc64":
-		initOregonStatePPC64()
 	case "darwin/amd64":
 		// The MacStadium builders' baked-in stage0.sh
 		// bootstrap file doesn't set GO_BUILDER_ENV
@@ -169,6 +167,8 @@
 		cmd.Args = append(cmd.Args, reverseHostTypeArgs(buildEnv)...)
 	case "host-linux-ppc64le-osu": // power8
 		cmd.Args = append(cmd.Args, reverseHostTypeArgs(buildEnv)...)
+	case "host-linux-ppc64-osu":
+		cmd.Args = append(cmd.Args, reverseHostTypeArgs(buildEnv)...)
 	}
 	switch osArch {
 	case "linux/s390x":
@@ -189,10 +189,6 @@
 		default:
 			panic(fmt.Sprintf("unknown/unspecified $GO_BUILDER_ENV value %q", env))
 		}
-	case "linux/ppc64":
-		// Assume OSU (osuosl.org) host type for now. If we get more, use
-		// GO_BUILD_HOST_TYPE (see above) and check that.
-		cmd.Args = append(cmd.Args, reverseHostTypeArgs("host-linux-ppc64-osu")...)
 	case "solaris/amd64", "illumos/amd64":
 		hostType := buildEnv
 		cmd.Args = append(cmd.Args, reverseHostTypeArgs(hostType)...)
@@ -409,11 +405,6 @@
 	log.Printf("untarred %s to %s in %v", tgzCache, destDir, time.Since(t1).Round(time.Second/10))
 }
 
-func initOregonStatePPC64() {
-	aptGetInstall("gcc", "strace", "libc6-dev", "gdb")
-	initBootstrapDir("/usr/local/go-bootstrap", "/usr/local/go-bootstrap.tar.gz")
-}
-
 func isUnix() bool {
 	switch runtime.GOOS {
 	case "plan9", "windows":
diff --git a/cmd/coordinator/status.go b/cmd/coordinator/status.go
index 700f703..6181f74 100644
--- a/cmd/coordinator/status.go
+++ b/cmd/coordinator/status.go
@@ -427,7 +427,7 @@
 func newOSUPPC64Checker() *healthChecker {
 	var hosts []string
 	for i := 1; i <= expectedHosts("host-linux-ppc64-osu"); i++ {
-		name := fmt.Sprintf("host-linux-ppc64-osu:go-be-%v", i)
+		name := fmt.Sprintf("host-linux-ppc64-osu:ppc64_%02d", i)
 		hosts = append(hosts, name)
 	}
 	return &healthChecker{
diff --git a/cmd/rundockerbuildlet/rundockerbuildlet.go b/cmd/rundockerbuildlet/rundockerbuildlet.go
index 61fa535..01c8fe9 100644
--- a/cmd/rundockerbuildlet/rundockerbuildlet.go
+++ b/cmd/rundockerbuildlet/rundockerbuildlet.go
@@ -150,11 +150,13 @@
 		}
 		cmd := exec.Command("docker", "run",
 			"-d",
-			"--memory="+*memory,
 			"--name="+name,
 			"-v", filepath.Dir(keyFile)+":/buildkey/",
 			"-e", "HOSTNAME="+name,
 			"--tmpfs=/workdir:rw,exec")
+		if *memory != "" {
+			cmd.Args = append(cmd.Args, "--memory="+*memory)
+		}
 		if *builderEnv != "" {
 			cmd.Args = append(cmd.Args, "-e", "GO_BUILDER_ENV="+*builderEnv)
 		}
diff --git a/env/linux-ppc64/osuosl/Dockerfile b/env/linux-ppc64/osuosl/Dockerfile
new file mode 100644
index 0000000..4dfd6a1
--- /dev/null
+++ b/env/linux-ppc64/osuosl/Dockerfile
@@ -0,0 +1,31 @@
+# Copyright 2019 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+FROM tiborvass/ubuntu:xenial-ppc64 # built locally from build-ubuntu.sh
+
+ENV DEBIAN_FRONTEND noninteractive
+
+RUN apt-get update && \
+    apt-get install --yes \
+          gcc curl strace \
+          ca-certificates netbase \
+          procps lsof psmisc \
+          libc6-dev gdb \
+          openssh-server
+
+RUN mkdir /usr/local/go-bootstrap && \
+    curl --silent https://storage.googleapis.com/go-builder-data/gobootstrap-linux-ppc64.tar.gz | \
+    tar -C /usr/local/go-bootstrap -zxv
+
+ENV GOROOT_BOOTSTRAP /usr/local/go-bootstrap
+RUN curl -o  /usr/local/bin/stage0 https://storage.googleapis.com/go-builder-data/buildlet-stage0.linux-ppc64 && \
+    chmod +x /usr/local/bin/stage0
+
+ENV GO_BUILDER_ENV host-linux-ppc64-osu
+
+ENV GO_BUILD_KEY_DELETE_AFTER_READ true
+ENV GO_BUILD_KEY_PATH /buildkey/gobuildkey
+
+CMD ["/usr/local/bin/stage0"]
+
diff --git a/env/linux-ppc64/osuosl/NOTES b/env/linux-ppc64/osuosl/NOTES
index 30dc089..1683916 100644
--- a/env/linux-ppc64/osuosl/NOTES
+++ b/env/linux-ppc64/osuosl/NOTES
@@ -1,7 +1,5 @@
 The linux-ppc64 buildlets run on PPC64 VMs at osuosl.org (OSU Open Source Lab).
 
-They run Debian jessie.
-
 Filing tickets: https://support.osuosl.org/
     Ticket username: bradfitz@golang.org
     Ticket password: http://go/pw-osuosl-ppc64
@@ -23,44 +21,31 @@
   go-be-4: debian@140.211.168.43
   go-be-5: debian@140.211.168.44
 
-Each was once configured by scping setup.bash to them, logging in to
-each, and running:
+# Installing Docker on the unsupported ppc64 platform
 
-$ sudo ./setup.bash <BUILDKEY_HERE>
+There are 3 main scripts, in chronological order:
+- build-golang.sh
+- build-docker.sh
+- build-ubuntu.sh
 
-TODO: these should be updated like linux-arm and linux-arm64 to use Docker
-      per build. That is https://golang.org/issue/21189
+## Go toolchain
 
-Machine information.
+The build-golang.sh script will create a Go toolchain for ppc64 and is meant to be run on a system for which Go has official releases, such as linux/amd64.
 
-debian@go-be-1:~$ free
-total       used       free     shared    buffers     cached
-Mem:       4176832    2045952    2130880      95616      74752    1638464
--/+ buffers/cache:     332736    3844096
-Swap:            0          0          0
+The resulting tgz archive (and sha256 checksum file) should be sent to the ppc64 machine
 
-debian@go-be-1:~$ cat /proc/cpuinfo
-processor       : 0
-cpu             : POWER8 (architected), altivec supported
-clock           : 3425.000000MHz
-revision        : 2.1 (pvr 004b 0201)
+## Docker
 
-processor       : 1
-cpu             : POWER8 (architected), altivec supported
-clock           : 3425.000000MHz
-revision        : 2.1 (pvr 004b 0201)
+The build-docker.sh script assumes it is running on the target ppc64 machine, after the Go toolchain archive and corresponding checksum file were transferred to the current directory.
+It will install docker and its dependencies to /usr/local/bin/ but will not start docker.
 
-timebase        : 512000000
-platform        : pSeries
-model           : IBM pSeries (emulated by qemu)
-machine         : CHRP IBM pSeries (emulated by qemu)
+## Ubuntu base image
 
-debian@go-be-1:~$ uname -a
-Linux go-be-1 3.16.0-4-powerpc64 #1 SMP Debian 3.16.36-1+deb8u1 (2016-09-03) ppc64 GNU/Linux
+The build-ubuntu.sh script is to show how the tiborvass/ubuntu:xenial-ppc64 base image was built.
+To build images with static binaries only, there is no need for an ubuntu base image.
+Keep in mind, that the ubuntu packages are all 32bit, even though the kernel is 64bit.
 
-debian@go-be-1:~$ lsb_release -a
-No LSB modules are available.
-Distributor ID: Debian
-Description:    Debian GNU/Linux 8.6 (jessie)
-Release:        8.6
-Codename:       jessie
+# Cleanup
+
+The cleanup.sh script by default uninstalls from /usr/local/bin/
+`./cleanup.sh all` will however remove all intermediary files and folders such as extracted archives.
diff --git a/env/linux-ppc64/osuosl/build-docker.sh b/env/linux-ppc64/osuosl/build-docker.sh
new file mode 100755
index 0000000..3af0e76
--- /dev/null
+++ b/env/linux-ppc64/osuosl/build-docker.sh
@@ -0,0 +1,88 @@
+#!/bin/sh -ex
+
+GO_VERSION=1.13.3
+CRUN_VERSION=6254263af0a41d3b78ed280f944acda10199d42a # latest released version doesn't work
+CONTAINERD_VERSION=v1.2.10
+DOCKER_VERSION=v19.03.4
+GOOS=linux
+GOARCH=ppc64
+
+
+# Setting up Go toolchain
+bootstrap=go-${GOOS}-${GOARCH}-bootstrap
+export GOROOT=$(pwd)/${bootstrap}
+export GOPATH=$(pwd)/go
+export PATH=$GOROOT/bin:$PATH
+
+install_go() {
+	if ! which go >/dev/null; then
+		sha256sum -c $bootstrap.tgz.sha256
+		tar xf $bootstrap.tgz
+	else
+		echo "skipping go installation"
+	fi
+	[ "$(go version)" = "go version go${GO_VERSION} ${GOOS}/${GOARCH}" ]
+}
+
+install_crun() {
+	if [ -e /usr/local/bin/runc ]; then
+		echo "skipping runc installation"
+		return
+	fi
+	# crun is a C-only implementation of the OCI runtime spec, compatible with runc
+	git clone https://github.com/containers/crun && cd crun && git checkout "$CRUN_VERSION"
+	sudo apt-get update && sudo apt-get install --no-install-recommends -y make gcc libc6-dev pkgconf libtool go-md2man libtool autoconf python3 automake libcap-dev libseccomp-dev libyajl-dev
+	./autogen.sh && ./configure --prefix=/usr/local && make && sudo make install
+
+	sudo ln -s crun /usr/local/bin/runc    # hacky but will work
+}
+
+install_containerd() {
+	if [ -e /usr/local/bin/containerd ]; then
+		echo "skipping containerd installation"
+		return
+	fi
+	# installs a static build of containerd
+	mkdir -p $GOPATH/src/github.com/containerd
+	git clone --depth 1 -b "$CONTAINERD_VERSION" https://github.com/containerd/containerd $GOPATH/src/github.com/containerd/containerd
+	cd $GOPATH/src/github.com/containerd/containerd
+	patch -p1 < containerd.patch
+	BUILDTAGS='netgo osusergo static_build no_btrfs' make && sudo make install
+}
+
+install_docker() {
+	# installs a static build of docker
+	# unfortunately, need to build manually
+	if [ -e /usr/local/bin/dockerd ]; then
+		echo "skipping dockerd installation"
+	else
+		mkdir -p $GOPATH/src/github.com/docker
+		git clone --depth=1 -b "$DOCKER_VERSION" https://github.com/docker/engine $GOPATH/src/github.com/docker/docker
+		cd $GOPATH/src/github.com/docker/docker
+		VERSION="$DOCKER_VERSION" GITCOMMIT=$(git rev-parse --short HEAD) bash ./hack/make/.go-autogen
+		CGO_ENABLED=0 go build -o dockerd \
+			-tags 'autogen netgo osusergo static_build exclude_graphdriver_devicemapper exclude_disk_quota' \
+			-installsuffix netgo  \
+			github.com/docker/docker/cmd/dockerd
+		sudo mv dockerd /usr/local/bin/dockerd
+	fi
+	if [ -e /usr/local/bin/docker ]; then
+		echo "skipping dockerd installation"
+		return
+	fi
+	git clone --depth=1 -b "$DOCKER_VERSION" https://github.com/docker/cli $GOPATH/src/github.com/docker/cli
+	cd $GOPATH/src/github.com/docker/cli
+	VERSION="$DOCKER_VERSION" GITCOMMIT=$(git rev-parse --short HEAD) ./scripts/build/binary
+	sudo cp build/docker-${GOOS}-${GOARCH} /usr/local/bin/docker
+}
+
+install_go
+install_crun
+install_containerd
+install_docker
+
+sudo install docker.service /etc/systemd/user/docker.service
+sudo systemctl enable /etc/systemd/user/docker.service || true
+sudo systemctl restart docker
+
+sudo docker version
diff --git a/env/linux-ppc64/osuosl/build-golang.sh b/env/linux-ppc64/osuosl/build-golang.sh
new file mode 100755
index 0000000..3ed8e55
--- /dev/null
+++ b/env/linux-ppc64/osuosl/build-golang.sh
@@ -0,0 +1,17 @@
+#!/bin/sh -ex
+
+GO_VERSION=1.13.3
+
+echo "Meant to be run on a system on which Go has official releases and is installed"
+GOHOSTARCH=$(go env GOHOSTARCH)
+GOHOSTOS=$(go env GOHOSTOS)
+export GOOS=linux
+export GOARCH=ppc64
+targz=go${GO_VERSION}.${GOHOSTOS}-${GOHOSTARCH}.tar.gz
+wget https://dl.google.com/go/${targz}
+tar xf ${targz}
+( cd go/src; ./bootstrap.bash )
+bootstrap=go-$GOOS-$GOARCH-bootstrap
+rm -f ${bootstrap}.tbz # does not contain all that's needed
+tar czf ${bootstrap}.tgz ${bootstrap}
+sha256sum $bootstrap.tgz | tee $bootstrap.tgz.sha256
diff --git a/env/linux-ppc64/osuosl/build-ubuntu.sh b/env/linux-ppc64/osuosl/build-ubuntu.sh
new file mode 100755
index 0000000..da5fe2a
--- /dev/null
+++ b/env/linux-ppc64/osuosl/build-ubuntu.sh
@@ -0,0 +1,25 @@
+#!/bin/sh -ex
+
+export rootfs=$(pwd)/ubuntu_xenial_1604
+if [ ! -e "$rootfs" ]; then
+	(
+		sudo -E sh -c 'debootstrap --variant=minbase --keyring=/usr/share/keyrings/ubuntu-archive-keyring.gpg --include ubuntu-keyring xenial $rootfs'
+		cd "$rootfs"
+		sudo rm -rf var/log/{dpkg,bootstrap,alternatives}.log var/cache/ldconfig/aux-cache var/cache/apt/* var/lib/apt/lists/* dev/* proc/* sys/*
+	)
+else
+	echo "skipping debootstrap"
+fi
+
+cat > Dockerfile.xenial <<'EOF'
+FROM scratch
+COPY ./ubuntu_xenial_1604/ /
+CMD ["/bin/bash"]
+EOF
+
+# always build with buildkit :)
+export DOCKER_BUILDKIT=1
+sudo -E docker build -f Dockerfile.xenial -t tiborvass/ubuntu:xenial-ppc64 .
+#sudo docker login
+#sudo docker push tiborvass/ubuntu:xenial-ppc64
+sudo docker run -it --rm tiborvass/ubuntu:xenial-ppc64 cat /etc/os-release
diff --git a/env/linux-ppc64/osuosl/clean.sh b/env/linux-ppc64/osuosl/clean.sh
new file mode 100755
index 0000000..9a3715d
--- /dev/null
+++ b/env/linux-ppc64/osuosl/clean.sh
@@ -0,0 +1,18 @@
+#!/bin/sh
+
+[ $(id -u) -ne 0 ] && echo need root && exit 1
+
+set -x
+
+pwd
+cat $0
+echo
+read -p "Press enter to continue" r
+
+rm -f /usr/local/bin/crun
+# being extra careful
+[ -L /usr/local/bin/runc ] && [ "$(readlink /usr/local/bin/runc)" = "crun" ] && rm -f /usr/local/bin/runc
+file /usr/local/bin/containerd | grep -q static && rm -f /usr/local/bin/containerd{,-shim,-shim-runc-v1,-shim-runc-v2,-stress} /usr/local/bin/ctr
+file /usr/local/bin/dockerd | grep -q static && rm -f /usr/local/bin/dockerd /usr/local/bin/docker
+
+[ "$1" = all ] && rm -rf Dockerfile.xenial crun go-linux-ppc64-bootstrap go ubuntu_xenial_1604
diff --git a/env/linux-ppc64/osuosl/containerd.patch b/env/linux-ppc64/osuosl/containerd.patch
new file mode 100644
index 0000000..735851d
--- /dev/null
+++ b/env/linux-ppc64/osuosl/containerd.patch
@@ -0,0 +1,15 @@
+diff --git a/Makefile.linux b/Makefile.linux
+index 2de23a1..8500cc2 100644
+--- a/Makefile.linux
++++ b/Makefile.linux
+@@ -18,8 +18,10 @@ COMMANDS += containerd-shim containerd-shim-runc-v1
+ 
+ # check GOOS for cross compile builds
+ ifeq ($(GOOS),linux)
++ifneq ($(GOARCH),ppc64)
+ 	GO_GCFLAGS += -buildmode=pie
+ endif
++endif
+ 
+ # amd64 supports go test -race
+ ifeq ($(GOARCH),amd64)
diff --git a/env/linux-ppc64/osuosl/docker.service b/env/linux-ppc64/osuosl/docker.service
new file mode 100644
index 0000000..2d9091f
--- /dev/null
+++ b/env/linux-ppc64/osuosl/docker.service
@@ -0,0 +1,11 @@
+[Unit]
+Description=Docker ppc64
+After=network.target
+
+[Service]
+ExecStart=/usr/local/bin/dockerd
+Restart=always
+RestartSec=2
+
+[Install]
+WantedBy=multi-user.target
diff --git a/env/linux-ppc64/osuosl/rundockerbuildlet.service b/env/linux-ppc64/osuosl/rundockerbuildlet.service
new file mode 100644
index 0000000..ecbb712
--- /dev/null
+++ b/env/linux-ppc64/osuosl/rundockerbuildlet.service
@@ -0,0 +1,16 @@
+[Unit]
+Description=Run Buildlets in Docker
+After=network.target
+
+[Install]
+WantedBy=network-online.target
+
+[Service]
+Type=simple
+# The (-n * -cpu) values must currently be <= number of host cores.
+# The host has 10 cores, so the -n=5 (five containers) * -cpu=2 (two CPUs per container) == 10.
+# TODO: add -memory=3.9g once the docker/crun issues are fixed to support memory limits.
+ExecStart=/usr/local/bin/rundockerbuildlet -basename=ppc64_ -image=golang/builder -n=5 -cpu=2 -memory= --env=host-linux-ppc64-osu
+Restart=always
+RestartSec=2
+StartLimitInterval=0
diff --git a/env/linux-ppc64/osuosl/setup.bash b/env/linux-ppc64/osuosl/setup.bash
deleted file mode 100644
index 7b1cb33..0000000
--- a/env/linux-ppc64/osuosl/setup.bash
+++ /dev/null
@@ -1,36 +0,0 @@
-#!/bin/bash
-
-set -e
-
-KEY=$1
-if [ "$KEY" = "" ]; then
-        echo "usage: ./setup.bash <BUILDKEY>" >&2
-        exit 2
-fi
-
-echo $KEY > /root/.gobuildkey
-
-apt-get update
-apt-get upgrade
-apt-get install strace libc6-dev gcc
-
-cd /etc/systemd/system
-cat >buildlet.service <<EOF
-[Unit]
-Description=Go builder buildlet
-After=network.target
-
-[Install]
-WantedBy=network-online.target
-
-[Service]
-Type=simple
-ExecStartPre=/bin/sh -c 'cd /usr/local/bin; /usr/bin/curl -R -f -z buildlet-stage0 -o buildlet-stage0 https://storage.googleapis.com/go-builder-data/buildlet-stage0.linux-ppc64 && chmod +x buildlet-stage0'
-ExecStart=/usr/local/bin/buildlet-stage0
-Restart=always
-RestartSec=2
-StartLimitInterval=0
-EOF
-
-systemctl enable buildlet.service
-systemctl start buildlet.service
diff --git a/go.mod b/go.mod
index fefbd84..384c64d 100644
--- a/go.mod
+++ b/go.mod
@@ -20,7 +20,7 @@
 	github.com/kr/pty v1.1.3
 	github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07
 	go4.org v0.0.0-20180809161055-417644f6feb5
-	golang.org/x/crypto v0.0.0-20190424203555-c05e17bb3b2d
+	golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529
 	golang.org/x/net v0.0.0-20190502183928-7f726cade0ab
 	golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a
 	golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852
diff --git a/go.sum b/go.sum
index fad34c4..c4d113e 100644
--- a/go.sum
+++ b/go.sum
@@ -30,10 +30,6 @@
 github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
 github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ=
 github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
-github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY=
-github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
-github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg=
-github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
 github.com/google/go-cmp v0.3.2-0.20191028172631-481baca67f93 h1:VvBteXw2zOXEgm0o3PgONTWf+bhUGsCaiNn3pbkU9LA=
 github.com/google/go-cmp v0.3.2-0.20191028172631-481baca67f93/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
 github.com/google/go-github v17.0.0+incompatible h1:N0LgJ1j65A7kfXrZnUDaYCs/Sf4rEjNlfyDHW9dolSY=
@@ -65,8 +61,8 @@
 go4.org v0.0.0-20180809161055-417644f6feb5 h1:+hE86LblG4AyDgwMCLTE6FOlM9+qjHSYS+rKqxUVdsM=
 go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
-golang.org/x/crypto v0.0.0-20190424203555-c05e17bb3b2d h1:adrbvkTDn9rGnXg2IJDKozEpXXLZN89pdIA+Syt4/u0=
-golang.org/x/crypto v0.0.0-20190424203555-c05e17bb3b2d/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529 h1:iMGN4xG0cnqj3t+zOM8wUB0BiPKHEwSxEZCvzcbZuvk=
+golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/exp v0.0.0-20190121172915-509febef88a4 h1:c2HOrn5iMezYjSlGPncknSEr/8x5LELb/ilJbXi9DEA=
 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=