cmd/gomote: remove the old create-VMs-directly model; always use coordinator

Fixes golang/go#11711

Change-Id: I1c05de286393a610b74595f57487ebd341b6e599
Reviewed-on: https://go-review.googlesource.com/12393
Reviewed-by: Andrew Gerrand <adg@golang.org>
diff --git a/cmd/gomote/auth.go b/cmd/gomote/auth.go
index e7df09b..bc421d9 100644
--- a/cmd/gomote/auth.go
+++ b/cmd/gomote/auth.go
@@ -11,11 +11,6 @@
 	"path/filepath"
 	"runtime"
 	"strings"
-
-	"golang.org/x/build/auth"
-	"golang.org/x/build/buildlet"
-	"golang.org/x/oauth2"
-	"google.golang.org/api/compute/v1"
 )
 
 func username() string {
@@ -42,41 +37,6 @@
 	return filepath.Join(homeDir(), ".config", "gomote")
 }
 
-func projTokenSource() oauth2.TokenSource {
-	ts, err := auth.ProjectTokenSource(*proj, compute.ComputeScope)
-	if err != nil {
-		log.Fatalf("Failed to get OAuth2 token source for project %s: %v", *proj, err)
-	}
-	return ts
-}
-
-func userKeyPair() buildlet.KeyPair {
-	keyDir := configDir()
-	crtFile := filepath.Join(keyDir, "gomote.crt")
-	keyFile := filepath.Join(keyDir, "gomote.key")
-	_, crtErr := os.Stat(crtFile)
-	_, keyErr := os.Stat(keyFile)
-	if crtErr == nil && keyErr == nil {
-		return buildlet.KeyPair{
-			CertPEM: slurpString(crtFile),
-			KeyPEM:  slurpString(keyFile),
-		}
-	}
-	check := func(what string, err error) {
-		if err != nil {
-			log.Printf("%s: %v", what, err)
-		}
-	}
-	check("making key dir", os.MkdirAll(keyDir, 0700))
-	kp, err := buildlet.NewKeyPair()
-	if err != nil {
-		log.Fatalf("Error generating new key pair: %v", err)
-	}
-	check("writing cert file: ", ioutil.WriteFile(crtFile, []byte(kp.CertPEM), 0600))
-	check("writing key file: ", ioutil.WriteFile(keyFile, []byte(kp.KeyPEM), 0600))
-	return kp
-}
-
 func slurpString(f string) string {
 	slurp, err := ioutil.ReadFile(f)
 	if err != nil {
@@ -91,8 +51,8 @@
 	}
 	keyDir := configDir()
 	baseFile := "user-" + *user + ".token"
-	if *dev {
-		baseFile = "dev-" + baseFile
+	if *staging {
+		baseFile = "staging-" + baseFile
 	}
 	tokenFile := filepath.Join(keyDir, baseFile)
 	slurp, err := ioutil.ReadFile(tokenFile)
diff --git a/cmd/gomote/create.go b/cmd/gomote/create.go
index e30980f..08badf2 100644
--- a/cmd/gomote/create.go
+++ b/cmd/gomote/create.go
@@ -7,13 +7,10 @@
 import (
 	"flag"
 	"fmt"
-	"log"
 	"os"
 	"sort"
 	"strings"
-	"time"
 
-	"golang.org/x/build/buildlet"
 	"golang.org/x/build/dashboard"
 )
 
@@ -37,8 +34,10 @@
 		}
 		os.Exit(1)
 	}
-	var timeout time.Duration
-	fs.DurationVar(&timeout, "timeout", 60*time.Minute, "how long the VM will live before being deleted.")
+	// TODO(bradfitz): restore this option, and send it to the coordinator:
+	// For now, comment it out so it's not misleading.
+	// var timeout time.Duration
+	// fs.DurationVar(&timeout, "timeout", 60*time.Minute, "how long the VM will live before being deleted.")
 
 	fs.Parse(args)
 	if fs.NArg() != 1 {
@@ -63,36 +62,11 @@
 		}
 	}
 
-	if *user == "" {
-		instPrefix := fmt.Sprintf("mote-%s-", username())
-		instName, err := nextName(instPrefix + builderType)
-		if err != nil {
-			return err
-		}
-		client, err := buildlet.StartNewVM(projTokenSource(), instName, builderType, buildlet.VMOpts{
-			Zone:        *zone,
-			ProjectID:   *proj,
-			TLS:         userKeyPair(),
-			DeleteIn:    timeout,
-			Description: fmt.Sprintf("gomote buildlet for %s", username()),
-			OnInstanceRequested: func() {
-				log.Printf("Sent create request. Waiting for operation.")
-			},
-			OnInstanceCreated: func() {
-				log.Printf("Instance created.")
-			},
-		})
-		if err != nil {
-			return fmt.Errorf("failed to create VM: %v", err)
-		}
-		fmt.Printf("%s\t%s\n", strings.TrimPrefix(instName, instPrefix), client.URL())
-	} else {
-		cc := coordinatorClient()
-		client, err := cc.CreateBuildlet(builderType)
-		if err != nil {
-			return fmt.Errorf("failed to create buildlet: %v", err)
-		}
-		fmt.Println(client.RemoteName())
+	cc := coordinatorClient()
+	client, err := cc.CreateBuildlet(builderType)
+	if err != nil {
+		return fmt.Errorf("failed to create buildlet: %v", err)
 	}
+	fmt.Println(client.RemoteName())
 	return nil
 }
diff --git a/cmd/gomote/destroy.go b/cmd/gomote/destroy.go
index 49f1e63..aed8818 100644
--- a/cmd/gomote/destroy.go
+++ b/cmd/gomote/destroy.go
@@ -27,9 +27,5 @@
 	if err != nil {
 		return err
 	}
-	if *user == "" {
-		return bc.DestroyVM(projTokenSource(), *proj, *zone, fmt.Sprintf("mote-%s-%s", username(), name))
-	} else {
-		return bc.Destroy()
-	}
+	return bc.Destroy()
 }
diff --git a/cmd/gomote/gomote.go b/cmd/gomote/gomote.go
index 2e6c5d7..00d1c7d 100644
--- a/cmd/gomote/gomote.go
+++ b/cmd/gomote/gomote.go
@@ -31,14 +31,9 @@
 )
 
 var (
-	user = flag.String("user", username(), "gomote server username; if set to the empty string, only GCE VMs can be created, without using the coordinator.")
+	user = flag.String("user", username(), "gomote server username. You must have the token for user-$USER. The error message will say where to put it.")
 
-	proj = flag.String("project", "symbolic-datum-552", "GCE project owning builders")
-	zone = flag.String("zone", "us-central1-a", "GCE zone")
-
-	// Mostly dev options:
-	dev            = flag.Bool("dev", false, "if true, the default project becomes the default staging project")
-	buildletBucket = flag.String("buildletbucket", "", "Optional alternate GCS bucket for the buildlet binaries.")
+	staging = flag.Bool("staging", false, "if true, use the staging build coordinator and buildlets")
 )
 
 type command struct {
@@ -84,7 +79,7 @@
 
 func coordinatorClient() *buildlet.CoordinatorClient {
 	inst := build.ProdCoordinator
-	if *dev {
+	if *staging {
 		inst = build.StagingCoordinator
 	}
 	return &buildlet.CoordinatorClient{
@@ -115,13 +110,9 @@
 	registerCommands()
 	flag.Usage = usage
 	flag.Parse()
-	if *dev {
-		*proj = "go-dashboard-dev"
+	if *staging {
 		dashboard.BuildletBucket = "dev-go-builder-data"
 	}
-	if v := *buildletBucket; v != "" {
-		dashboard.BuildletBucket = v
-	}
 	args := flag.Args()
 	if len(args) == 0 {
 		usage()
diff --git a/cmd/gomote/list.go b/cmd/gomote/list.go
index 06d3159..ab7ffaa 100644
--- a/cmd/gomote/list.go
+++ b/cmd/gomote/list.go
@@ -28,62 +28,51 @@
 		fs.Usage()
 	}
 
-	if *user == "" {
-		prefix := fmt.Sprintf("mote-%s-", username())
-		vms, err := buildlet.ListVMs(projTokenSource(), *proj, *zone)
-		if err != nil {
-			return fmt.Errorf("failed to list VMs: %v", err)
-		}
-		for _, vm := range vms {
-			if !strings.HasPrefix(vm.Name, prefix) {
-				continue
+	cc := coordinatorClient()
+	rbs, err := cc.RemoteBuildlets()
+	if err != nil {
+		log.Fatal(err)
+	}
+	for _, rb := range rbs {
+		fmt.Printf("%s\t%s\texpires in %v\n", rb.Name, rb.Type, rb.Expires.Sub(time.Now()))
+	}
+
+	return nil
+}
+
+func clientAndConf(name string) (bc *buildlet.Client, conf dashboard.BuildConfig, err error) {
+	cc := coordinatorClient()
+
+	rbs, err := cc.RemoteBuildlets()
+	if err != nil {
+		return
+	}
+	var ok bool
+	for _, rb := range rbs {
+		if rb.Name == name {
+			conf, ok = namedConfig(rb.Type)
+			if !ok {
+				err = fmt.Errorf("builder %q exists, but unknown type %q", name, rb.Type)
+				return
 			}
-			fmt.Printf("%s\thttps://%s\n", strings.TrimPrefix(vm.Name, prefix), strings.TrimSuffix(vm.IPPort, ":443"))
-		}
-	} else {
-		cc := coordinatorClient()
-		rbs, err := cc.RemoteBuildlets()
-		if err != nil {
-			log.Fatal(err)
-		}
-		for _, rb := range rbs {
-			fmt.Printf("%s\t%s\texpires in %v\n", rb.Name, rb.Type, rb.Expires.Sub(time.Now()))
+			break
 		}
 	}
-	return nil
+	if !ok {
+		err = fmt.Errorf("unknown builder %q", name)
+		return
+	}
+
+	bc, err = namedClient(name)
+	return
 }
 
 func namedClient(name string) (*buildlet.Client, error) {
 	if strings.Contains(name, ":") {
 		return buildlet.NewClient(name, buildlet.NoKeyPair), nil
 	}
-	if *user != "" {
-		cc := coordinatorClient()
-		return cc.NamedBuildlet(name)
-	}
-	// TODO(bradfitz): cache the list on disk and avoid the API call?
-	vms, err := buildlet.ListVMs(projTokenSource(), *proj, *zone)
-	if err != nil {
-		return nil, fmt.Errorf("error listing VMs while looking up %q: %v", name, err)
-	}
-	wantName := fmt.Sprintf("mote-%s-%s", username(), name)
-	var matches []buildlet.VM
-	for _, vm := range vms {
-		if vm.Name == wantName {
-			return buildlet.NewClient(vm.IPPort, vm.TLS), nil
-		}
-		if strings.HasPrefix(vm.Name, wantName) {
-			matches = append(matches, vm)
-		}
-	}
-	if len(matches) == 1 {
-		vm := matches[0]
-		return buildlet.NewClient(vm.IPPort, vm.TLS), nil
-	}
-	if len(matches) > 1 {
-		return nil, fmt.Errorf("prefix %q is ambiguous", wantName)
-	}
-	return nil, fmt.Errorf("buildlet %q not running", name)
+	cc := coordinatorClient()
+	return cc.NamedBuildlet(name)
 }
 
 // namedConfig returns the builder configuration that matches the given mote
@@ -97,29 +86,3 @@
 	}
 	return dashboard.Builders[match], match != ""
 }
-
-// nextName returns the next available numbered name or the given buildlet base
-// name. For example, if the provided prefix is "linux-amd64" and there's
-// already an instance named "linux-amd64", nextName will return
-// "linux-amd64-1".
-func nextName(prefix string) (string, error) {
-	vms, err := buildlet.ListVMs(projTokenSource(), *proj, *zone)
-	if err != nil {
-		return "", fmt.Errorf("error listing VMs: %v", err)
-	}
-	matches := map[string]bool{}
-	for _, vm := range vms {
-		if strings.HasPrefix(vm.Name, prefix) {
-			matches[vm.Name] = true
-		}
-	}
-	if len(matches) == 0 || !matches[prefix] {
-		return prefix, nil
-	}
-	for i := 1; ; i++ {
-		next := fmt.Sprintf("%v-%v", prefix, i)
-		if !matches[next] {
-			return next, nil
-		}
-	}
-}
diff --git a/cmd/gomote/put.go b/cmd/gomote/put.go
index 3fef2dc..fb6f7ac 100644
--- a/cmd/gomote/put.go
+++ b/cmd/gomote/put.go
@@ -99,18 +99,14 @@
 		fs.Usage()
 	}
 	name := fs.Arg(0)
-	conf, ok := namedConfig(name)
-	if !ok {
-		return fmt.Errorf("unknown builder %q", name)
+	bc, conf, err := clientAndConf(name)
+	if err != nil {
+		return err
 	}
 	if conf.Go14URL == "" {
 		fmt.Printf("No Go14URL field defined for %q; ignoring. (may be baked into image)\n", name)
 		return nil
 	}
-	bc, err := namedClient(name)
-	if err != nil {
-		return err
-	}
 	return bc.PutTarFromURL(conf.Go14URL, "go1.4")
 }
 
diff --git a/cmd/gomote/run.go b/cmd/gomote/run.go
index 9421b82..a14f0bc 100644
--- a/cmd/gomote/run.go
+++ b/cmd/gomote/run.go
@@ -40,34 +40,8 @@
 	name, cmd := fs.Arg(0), fs.Arg(1)
 
 	var conf dashboard.BuildConfig
-	if *user == "" {
-		var ok bool
-		conf, ok = namedConfig(name)
-		if !ok {
-			return fmt.Errorf("unknown builder type %q", name)
-		}
-	} else {
-		cc := coordinatorClient()
-		rbs, err := cc.RemoteBuildlets()
-		if err != nil {
-			return err
-		}
-		var ok bool
-		for _, rb := range rbs {
-			if rb.Name == name {
-				conf, ok = namedConfig(rb.Type)
-				if !ok {
-					return fmt.Errorf("builder %q exists, but unknown type %q", name, rb.Type)
-				}
-				break
-			}
-		}
-		if !ok {
-			return fmt.Errorf("unknown builder %q", name)
-		}
-	}
 
-	bc, err := namedClient(name)
+	bc, conf, err := clientAndConf(name)
 	if err != nil {
 		return err
 	}