cmd/coordinator: add BuildletPool abstraction; don't assume GCE

This starts the process of making the coordinator about to use the
buildlet on things other than GCE.

Update golang/go#8647 (ARM, reverse proxy or online.net)
Update golang/go#10267 (windows 2003 on AWS)
Update golang/go#9495 (OS X VMWare VMs on racked Mac Minis)

Change-Id: I5df79ea67e0ececba8b880e81bd93d4c80897455
Reviewed-on: https://go-review.googlesource.com/8198
Reviewed-by: David Crawshaw <crawshaw@golang.org>
diff --git a/buildlet/buildletclient.go b/buildlet/buildletclient.go
index f178162..4dd5f66 100644
--- a/buildlet/buildletclient.go
+++ b/buildlet/buildletclient.go
@@ -40,6 +40,28 @@
 	}
 }
 
+// SetCloseFunc sets a function to be called when c.Close is called.
+// SetCloseFunc must not be called concurrently with Close.
+func (c *Client) SetCloseFunc(fn func() error) {
+	c.closeFunc = fn
+}
+
+func (c *Client) Close() error {
+	var err error
+	if c.closeFunc != nil {
+		err = c.closeFunc()
+		c.closeFunc = nil
+	}
+	return err
+}
+
+// SetDescription sets a short description of where the buildlet
+// connection came from.  This is used by the build coordinator status
+// page, mostly for debugging.
+func (c *Client) SetDescription(v string) {
+	c.desc = v
+}
+
 // defaultDialer returns the net/http package's default Dial function.
 // Notably, this sets TCP keep-alive values, so when we kill VMs
 // (whose TCP stacks stop replying, forever), we don't leak file
@@ -57,6 +79,16 @@
 	tls        KeyPair
 	password   string // basic auth password or empty for none
 	httpClient *http.Client
+
+	closeFunc func() error
+	desc      string
+}
+
+func (c *Client) String() string {
+	if c == nil {
+		return "(nil *buildlet.Client)"
+	}
+	return strings.TrimSpace(c.URL() + " " + c.desc)
 }
 
 // URL returns the buildlet's URL prefix, without a trailing slash.