Skip to content

Commit 58d7fcc

Browse files
cagedmantisgopherbot
authored andcommitted
cmd/gomote, internal/iapclient: add a gomote login command
This change adds a gomote login subcommand. There is currently an issue where gomote users have their authentication token invalidated. They are unable to log into the gomote service. The only way to create a new authentication token is to manually delete the authentication token from the file system and attempt another command. This change adds a login subcommand which removes any existing authentication token and initiates the authentication workflow. Investigation into why we can't detect invalid tokens will continue after this CL has been submitted. The login command also authenticates with the LUCI service. For golang/go#68612 Change-Id: Ib0c14546e919648ffd76a1021154134184bc18e3 Reviewed-on: https://go-review.googlesource.com/c/build/+/601796 LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: Michael Knyszek <[email protected]> Reviewed-by: Dmitri Shuralyov <[email protected]> Auto-Submit: Carlos Amedee <[email protected]>
1 parent 1cfd0d1 commit 58d7fcc

File tree

3 files changed

+73
-4
lines changed

3 files changed

+73
-4
lines changed

cmd/gomote/gomote.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ To list the subcommands, run "gomote" without arguments:
2727
destroy destroy a buildlet
2828
gettar extract a tar.gz from a buildlet
2929
list list active buildlets
30+
login create authentication credentials for the gomote services
3031
ls list the contents of a directory on a buildlet
3132
ping test whether a buildlet is alive and reachable
3233
push sync your GOROOT directory to the buildlet
@@ -215,8 +216,9 @@ func registerCommands() {
215216
registerCommand("destroy", "destroy a buildlet", destroy)
216217
registerCommand("gettar", "extract a tar.gz from a buildlet", getTar)
217218
registerCommand("group", "manage groups of instances", group)
218-
registerCommand("ls", "list the contents of a directory on a buildlet", ls)
219219
registerCommand("list", "list active buildlets", list)
220+
registerCommand("login", "authenticate with the gomote service", login)
221+
registerCommand("ls", "list the contents of a directory on a buildlet", ls)
220222
registerCommand("ping", "test whether a buildlet is alive and reachable ", ping)
221223
registerCommand("push", "sync your GOROOT directory to the buildlet", push)
222224
registerCommand("put", "put files on a buildlet", put)

cmd/gomote/login.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// Copyright 2024 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package main
6+
7+
import (
8+
"context"
9+
"flag"
10+
"fmt"
11+
"log"
12+
"os"
13+
"time"
14+
15+
"golang.org/x/build/internal/iapclient"
16+
)
17+
18+
// login triggers the authentication workflow for the gomote service and
19+
// LUCI.
20+
func login(args []string) error {
21+
fs := flag.NewFlagSet("login", flag.ContinueOnError)
22+
fs.Usage = func() {
23+
fmt.Fprintln(os.Stderr, "login usage: gomote login")
24+
fmt.Fprintln(os.Stderr)
25+
fs.PrintDefaults()
26+
os.Exit(1)
27+
}
28+
fs.Parse(args)
29+
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
30+
defer cancel()
31+
log.Print("Authenticating with the gomote service.")
32+
if _, err := iapclient.TokenSourceForceLogin(ctx); err != nil {
33+
fmt.Fprintf(os.Stderr, "unable to authenticate into gomoteserver: %s\n", err)
34+
}
35+
auth := createLUCIAuthenticator(ctx)
36+
log.Print("Authenticating with the LUCI service.")
37+
if err := auth.Login(); err != nil {
38+
fmt.Fprintf(os.Stderr, "unable to authenticate into LUCI: %s\n", err)
39+
}
40+
return nil
41+
}

internal/iapclient/iapclient.go

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,11 @@ type codeResponse struct {
103103
VerificationURL string `json:"verification_url"`
104104
}
105105

106+
const (
107+
configSubDir = "gomote"
108+
tokenFile = "iap-refresh-tv-token"
109+
)
110+
106111
func writeToken(refresh *oauth2.Token) error {
107112
configDir, err := os.UserConfigDir()
108113
if err != nil {
@@ -112,19 +117,30 @@ func writeToken(refresh *oauth2.Token) error {
112117
if err != nil {
113118
return err
114119
}
115-
err = os.MkdirAll(filepath.Join(configDir, "gomote"), 0755)
120+
err = os.MkdirAll(filepath.Join(configDir, configSubDir), 0755)
121+
if err != nil {
122+
return err
123+
}
124+
return os.WriteFile(filepath.Join(configDir, configSubDir, tokenFile), refreshBytes, 0600)
125+
}
126+
127+
func removeToken() error {
128+
configDir, err := os.UserConfigDir()
116129
if err != nil {
117130
return err
118131
}
119-
return os.WriteFile(filepath.Join(configDir, "gomote/iap-refresh-tv-token"), refreshBytes, 0600)
132+
if err := os.Remove(filepath.Join(configDir, configSubDir, tokenFile)); err != nil && !os.IsNotExist(err) {
133+
return err
134+
}
135+
return nil
120136
}
121137

122138
func cachedToken() (*oauth2.Token, error) {
123139
configDir, err := os.UserConfigDir()
124140
if err != nil {
125141
return nil, err
126142
}
127-
refreshBytes, err := os.ReadFile(filepath.Join(configDir, "gomote/iap-refresh-tv-token"))
143+
refreshBytes, err := os.ReadFile(filepath.Join(configDir, configSubDir, tokenFile))
128144
if err != nil {
129145
if os.IsNotExist(err) {
130146
return nil, nil
@@ -141,6 +157,16 @@ func cachedToken() (*oauth2.Token, error) {
141157
return &refreshToken, nil
142158
}
143159

160+
// TokenSource returns a TokenSource that can be used to access Go's
161+
// IAP-protected sites. It will delete any existing authentication token
162+
// credentials and prompt for login.
163+
func TokenSourceForceLogin(ctx context.Context) (oauth2.TokenSource, error) {
164+
if err := removeToken(); err != nil {
165+
return nil, fmt.Errorf("failed to delete existing token file: %s", err)
166+
}
167+
return TokenSource(ctx)
168+
}
169+
144170
// TokenSource returns a TokenSource that can be used to access Go's
145171
// IAP-protected sites. It will prompt for login if necessary.
146172
func TokenSource(ctx context.Context) (oauth2.TokenSource, error) {

0 commit comments

Comments
 (0)