cmd/gomote: add gomote GRPC client and authentication

This change adds the GRPC gomote server client to the gomote client.
It also adds the authentication logic to be used with the gomote server.

For golang/go#47521
For golang/go#48737
Fixes golang/go#48739

Change-Id: If83287e27d59d14056131d6077adc4b1a8e85913
Reviewed-on: https://go-review.googlesource.com/c/build/+/397656
Reviewed-by: Heschi Kreinick <heschi@google.com>
Reviewed-by: Carlos Amedee <carlos@golang.org>
Run-TryBot: Carlos Amedee <carlos@golang.org>
Auto-Submit: Carlos Amedee <carlos@golang.org>
TryBot-Result: Gopher Robot <gobot@golang.org>
diff --git a/cmd/gomote/gomote.go b/cmd/gomote/gomote.go
index fba653d..8c6f404 100644
--- a/cmd/gomote/gomote.go
+++ b/cmd/gomote/gomote.go
@@ -84,13 +84,21 @@
 package main
 
 import (
+	"context"
+	"crypto/tls"
 	"flag"
 	"fmt"
 	"os"
 	"sort"
+	"strings"
 
 	"golang.org/x/build/buildenv"
 	"golang.org/x/build/buildlet"
+	"golang.org/x/build/internal/gomote/protos"
+	"golang.org/x/build/internal/iapclient"
+	"google.golang.org/grpc"
+	"google.golang.org/grpc/credentials"
+	"google.golang.org/grpc/credentials/oauth"
 )
 
 var (
@@ -155,6 +163,10 @@
 	registerCommand("ssh", "ssh to a buildlet", ssh)
 }
 
+var (
+	serverAddr = flag.String("server", "build.golang.org:443", "Address for GRPC server")
+)
+
 func main() {
 	buildlet.RegisterFlags()
 	registerCommands()
@@ -177,3 +189,28 @@
 		os.Exit(1)
 	}
 }
+
+// gomoteServerClient returns a gomote server client which can be used to interact with the gomote GRPC server.
+// It will either retrieve a previously created authentication token or attempt to create a new one.
+func gomoteServerClient(ctx context.Context) protos.GomoteServiceClient {
+	ts, err := iapclient.TokenSource(ctx)
+	if err != nil {
+		logAndExitf("failed to retrieve oauth token: %s", err)
+	}
+	opts := []grpc.DialOption{
+		grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{InsecureSkipVerify: strings.HasPrefix(*serverAddr, "localhost:")})),
+		grpc.WithDefaultCallOptions(grpc.PerRPCCredentials(oauth.TokenSource{TokenSource: ts})),
+		grpc.WithBlock(),
+	}
+	grpcClient, err := grpc.DialContext(ctx, *serverAddr, opts...)
+	if err != nil {
+		logAndExitf("dialing the server=%s failed with: %s", *serverAddr, err)
+	}
+	return protos.NewGomoteServiceClient(grpcClient)
+}
+
+// logAndExitf is equivalent to Printf to Stderr followed by a call to os.Exit(1).
+func logAndExitf(format string, v ...interface{}) {
+	fmt.Fprintf(os.Stderr, format, v...)
+	os.Exit(1)
+}