cmd/gomote: implements GRPC list command

This change adds the implementation for the GRPC list command to the
gomote client.

Updates golang/go#48737
For golang/go#47521

Change-Id: Ie9eea0136e0e22edc43ec67e4bd0f8c5350a3ce8
Reviewed-on: https://go-review.googlesource.com/c/build/+/398056
Auto-Submit: Carlos Amedee <carlos@golang.org>
Reviewed-by: Heschi Kreinick <heschi@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Run-TryBot: Carlos Amedee <carlos@golang.org>
Reviewed-by: Alex Rakoczy <alex@golang.org>
diff --git a/cmd/gomote/gomote.go b/cmd/gomote/gomote.go
index 0a93d02..7771c85 100644
--- a/cmd/gomote/gomote.go
+++ b/cmd/gomote/gomote.go
@@ -153,7 +153,7 @@
 	registerCommand("destroy", "destroy a buildlet", legacyDestroy)
 	registerCommand("gettar", "extract a tar.gz from a buildlet", getTar)
 	registerCommand("ls", "list the contents of a directory on a buildlet", ls)
-	registerCommand("list", "list active buildlets", list)
+	registerCommand("list", "list active buildlets", legacyList)
 	registerCommand("ping", "test whether a buildlet is alive and reachable ", ping)
 	registerCommand("push", "sync your GOROOT directory to the buildlet", push)
 	registerCommand("put", "put files on a buildlet", put)
@@ -218,6 +218,7 @@
 	cm := map[string]subCommand{
 		"create":  create,
 		"destroy": destroy,
+		"list":    list,
 	}
 	if len(args) == 0 {
 		usage()
diff --git a/cmd/gomote/list.go b/cmd/gomote/list.go
index ab99b11..3f8460f 100644
--- a/cmd/gomote/list.go
+++ b/cmd/gomote/list.go
@@ -5,6 +5,7 @@
 package main
 
 import (
+	"context"
 	"flag"
 	"fmt"
 	"log"
@@ -14,9 +15,10 @@
 
 	"golang.org/x/build/buildlet"
 	"golang.org/x/build/dashboard"
+	"golang.org/x/build/internal/gomote/protos"
 )
 
-func list(args []string) error {
+func legacyList(args []string) error {
 	fs := flag.NewFlagSet("list", flag.ContinueOnError)
 	fs.Usage = func() {
 		fmt.Fprintln(os.Stderr, "list usage: gomote list")
@@ -123,3 +125,27 @@
 
 	return bc, conf, nil
 }
+
+func list(args []string) error {
+	fs := flag.NewFlagSet("list", flag.ContinueOnError)
+	fs.Usage = func() {
+		fmt.Fprintln(os.Stderr, "list usage: gomote list")
+		fs.PrintDefaults()
+		os.Exit(1)
+	}
+	fs.Parse(args)
+	if fs.NArg() != 0 {
+		fs.Usage()
+	}
+
+	ctx := context.Background()
+	client := gomoteServerClient(ctx)
+	resp, err := client.ListInstances(ctx, &protos.ListInstancesRequest{})
+	if err != nil {
+		return fmt.Errorf("unable to list instance: %s", statusFromError(err))
+	}
+	for _, inst := range resp.GetInstances() {
+		fmt.Printf("%s\t%s\t%s\texpires in %v\n", inst.GetGomoteId(), inst.GetBuilderType(), inst.GetHostType(), time.Unix(inst.GetExpires(), 0).Sub(time.Now()))
+	}
+	return nil
+}