all: dockerize scaleway builders

Fixes golang/go#20397

Change-Id: I353e879e61aeef56f0c228bbd37cc1eea2ce8b4e
Reviewed-on: https://go-review.googlesource.com/43612
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
diff --git a/cmd/buildlet/stage0/stage0.go b/cmd/buildlet/stage0/stage0.go
index afd6934..a5f02b7 100644
--- a/cmd/buildlet/stage0/stage0.go
+++ b/cmd/buildlet/stage0/stage0.go
@@ -11,19 +11,14 @@
 package main
 
 import (
-	"bytes"
-	"encoding/json"
 	"flag"
 	"fmt"
-	"io/ioutil"
 	"log"
 	"net"
-	"net/http"
 	"os"
 	"os/exec"
 	"path/filepath"
 	"runtime"
-	"strings"
 	"time"
 
 	"cloud.google.com/go/compute/metadata"
@@ -40,11 +35,6 @@
 
 const attr = "buildlet-binary-url"
 
-var (
-	onScaleway   bool
-	scalewayMeta scalewayMetadata
-)
-
 // untar helper, for the Windows image prep script.
 var (
 	untarFile    = flag.String("untar-file", "", "if non-empty, tar.gz to untar to --untar-dest-dir")
@@ -61,12 +51,11 @@
 
 	switch osArch {
 	case "linux/arm":
-		if os.Getenv("GO_BUILDER_ENV") == "linux-arm-arm5spacemonkey" {
+		switch env := os.Getenv("GO_BUILDER_ENV"); env {
+		case "linux-arm-arm5spacemonkey", "host-linux-arm-scaleway":
 			// No setup currently.
-		} else {
-			if _, err := os.Stat("/usr/local/bin/oc-metadata"); err == nil {
-				initScaleway()
-			}
+		default:
+			panic(fmt.Sprintf("unknown/unspecified $GO_BUILDER_ENV value %q", env))
 		}
 	case "linux/arm64":
 		switch env := os.Getenv("GO_BUILDER_ENV"); env {
@@ -112,11 +101,17 @@
 	cmd.Stdout = os.Stdout
 	cmd.Stderr = os.Stderr
 	cmd.Env = env
-	if onScaleway {
-		cmd.Args = append(cmd.Args, scalewayBuildletArgs()...)
-	}
-	if os.Getenv("GO_BUILDER_ENV") == "linux-arm-arm5spacemonkey" {
-		cmd.Args = append(cmd.Args, legacyReverseBuildletArgs("linux-arm-arm5spacemonkey")...)
+	switch buildenv := os.Getenv("GO_BUILDER_ENV"); buildenv {
+	case "linux-arm-arm5spacemonkey":
+		cmd.Args = append(cmd.Args, legacyReverseBuildletArgs(buildenv)...)
+	case "host-linux-arm-scaleway":
+		scalewayArgs := append(
+			legacyReverseBuildletArgs(buildenv),
+			"--hostname="+os.Getenv("HOSTNAME"),
+		)
+		cmd.Args = append(cmd.Args,
+			scalewayArgs...,
+		)
 	}
 	switch osArch {
 	case "linux/s390x":
@@ -159,38 +154,6 @@
 	}
 }
 
-func scalewayBuildletArgs() []string {
-	var modes []string // e.g. "linux-arm", "linux-arm-arm5"
-	// tags are of form "buildkey_linux-arm_HEXHEXHEX"
-	for _, tag := range scalewayMeta.Tags {
-		if strings.HasPrefix(tag, "buildkey_") {
-			parts := strings.Split(tag, "_")
-			if len(parts) != 3 {
-				log.Fatalf("invalid server tag %q", tag)
-			}
-			mode, buildkey := parts[1], parts[2]
-			modes = append(modes, mode)
-			file := "/root/.gobuildkey-" + mode
-			if fi, err := os.Stat(file); err != nil || (err == nil && fi.Size() == 0) {
-				if err := ioutil.WriteFile(file, []byte(buildkey), 0600); err != nil {
-					log.Fatal(err)
-				}
-			}
-		}
-	}
-	server := "farmer.golang.org:443"
-	if scalewayMeta.IsStaging() {
-		server = "104.154.113.235:443" // fixed IP, but no hostname.
-	}
-	return []string{
-		"--workdir=/workdir",
-		"--hostname=" + scalewayMeta.Hostname,
-		"--halt=false",
-		"--reverse=" + strings.Join(modes, ","),
-		"--coordinator=" + server,
-	}
-}
-
 // awaitNetwork reports whether the network came up within 30 seconds,
 // determined somewhat arbitrarily via a DNS lookup for google.com.
 func awaitNetwork() bool {
@@ -228,13 +191,6 @@
 		if v := os.Getenv("META_BUILDLET_BINARY_URL"); v != "" {
 			return v
 		}
-		if onScaleway {
-			if scalewayMeta.IsStaging() {
-				return "https://storage.googleapis.com/dev-go-builder-data/buildlet.linux-arm"
-			} else {
-				return "https://storage.googleapis.com/go-builder-data/buildlet.linux-arm"
-			}
-		}
 		sleepFatalf("Not on GCE, and no META_BUILDLET_BINARY_URL specified.")
 	}
 	v, err := metadata.InstanceAttributeValue(attr)
@@ -274,136 +230,6 @@
 	}
 }
 
-func initScaleway() {
-	log.Printf("On scaleway.")
-	onScaleway = true
-	initScalewaySwap()
-	initScalewayWorkdir()
-	initScalewayMeta()
-	initScalewayDNS()
-	initScalewayGo14()
-	log.Printf("Scaleway init complete; metadata is %+v", scalewayMeta)
-}
-
-type scalewayMetadata struct {
-	Name     string   `json:"name"`
-	Hostname string   `json:"hostname"`
-	Tags     []string `json:"tags"`
-}
-
-// IsStaging reports whether this instance has a "staging" tag.
-func (m *scalewayMetadata) IsStaging() bool {
-	for _, t := range m.Tags {
-		if t == "staging" {
-			return true
-		}
-	}
-	return false
-}
-
-func initScalewayMeta() {
-	const metaURL = "http://169.254.42.42/conf?format=json"
-	res, err := http.Get(metaURL)
-	if err != nil {
-		log.Fatalf("failed to get scaleway metadata: %v", err)
-	}
-	defer res.Body.Close()
-	if res.StatusCode != http.StatusOK {
-		log.Fatalf("failed to get scaleway metadata from %s: %v", metaURL, res.Status)
-	}
-	if err := json.NewDecoder(res.Body).Decode(&scalewayMeta); err != nil {
-		log.Fatalf("invalid JSON from scaleway metadata URL %s: %v", metaURL, err)
-	}
-}
-
-func initScalewayDNS() {
-	setFileContents("/etc/resolv.conf", []byte("nameserver 8.8.8.8\n"))
-}
-
-func setFileContents(file string, contents []byte) {
-	old, err := ioutil.ReadFile(file)
-	if err == nil && bytes.Equal(old, contents) {
-		return
-	}
-	if err := ioutil.WriteFile(file, contents, 0644); err != nil {
-		log.Fatal(err)
-	}
-}
-
-func initScalewaySwap() {
-	const swapFile = "/swapfile"
-	slurp, _ := ioutil.ReadFile("/proc/swaps")
-	if strings.Contains(string(slurp), swapFile) {
-		log.Printf("scaleway swapfile already active.")
-		return
-	}
-	os.Remove(swapFile) // if it already exists, else ignore error
-	log.Printf("Running fallocate on swapfile")
-	if out, err := exec.Command("fallocate", "--length", "16GiB", swapFile).CombinedOutput(); err != nil {
-		log.Fatalf("Failed to fallocate /swapfile: %v, %s", err, out)
-	}
-	log.Printf("Running mkswap")
-	if out, err := exec.Command("mkswap", swapFile).CombinedOutput(); err != nil {
-		log.Fatalf("Failed to mkswap /swapfile: %v, %s", err, out)
-	}
-	os.Chmod(swapFile, 0600)
-	log.Printf("Running swapon")
-	if out, err := exec.Command("swapon", swapFile).CombinedOutput(); err != nil {
-		log.Fatalf("Failed to swapon /swapfile: %v, %s", err, out)
-	}
-}
-
-func initScalewayWorkdir() {
-	const dir = "/workdir"
-	slurp, _ := ioutil.ReadFile("/proc/mounts")
-	if strings.Contains(string(slurp), dir) {
-		log.Printf("scaleway workdir already mounted")
-		return
-	}
-	if err := os.MkdirAll("/workdir", 0755); err != nil {
-		log.Fatal(err)
-	}
-	if out, err := exec.Command("mount",
-		"-t", "tmpfs",
-		"-o", "size=8589934592",
-		"tmpfs", "/workdir").CombinedOutput(); err != nil {
-		log.Fatalf("Failed to mount /buildtmp: %v, %s", err, out)
-	}
-}
-
-func initScalewayGo14() {
-	if fi, err := os.Stat("/usr/local/go"); err == nil && fi.IsDir() {
-		log.Printf("go directory already exists.")
-		return
-	}
-	os.RemoveAll("/usr/local/go") // in case it existed somehow, or as regular file
-	if err := os.RemoveAll("/usr/local/go.tmp"); err != nil {
-		log.Fatal(err)
-	}
-	if err := os.MkdirAll("/usr/local/go.tmp", 0755); err != nil {
-		log.Fatal(err)
-	}
-	log.Printf("Downloading go1.4-linux-arm.tar.gz")
-	if out, err := exec.Command("curl",
-		"-o", "/usr/local/go.tmp/go.tar.gz",
-		"--silent",
-		"https://storage.googleapis.com/go-builder-data/go1.4-linux-arm.tar.gz",
-	).CombinedOutput(); err != nil {
-		log.Fatalf("Failed to download go1.4-linux-arm.tar.gz: %v, %s", err, out)
-	}
-	log.Printf("Extracting go1.4-linux-arm.tar.gz")
-	if out, err := exec.Command("tar",
-		"-C", "/usr/local/go.tmp",
-		"-zx",
-		"-f", "/usr/local/go.tmp/go.tar.gz",
-	).CombinedOutput(); err != nil {
-		log.Fatalf("Failed to untar go1.4-linux-arm.tar.gz: %v, %s", err, out)
-	}
-	if err := os.Rename("/usr/local/go.tmp", "/usr/local/go"); err != nil {
-		log.Fatal(err)
-	}
-}
-
 func aptGetInstall(pkgs ...string) {
 	args := append([]string{"--yes", "install"}, pkgs...)
 	cmd := exec.Command("apt-get", args...)
diff --git a/cmd/rundockerbuildlet/rundockerbuildlet.go b/cmd/rundockerbuildlet/rundockerbuildlet.go
index 9bf600e..691f56e 100644
--- a/cmd/rundockerbuildlet/rundockerbuildlet.go
+++ b/cmd/rundockerbuildlet/rundockerbuildlet.go
@@ -10,10 +10,12 @@
 
 import (
 	"bytes"
+	"encoding/json"
 	"flag"
 	"fmt"
 	"io/ioutil"
 	"log"
+	"net/http"
 	"os"
 	"os/exec"
 	"path/filepath"
@@ -29,14 +31,17 @@
 	keyFile  = flag.String("key", "/etc/gobuild.key", "go build key file")
 )
 
-var buildKey []byte
+var (
+	buildKey     []byte
+	scalewayMeta = new(scalewayMetadata)
+)
 
 func main() {
 	flag.Parse()
 
 	key, err := ioutil.ReadFile(*keyFile)
 	if err != nil {
-		log.Fatalf("error reading build key from --key=%s: %v", buildKey, err)
+		log.Fatalf("error reading build key from --key=%s: %v", keyFile, err)
 	}
 	buildKey = bytes.TrimSpace(key)
 
@@ -44,6 +49,10 @@
 		log.Fatalf("docker --image is required")
 	}
 
+	if _, err := os.Stat("/usr/local/bin/oc-metadata"); err == nil {
+		initScalewayMeta()
+	}
+
 	log.Printf("Started. Will keep %d copies of %s running.", *numInst, *image)
 	for {
 		if err := checkFix(); err != nil {
@@ -71,7 +80,12 @@
 			continue
 		}
 		container, name, status := f[0], f[1], f[2]
-		if !strings.HasPrefix(name, *basename) {
+		prefix := *basename
+		if scalewayMeta != nil {
+			// scaleway containers are named after their instance.
+			prefix = scalewayMeta.Hostname
+		}
+		if !strings.HasPrefix(name, prefix) {
 			continue
 		}
 		if strings.HasPrefix(status, "Exited") {
@@ -85,7 +99,15 @@
 	}
 
 	for num := 1; num <= *numInst; num++ {
-		name := fmt.Sprintf("%s%02d", *basename, num)
+		var name string
+		if scalewayMeta != nil {
+			// The -name passed to 'docker run' should match the
+			// c1 instance hostname for debugability.
+			// There should only be one running container per c1 instance.
+			name = scalewayMeta.Hostname
+		} else {
+			name = fmt.Sprintf("%s%02d", *basename, num)
+		}
 		if running[name] {
 			continue
 		}
@@ -113,3 +135,24 @@
 	}
 	return nil
 }
+
+type scalewayMetadata struct {
+	Name     string   `json:"name"`
+	Hostname string   `json:"hostname"`
+	Tags     []string `json:"tags"`
+}
+
+func initScalewayMeta() {
+	const metaURL = "http://169.254.42.42/conf?format=json"
+	res, err := http.Get(metaURL)
+	if err != nil {
+		log.Fatalf("failed to get scaleway metadata: %v", err)
+	}
+	defer res.Body.Close()
+	if res.StatusCode != http.StatusOK {
+		log.Fatalf("failed to get scaleway metadata from %s: %v", metaURL, res.Status)
+	}
+	if err := json.NewDecoder(res.Body).Decode(scalewayMeta); err != nil {
+		log.Fatalf("invalid JSON from scaleway metadata URL %s: %v", metaURL, err)
+	}
+}
diff --git a/cmd/scaleway/scaleway.go b/cmd/scaleway/scaleway.go
index 2b9d84a..f1fc8bb 100644
--- a/cmd/scaleway/scaleway.go
+++ b/cmd/scaleway/scaleway.go
@@ -23,12 +23,15 @@
 var (
 	token   = flag.String("token", "", "API token")
 	org     = flag.String("org", "1f34701d-668b-441b-bf08-0b13544e99de", "Organization ID (default is bradfitz@golang.org's account)")
-	image   = flag.String("image", "bebe2c6f-bbb5-4182-9cce-04cab2f44b2b", "Disk image ID; default is the snapshot we made last")
+	image   = flag.String("image", "e488d5e3-d278-47a7-8f7d-1154e1f61dc9", "Disk image ID; default is the snapshot we made last")
 	num     = flag.Int("n", 0, "Number of servers to create; if zero, defaults to a value as a function of --staging")
 	tags    = flag.String("tags", "", "Comma-separated list of tags. The build key tags should be of the form 'buildkey_linux-arm_HEXHEXHEXHEXHEX'. If empty, it's automatic.")
 	staging = flag.Bool("staging", false, "If true, deploy staging instances (with staging names and tags) instead of prod.")
 )
 
+// ctype is the Commercial Type of server we use for the builders.
+const ctype = "C1"
+
 func main() {
 	flag.Parse()
 	if *tags == "" {
@@ -76,10 +79,11 @@
 				tags = append(tags, "staging")
 			}
 			body, err := json.Marshal(createServerRequest{
-				Org:   *org,
-				Name:  name,
-				Image: *image,
-				Tags:  tags,
+				Org:            *org,
+				Name:           name,
+				Image:          *image,
+				CommercialType: ctype,
+				Tags:           tags,
 			})
 			if err != nil {
 				log.Fatal(err)
@@ -115,10 +119,11 @@
 }
 
 type createServerRequest struct {
-	Org   string   `json:"organization"`
-	Name  string   `json:"name"`
-	Image string   `json:"image"`
-	Tags  []string `json:"tags"`
+	Org            string   `json:"organization"`
+	Name           string   `json:"name"`
+	Image          string   `json:"image"`
+	CommercialType string   `json:"commercial_type"`
+	Tags           []string `json:"tags"`
 }
 
 type Client struct {
diff --git a/dashboard/builders.go b/dashboard/builders.go
index b5d2ec1..70c6fb7 100644
--- a/dashboard/builders.go
+++ b/dashboard/builders.go
@@ -73,21 +73,11 @@
 		buildletURLTmpl: "http://storage.googleapis.com/$BUCKET/buildlet.linux-amd64",
 		env:             []string{"GOROOT_BOOTSTRAP=/go1.4"},
 	},
-	// TODO(shadams): remove once scaleway docker migration
-	// is complete.
-	"host-linux-arm": &HostConfig{
-		IsReverse:      true,
-		ExpectNum:      50,
-		env:            []string{"GOROOT_BOOTSTRAP=/usr/local/go"},
-		ReverseAliases: []string{"linux-arm", "linux-arm-arm5"},
-	},
-	// TODO(shadams): fix reverse aliases to match host-linux-arm
-	// once scaleway docker migration is complete.
 	"host-linux-arm-scaleway": &HostConfig{
 		IsReverse:      true,
 		ExpectNum:      50,
 		env:            []string{"GOROOT_BOOTSTRAP=/usr/local/go"},
-		ReverseAliases: []string{"linux-arm-TMP"},
+		ReverseAliases: []string{"linux-arm", "linux-arm-arm5"},
 	},
 	"host-linux-arm5spacemonkey": &HostConfig{
 		IsReverse:      true,
@@ -912,22 +902,14 @@
 		HostType: "host-linux-sid",
 		Notes:    "Debian sid (unstable)",
 	})
-	// TODO(shadams): change HostType to host-linux-arm-scaleway
-	// when scaleway docker migration is complete.
 	addBuilder(BuildConfig{
 		Name:              "linux-arm",
-		HostType:          "host-linux-arm",
+		HostType:          "host-linux-arm-scaleway",
 		TryBot:            true,
 		FlakyNet:          true,
 		numTestHelpers:    2,
 		numTryTestHelpers: 7,
 	})
-	// TODO(shadams): remove when scaleway docker migration
-	// is complete.
-	addBuilder(BuildConfig{
-		Name:     "linux-arm-TMP",
-		HostType: "host-linux-arm-scaleway",
-	})
 	addBuilder(BuildConfig{
 		Name:          "linux-arm-nativemake",
 		Notes:         "runs make.bash on real ARM hardware, but does not run tests",
diff --git a/env/linux-arm/scaleway/Dockerfile b/env/linux-arm/scaleway/Dockerfile
new file mode 100644
index 0000000..f66c577
--- /dev/null
+++ b/env/linux-arm/scaleway/Dockerfile
@@ -0,0 +1,34 @@
+# Copyright 2017 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 scaleway/ubuntu:armhf-xenial
+
+RUN apt-get update
+
+RUN apt-get install --yes \
+          gcc strace procps psmisc libc6-dev
+
+RUN curl -L -o go1.8.1.tar.gz https://golang.org/dl/go1.8.1.linux-armv6l.tar.gz && \
+    tar fxzv go1.8.1.tar.gz -C /usr/local
+
+ENV GO_BOOTSTRAP=/usr/local/go
+
+# compiled stage0 binary must be in working dir
+COPY stage0 /usr/local/bin/stage0
+
+ENV GO_BUILD_KEY_PATH /buildkey/gobuildkey
+ENV GO_BUILD_KEY_DELETE_AFTER_READ true
+
+# Not really, but we're in a container like Kubernetes, and this makes the syscall
+# package happy:
+ENV IN_KUBERNETES 1
+
+ENV GO_BUILDER_ENV host-linux-arm-scaleway
+
+# env specific
+ARG buildlet_bucket
+
+ENV META_BUILDLET_BINARY_URL "https://storage.googleapis.com/$buildlet_bucket/buildlet.linux-arm"
+
+CMD ["/usr/local/bin/stage0"]
\ No newline at end of file
diff --git a/env/linux-arm/scaleway/Makefile b/env/linux-arm/scaleway/Makefile
new file mode 100644
index 0000000..ab4ae4b
--- /dev/null
+++ b/env/linux-arm/scaleway/Makefile
@@ -0,0 +1,14 @@
+# Copyright 2017 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.
+
+# Compiled stage0 binary must be in working dir.
+
+STAGING_BUCKET=dev-go-builder-data
+PROD_BUCKET=go-builder-data
+
+staging: Dockerfile
+	docker build --build-arg buildlet_bucket=$(STAGING_BUCKET) -t gobuilder-arm-scaleway:latest .
+
+prod: Dockerfile
+	docker build --build-arg buildlet_bucket=$(PROD_BUCKET) -t gobuilder-arm-scaleway:latest .
diff --git a/env/linux-arm/scaleway/README b/env/linux-arm/scaleway/README
index 3cb5492..516735d 100644
--- a/env/linux-arm/scaleway/README
+++ b/env/linux-arm/scaleway/README
@@ -1,35 +1,28 @@
-To create a fresh builder host:  (should only be needed once)
+C1 image created with docker base image using 
+`armv7l 4.10.8 docker #1` bootscript.
 
-Create a new Scaleway server with type "Docker 1.5" (second tab).
+Machines:
 
-Make a tmpfs:
-# echo "tmpfs /tmpfs tmpfs" >> /etc/fstab
-# mkdir /tmpfs
+    $ ssh -i ~/keys/id_ed25519_golang1 root@$C1_SERVER_IP
+    (key: http://go/go-builders-ssh)
 
-Make a 2GB swap file:
-# dd if=/dev/zero of=/swap count=2097152 obs=1024
-# mkswap /swap
-# chmod 0600 /swap
-# echo "/swap none swap loop 0 0" >> /etc/fstab
+Machine setup:
+	# local:
+	$ scp env/linux-arm/scaleway/* root@$C1_SERVER_IP:~/scaleway
 
-Reboot.
+	$ GOARCH=arm GOOS=linux go install golang.org/x/build/cmd/rundockerbuildlet && \
+	 scp ~/bin/linux_arm/rundockerbuildlet root@$C1_SERVER_IP:/usr/local/bin
+	$ GOARCH=arm GOOS=linux go install golang.org/x/build/cmd/buildlet/stage0 && \
+	 scp ~/bin/linux_arm/stage0 root@$C1_SERVER_IP:~/scaleway
+	# NOTE: commit SHA of rundockerbuildlet/stage0 on instance snapshot (06/19/17)
+	# golang.org/x/build is 282d813.
 
-Should see swaps in "cat /proc/swaps" and tmpfs in "cat /proc/mounts" now.
+	$ scp rundockerbuildlet.service root@$C1_SERVER_IP:/etc/systemd/user/
 
-* Copy the contents of this directory to the server.
+	# c1 server:
 
-* Go into that directory and:
-  # docker build -t buildlet .
+	$ echo "<BUILDER KEY>" > /etc/gobuild.key > /root/.gobuildkey
 
-Add to /etc/rc.local:
+	$ systemctl enable /etc/systemd/user/rundockerbuildlet.service
+	$ systemctl start rundockerbuildlet.service
 
-  (mkdir -p /tmpfs/buildertmp && docker run -e BUILDKEY_ARM=xxx -e BUILDKEY_ARM5=xxx -v=/tmpfs/buildertmp:/tmp --restart=always -d --name=buildlet buildlet) &
-  sleep 5
-
-.. before the exit 0
-
-Power it down (with ARCHIVE),
-
-Snapshot the disk.
-
-Start a bunch of them. (see golang.org/x/build/cmd/scaleway)
diff --git a/env/linux-arm/scaleway/buildlet.service b/env/linux-arm/scaleway/buildlet.service
deleted file mode 100644
index 0fee9b1..0000000
--- a/env/linux-arm/scaleway/buildlet.service
+++ /dev/null
@@ -1,16 +0,0 @@
-# See NOTES files
-
-[Unit]
-Description=Go builder buildlet
-After=network.target
-
-[Install]
-WantedBy=network-online.target
-
-[Service]
-Type=simple
-ExecStartPre=/bin/sh -c '/usr/bin/curl -f -o /usr/local/bin/buildlet-stage0 https://storage.googleapis.com/go-builder-data/buildlet-stage0.linux-arm-scaleway?$(date +%s) && chmod +x /usr/local/bin/buildlet-stage0'
-ExecStart=/usr/local/bin/buildlet-stage0
-Restart=always
-RestartSec=2
-StartLimitInterval=0
diff --git a/env/linux-arm/scaleway/rundockerbuildlet.service b/env/linux-arm/scaleway/rundockerbuildlet.service
new file mode 100644
index 0000000..372da1d
--- /dev/null
+++ b/env/linux-arm/scaleway/rundockerbuildlet.service
@@ -0,0 +1,13 @@
+[Unit]
+Description=Run Buildlets in Docker
+After=network.target
+
+[Install]
+WantedBy=network-online.target
+
+[Service]
+Type=simple
+ExecStart=/usr/local/bin/rundockerbuildlet -basename=scaleway -image=gobuilder-arm-scaleway:latest -n=1 
+Restart=always
+RestartSec=2
+StartLimitInterval=0
\ No newline at end of file
diff --git a/env/linux-arm64/linaro/build.sh b/env/linux-arm64/linaro/build.sh
index 391ecee..63c57a1 100755
--- a/env/linux-arm64/linaro/build.sh
+++ b/env/linux-arm64/linaro/build.sh
@@ -3,5 +3,4 @@
 # This is run on the arm64 host with the Dockerfile in the same directory. 
 # The parent Dockerfile and build.sh (linux-arm64/*) must be in parent directory.
 
-
 (cd ../ && ./build.sh) && docker build -t gobuilder-arm64-linaro:1 .
\ No newline at end of file
diff --git a/env/linux-arm64/packet/README b/env/linux-arm64/packet/README
index 933a9d5..4ad42ba 100644
--- a/env/linux-arm64/packet/README
+++ b/env/linux-arm64/packet/README
@@ -40,7 +40,7 @@
    $ GOARCH=arm64 GOOS=linux go install golang.org/x/build/cmd/rundockerbuildlet && \
      scp -i ~/keys/id_ed25519_golang1 ~/bin/linux_arm64/rundockerbuildlet root@147.75.109.230:/usr/local/bin
 
-   $ scp -i ~/keys/id_ed25519_golang1 rundockerbuildlet.service root@147.75.109.230:/usr/local/bin:/etc/systemd/user/
+   $ scp -i ~/keys/id_ed25519_golang1 rundockerbuildlet.service root@147.75.109.230:/etc/systemd/user/
 
    $ systemctl enable /etc/systemd/user/rundockerbuildlet.service
    $ systemctl start rundockerbuildlet.service
\ No newline at end of file