buildlet: add DestroyVM method to Client

And use it in gomote and release tools.

Change-Id: I87fa013d6d6729e7305dacd137be1b3d3b02f5f4
Reviewed-on: https://go-review.googlesource.com/3771
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
diff --git a/buildlet/buildletclient.go b/buildlet/buildletclient.go
index f341224..9d0e4d8 100644
--- a/buildlet/buildletclient.go
+++ b/buildlet/buildletclient.go
@@ -15,6 +15,9 @@
 	"net/http"
 	"net/url"
 	"strings"
+	"time"
+
+	"golang.org/x/oauth2"
 )
 
 // NewClient returns a *Client that will manipulate ipPort,
@@ -232,6 +235,50 @@
 	return c.doOK(req)
 }
 
+// DestroyVM shuts down the buildlet and destroys the VM instance.
+func (c *Client) DestroyVM(ts oauth2.TokenSource, proj, zone, instance string) error {
+	gceErrc := make(chan error, 1)
+	buildletErrc := make(chan error, 1)
+	go func() {
+		gceErrc <- DestroyVM(ts, proj, zone, instance)
+	}()
+	go func() {
+		buildletErrc <- c.Destroy()
+	}()
+	timeout := time.NewTimer(5 * time.Second)
+	defer timeout.Stop()
+
+	var retErr error
+	var gceDone, buildletDone bool
+	for !gceDone || !buildletDone {
+		select {
+		case err := <-gceErrc:
+			if err != nil {
+				retErr = err
+			}
+			gceDone = true
+		case err := <-buildletErrc:
+			if err != nil {
+				retErr = err
+			}
+			buildletDone = true
+		case <-timeout.C:
+			e := ""
+			if !buildletDone {
+				e = "timeout asking buildlet to shut down"
+			}
+			if !gceDone {
+				if e != "" {
+					e += " and "
+				}
+				e += "timeout asking GCE to delete builder VM"
+			}
+			return errors.New(e)
+		}
+	}
+	return retErr
+}
+
 func condRun(fn func()) {
 	if fn != nil {
 		fn()
diff --git a/cmd/gomote/destroy.go b/cmd/gomote/destroy.go
index 53cf5d2..4a6c74d 100644
--- a/cmd/gomote/destroy.go
+++ b/cmd/gomote/destroy.go
@@ -5,14 +5,9 @@
 package main
 
 import (
-	"errors"
 	"flag"
 	"fmt"
-	"log"
 	"os"
-	"time"
-
-	"golang.org/x/build/buildlet"
 )
 
 func destroy(args []string) error {
@@ -33,47 +28,5 @@
 		return err
 	}
 
-	// Ask it to kill itself, and tell GCE to kill it too:
-	gceErrc := make(chan error, 1)
-	buildletErrc := make(chan error, 1)
-	go func() {
-		gceErrc <- buildlet.DestroyVM(projTokenSource(), *proj, *zone, fmt.Sprintf("mote-%s-%s", username(), name))
-	}()
-	go func() {
-		buildletErrc <- bc.Destroy()
-	}()
-	timeout := time.NewTimer(5 * time.Second)
-	defer timeout.Stop()
-
-	var retErr error
-	var gceDone, buildletDone bool
-	for !gceDone || !buildletDone {
-		select {
-		case err := <-gceErrc:
-			if err != nil {
-				log.Printf("GCE: %v", err)
-				retErr = err
-			} else {
-				log.Printf("Requested GCE delete.")
-			}
-			gceDone = true
-		case err := <-buildletErrc:
-			if err != nil {
-				log.Printf("Buildlet: %v", err)
-				retErr = err
-			} else {
-				log.Printf("Requested buildlet to shut down.")
-			}
-			buildletDone = true
-		case <-timeout.C:
-			if !buildletDone {
-				log.Printf("timeout asking buildlet to shut down")
-			}
-			if !gceDone {
-				log.Printf("timeout asking GCE to delete builder VM")
-			}
-			return errors.New("timeout")
-		}
-	}
-	return retErr
+	return bc.DestroyVM(projTokenSource(), *proj, *zone, fmt.Sprintf("mote-%s-%s", username(), name))
 }
diff --git a/cmd/release/release.go b/cmd/release/release.go
index 82599f2..6a5aad1 100644
--- a/cmd/release/release.go
+++ b/cmd/release/release.go
@@ -108,7 +108,10 @@
 
 	defer func() {
 		log.Printf("%v: Destroying VM.", instance)
-		haltAndDestroy(client, instance)
+		err := client.DestroyVM(projTokenSource(), *project, *zone, instance)
+		if err != nil {
+			log.Printf("%v: Destroying VM: %v", instance, err)
+		}
 	}()
 
 	// Push source to VM
@@ -175,49 +178,6 @@
 	return nil
 }
 
-func haltAndDestroy(bc *buildlet.Client, instance string) {
-	// TODO(adg): move this to buildlet library.
-
-	// Ask buildlet to kill itself, and tell GCE to kill it too.
-	gceErrc := make(chan error, 1)
-	buildletErrc := make(chan error, 1)
-	go func() {
-		gceErrc <- buildlet.DestroyVM(projTokenSource(), *project, *zone, instance)
-	}()
-	go func() {
-		buildletErrc <- bc.Destroy()
-	}()
-	timeout := time.NewTimer(5 * time.Second)
-	defer timeout.Stop()
-
-	var gceDone, buildletDone bool
-	for !gceDone || !buildletDone {
-		select {
-		case err := <-gceErrc:
-			if err != nil {
-				log.Printf("%v: GCE: %v", instance, err)
-			} else {
-				log.Printf("%v: Requested GCE delete.", instance)
-			}
-			gceDone = true
-		case err := <-buildletErrc:
-			if err != nil {
-				log.Printf("%v: Buildlet: %v", instance, err)
-			} else {
-				log.Printf("%v: Requested buildlet to shut down.", instance)
-			}
-			buildletDone = true
-		case <-timeout.C:
-			if !buildletDone {
-				log.Printf("%v: timeout asking buildlet to shut down", instance)
-			}
-			if !gceDone {
-				log.Printf("%v: timeout asking GCE to delete builder VM", instance)
-			}
-		}
-	}
-}
-
 func projTokenSource() oauth2.TokenSource {
 	ts, err := auth.ProjectTokenSource(*project, compute.ComputeScope)
 	if err != nil {