diff options
Diffstat (limited to 'dashboard/cmd')
-rw-r--r-- | dashboard/cmd/buildlet/Makefile | 12 | ||||
-rw-r--r-- | dashboard/cmd/buildlet/buildlet.go | 65 | ||||
-rw-r--r-- | dashboard/cmd/buildlet/stage0/Makefile | 2 | ||||
-rw-r--r-- | dashboard/cmd/coordinator/Makefile | 2 | ||||
-rw-r--r-- | dashboard/cmd/coordinator/coordinator.go | 2 | ||||
-rw-r--r-- | dashboard/cmd/gomote/auth.go | 87 | ||||
-rw-r--r-- | dashboard/cmd/gomote/create.go | 67 | ||||
-rw-r--r-- | dashboard/cmd/gomote/destroy.go | 42 | ||||
-rw-r--r-- | dashboard/cmd/gomote/gomote.go | 105 | ||||
-rw-r--r-- | dashboard/cmd/gomote/list.go | 57 | ||||
-rw-r--r-- | dashboard/cmd/gomote/put.go | 83 | ||||
-rw-r--r-- | dashboard/cmd/gomote/run.go | 42 | ||||
-rw-r--r-- | dashboard/cmd/upload/upload.go | 21 |
13 files changed, 556 insertions, 31 deletions
diff --git a/dashboard/cmd/buildlet/Makefile b/dashboard/cmd/buildlet/Makefile index 833a17c..078a4e9 100644 --- a/dashboard/cmd/buildlet/Makefile +++ b/dashboard/cmd/buildlet/Makefile @@ -3,24 +3,24 @@ buildlet: buildlet.go buildlet.linux-amd64: buildlet.go GOOS=linux GOARCH=amd64 go build -o $@ --tags=extdep - cat $@ | (cd ../upload && go run upload.go --public go-builder-data/$@) + cat $@ | (cd ../upload && go run --tags=extdep upload.go --public go-builder-data/$@) buildlet.openbsd-amd64: buildlet.go GOOS=openbsd GOARCH=amd64 go build -o $@ --tags=extdep - cat $@ | (cd ../upload && go run upload.go --public go-builder-data/$@) + cat $@ | (cd ../upload && go run --tags=extdep upload.go --public go-builder-data/$@) buildlet.plan9-386: buildlet.go GOOS=plan9 GOARCH=386 go build -o $@ --tags=extdep - cat $@ | (cd ../upload && go run upload.go --public go-builder-data/$@) + cat $@ | (cd ../upload && go run --tags=extdep upload.go --public go-builder-data/$@) buildlet.windows-amd64: buildlet.go GOOS=windows GOARCH=amd64 go build -o $@ --tags=extdep - cat $@ | (cd ../upload && go run upload.go --public go-builder-data/$@) + cat $@ | (cd ../upload && go run --tags=extdep upload.go --public go-builder-data/$@) buildlet.darwin-amd64: buildlet.go GOOS=darwin GOARCH=amd64 go build -o $@ --tags=extdep - cat $@ | (cd ../upload && go run upload.go --public go-builder-data/$@) + cat $@ | (cd ../upload && go run --tags=extdep upload.go --public go-builder-data/$@) buildlet.netbsd-amd64: buildlet.go GOOS=netbsd GOARCH=amd64 go build -o $@ --tags=extdep - cat $@ | (cd ../upload && go run upload.go --public go-builder-data/$@) + cat $@ | (cd ../upload && go run --tags=extdep upload.go --public go-builder-data/$@) diff --git a/dashboard/cmd/buildlet/buildlet.go b/dashboard/cmd/buildlet/buildlet.go index 29c60ee..63ec7f4 100644 --- a/dashboard/cmd/buildlet/buildlet.go +++ b/dashboard/cmd/buildlet/buildlet.go @@ -18,6 +18,7 @@ import ( "archive/tar" "compress/gzip" "crypto/tls" + "errors" "flag" "fmt" "io" @@ -37,8 +38,9 @@ import ( ) var ( - scratchDir = flag.String("scratchdir", "", "Temporary directory to use. The contents of this directory may be deleted at any time. If empty, TempDir is used to create one.") - listenAddr = flag.String("listen", defaultListenAddr(), "address to listen on. Warning: this service is inherently insecure and offers no protection of its own. Do not expose this port to the world.") + haltEntireOS = flag.Bool("halt", true, "halt OS in /halt handler. If false, the buildlet process just ends.") + scratchDir = flag.String("scratchdir", "", "Temporary directory to use. The contents of this directory may be deleted at any time. If empty, TempDir is used to create one.") + listenAddr = flag.String("listen", defaultListenAddr(), "address to listen on. Warning: this service is inherently insecure and offers no protection of its own. Do not expose this port to the world.") ) func defaultListenAddr() string { @@ -59,6 +61,8 @@ func defaultListenAddr() string { return ":80" } +var osHalt func() // set by some machines + func main() { flag.Parse() if !metadata.OnGCE() && !strings.HasPrefix(*listenAddr, "localhost:") { @@ -87,8 +91,12 @@ func main() { http.HandleFunc("/", handleRoot) password := metadataValue("password") - http.Handle("/writetgz", requirePassword{http.HandlerFunc(handleWriteTGZ), password}) - http.Handle("/exec", requirePassword{http.HandlerFunc(handleExec), password}) + requireAuth := func(handler func(w http.ResponseWriter, r *http.Request)) http.Handler { + return requirePasswordHandler{http.HandlerFunc(handler), password} + } + http.Handle("/writetgz", requireAuth(handleWriteTGZ)) + http.Handle("/exec", requireAuth(handleExec)) + http.Handle("/halt", requireAuth(handleHalt)) // TODO: removeall tlsCert, tlsKey := metadataValue("tls-cert"), metadataValue("tls-key") @@ -293,6 +301,51 @@ func handleExec(w http.ResponseWriter, r *http.Request) { log.Printf("Run = %s", state) } +func handleHalt(w http.ResponseWriter, r *http.Request) { + if r.Method != "POST" { + http.Error(w, "requires POST method", http.StatusBadRequest) + return + } + log.Printf("Halting in 1 second.") + // do the halt in 1 second, to give the HTTP response time to complete: + time.AfterFunc(1*time.Second, haltMachine) +} + +func haltMachine() { + if !*haltEntireOS { + log.Printf("Ending buildlet process due to halt.") + os.Exit(0) + return + } + log.Printf("Halting machine.") + time.AfterFunc(5*time.Second, func() { os.Exit(0) }) + if osHalt != nil { + // TODO: Windows: http://msdn.microsoft.com/en-us/library/windows/desktop/aa376868%28v=vs.85%29.aspx + osHalt() + os.Exit(0) + } + // Backup mechanism, if exec hangs for any reason: + var err error + switch runtime.GOOS { + case "openbsd": + // Quick, no fs flush, and power down: + err = exec.Command("halt", "-q", "-n", "-p").Run() + case "freebsd": + // Power off (-p), via halt (-o), now. + err = exec.Command("shutdown", "-p", "-o", "now").Run() + case "linux": + // Don't sync (-n), force without shutdown (-f), and power off (-p). + err = exec.Command("/bin/halt", "-n", "-f", "-p").Run() + case "plan9": + err = exec.Command("fshalt").Run() + default: + err = errors.New("No system-specific halt command run; will just end buildlet process.") + } + log.Printf("Shutdown: %v", err) + log.Printf("Ending buildlet process post-halt") + os.Exit(0) +} + // flushWriter is an io.Writer wrapper that writes to w and // Flushes the output immediately, if w is an http.Flusher. type flushWriter struct { @@ -336,12 +389,12 @@ func badRequest(msg string) error { // requirePassword is an http.Handler auth wrapper that enforces a // HTTP Basic password. The username is ignored. -type requirePassword struct { +type requirePasswordHandler struct { h http.Handler password string // empty means no password } -func (h requirePassword) ServeHTTP(w http.ResponseWriter, r *http.Request) { +func (h requirePasswordHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { _, gotPass, _ := r.BasicAuth() if h.password != "" && h.password != gotPass { http.Error(w, "invalid password", http.StatusForbidden) diff --git a/dashboard/cmd/buildlet/stage0/Makefile b/dashboard/cmd/buildlet/stage0/Makefile index b69cacf..bf66be3 100644 --- a/dashboard/cmd/buildlet/stage0/Makefile +++ b/dashboard/cmd/buildlet/stage0/Makefile @@ -1,3 +1,3 @@ buildlet-stage0.windows-amd64: stage0.go GOOS=windows GOARCH=amd64 go build -o $@ --tags=extdep - cat $@ | (cd ../../upload && go run upload.go --public go-builder-data/$@) + cat $@ | (cd ../../upload && go run --tags=extdep upload.go --public go-builder-data/$@) diff --git a/dashboard/cmd/coordinator/Makefile b/dashboard/cmd/coordinator/Makefile index d004fa8..56887c0 100644 --- a/dashboard/cmd/coordinator/Makefile +++ b/dashboard/cmd/coordinator/Makefile @@ -6,4 +6,4 @@ coordinator: coordinator.go # And watch its logs with: # sudo journalctl -f -u gobuild.service upload: coordinator - cat coordinator | (cd ../upload && go run upload.go --public go-builder-data/coordinator) + cat coordinator | (cd ../upload && go run --tags=extdep upload.go --public go-builder-data/coordinator) diff --git a/dashboard/cmd/coordinator/coordinator.go b/dashboard/cmd/coordinator/coordinator.go index e21f7f7..900b848 100644 --- a/dashboard/cmd/coordinator/coordinator.go +++ b/dashboard/cmd/coordinator/coordinator.go @@ -1113,7 +1113,7 @@ func hasComputeScope() bool { return false } for _, v := range scopes { - if v == compute.DevstorageFull_controlScope { + if v == compute.ComputeScope { return true } } diff --git a/dashboard/cmd/gomote/auth.go b/dashboard/cmd/gomote/auth.go new file mode 100644 index 0000000..56ca0d4 --- /dev/null +++ b/dashboard/cmd/gomote/auth.go @@ -0,0 +1,87 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build extdep + +package main + +import ( + "io/ioutil" + "log" + "os" + "path/filepath" + "runtime" + + "golang.org/x/oauth2" + "golang.org/x/tools/dashboard/auth" + "golang.org/x/tools/dashboard/buildlet" + "google.golang.org/api/compute/v1" +) + +func username() string { + if runtime.GOOS == "windows" { + return os.Getenv("USERNAME") + } + return os.Getenv("USER") +} + +func homeDir() string { + if runtime.GOOS == "windows" { + return os.Getenv("HOMEDRIVE") + os.Getenv("HOMEPATH") + } + return os.Getenv("HOME") +} + +func configDir() string { + if runtime.GOOS == "windows" { + return filepath.Join(os.Getenv("APPDATA"), "Gomote") + } + if xdg := os.Getenv("XDG_CONFIG_HOME"); xdg != "" { + return filepath.Join(xdg, "gomote") + } + return filepath.Join(homeDir(), ".config", "gomote") +} + +func projTokenSource() oauth2.TokenSource { + ts, err := auth.ProjectTokenSource(*proj, compute.ComputeScope) + if err != nil { + log.Fatalf("Failed to get OAuth2 token source for project %s: %v", *proj, err) + } + return ts +} + +func userKeyPair() buildlet.KeyPair { + keyDir := configDir() + crtFile := filepath.Join(keyDir, "gomote.crt") + keyFile := filepath.Join(keyDir, "gomote.key") + _, crtErr := os.Stat(crtFile) + _, keyErr := os.Stat(keyFile) + if crtErr == nil && keyErr == nil { + return buildlet.KeyPair{ + CertPEM: slurpString(crtFile), + KeyPEM: slurpString(keyFile), + } + } + check := func(what string, err error) { + if err != nil { + log.Printf("%s: %v", what, err) + } + } + check("making key dir", os.MkdirAll(keyDir, 0700)) + kp, err := buildlet.NewKeyPair() + if err != nil { + log.Fatalf("Error generating new key pair: %v", err) + } + check("writing cert file: ", ioutil.WriteFile(crtFile, []byte(kp.CertPEM), 0600)) + check("writing key file: ", ioutil.WriteFile(keyFile, []byte(kp.KeyPEM), 0600)) + return kp +} + +func slurpString(f string) string { + slurp, err := ioutil.ReadFile(f) + if err != nil { + log.Fatal(err) + } + return string(slurp) +} diff --git a/dashboard/cmd/gomote/create.go b/dashboard/cmd/gomote/create.go new file mode 100644 index 0000000..bb25a8e --- /dev/null +++ b/dashboard/cmd/gomote/create.go @@ -0,0 +1,67 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build extdep + +package main + +import ( + "flag" + "fmt" + "log" + "os" + "sort" + "time" + + "golang.org/x/tools/dashboard" + "golang.org/x/tools/dashboard/buildlet" +) + +func create(args []string) error { + fs := flag.NewFlagSet("create", flag.ContinueOnError) + fs.Usage = func() { + fmt.Fprintln(os.Stderr, "create usage: gomote create [create-opts] <type>\n\n") + fs.PrintDefaults() + os.Exit(1) + } + var timeout time.Duration + fs.DurationVar(&timeout, "timeout", 60*time.Minute, "how long the VM will live before being deleted.") + + fs.Parse(args) + if fs.NArg() != 1 { + fs.Usage() + } + builderType := fs.Arg(0) + conf, ok := dashboard.Builders[builderType] + if !ok || !conf.UsesVM() { + var valid []string + for k, conf := range dashboard.Builders { + if conf.UsesVM() { + valid = append(valid, k) + } + } + sort.Strings(valid) + return fmt.Errorf("Invalid builder type %q. Valid options include: %q", builderType, valid) + } + + instName := fmt.Sprintf("mote-%s-%s", username(), builderType) + client, err := buildlet.StartNewVM(projTokenSource(), instName, builderType, buildlet.VMOpts{ + Zone: *zone, + ProjectID: *proj, + TLS: userKeyPair(), + DeleteIn: timeout, + Description: fmt.Sprintf("gomote buildlet for %s", username()), + OnInstanceRequested: func() { + log.Printf("Sent create request. Waiting for operation.") + }, + OnInstanceCreated: func() { + log.Printf("Instance created.") + }, + }) + if err != nil { + return fmt.Errorf("failed to create VM: %v", err) + } + fmt.Printf("%s\t%s\n", builderType, client.URL()) + return nil +} diff --git a/dashboard/cmd/gomote/destroy.go b/dashboard/cmd/gomote/destroy.go new file mode 100644 index 0000000..ca9b4de --- /dev/null +++ b/dashboard/cmd/gomote/destroy.go @@ -0,0 +1,42 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build extdep + +package main + +import ( + "flag" + "fmt" + "os" + + "golang.org/x/tools/dashboard/buildlet" +) + +func destroy(args []string) error { + fs := flag.NewFlagSet("destroy", flag.ContinueOnError) + fs.Usage = func() { + fmt.Fprintln(os.Stderr, "create usage: gomote destroy <instance>\n\n") + fs.PrintDefaults() + os.Exit(1) + } + + fs.Parse(args) + if fs.NArg() != 1 { + fs.Usage() + } + name := fs.Arg(0) + bc, err := namedClient(name) + if err != nil { + return err + } + + // First ask it to kill itself, and then tell GCE to kill it too: + shutErr := bc.Destroy() + gceErr := buildlet.DestroyVM(projTokenSource(), *proj, *zone, fmt.Sprintf("mote-%s-%s", username(), name)) + if shutErr != nil { + return shutErr + } + return gceErr +} diff --git a/dashboard/cmd/gomote/gomote.go b/dashboard/cmd/gomote/gomote.go new file mode 100644 index 0000000..7ede494 --- /dev/null +++ b/dashboard/cmd/gomote/gomote.go @@ -0,0 +1,105 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build extdep + +/* +The gomote command is a client for the Go builder infrastructure. +It's a remote control for remote Go builder machines. + +Usage: + + gomote [global-flags] cmd [cmd-flags] + + For example, + $ gomote create openbsd-amd64-gce56 + $ gomote push + $ gomote run openbsd-amd64-gce56 src/make.bash + +TODO: document more, and figure out the CLI interface more. +*/ +package main + +import ( + "flag" + "fmt" + "os" + "sort" +) + +var ( + proj = flag.String("project", "symbolic-datum-552", "GCE project owning builders") + zone = flag.String("zone", "us-central1-a", "GCE zone") +) + +type command struct { + name string + des string + run func([]string) error +} + +var commands = map[string]command{} + +func sortedCommands() []string { + s := make([]string, 0, len(commands)) + for name := range commands { + s = append(s, name) + } + sort.Strings(s) + return s +} + +func usage() { + fmt.Fprintf(os.Stderr, `Usage of gomote: gomote [global-flags] <cmd> [cmd-flags] + +Global flags: +`) + flag.PrintDefaults() + fmt.Fprintf(os.Stderr, "Commands:\n\n") + for _, name := range sortedCommands() { + fmt.Fprintf(os.Stderr, " %-10s %s\n", name, commands[name].des) + } + os.Exit(1) +} + +func registerCommand(name, des string, run func([]string) error) { + if _, dup := commands[name]; dup { + panic("duplicate registration of " + name) + } + commands[name] = command{ + name: name, + des: des, + run: run, + } +} + +func registerCommands() { + registerCommand("create", "create a buildlet", create) + registerCommand("destroy", "destroy a buildlet", destroy) + registerCommand("list", "list buildlets", list) + registerCommand("run", "run a command on a buildlet", run) + registerCommand("put", "put files on a buildlet", put) + registerCommand("puttar", "extract a tar.gz to a buildlet", putTar) +} + +func main() { + registerCommands() + flag.Usage = usage + flag.Parse() + args := flag.Args() + if len(args) == 0 { + usage() + } + cmdName := args[0] + cmd, ok := commands[cmdName] + if !ok { + fmt.Fprintf(os.Stderr, "Unknown command %q\n", cmdName) + usage() + } + err := cmd.run(args[1:]) + if err != nil { + fmt.Fprintf(os.Stderr, "Error running %s: %v\n", cmdName, err) + os.Exit(1) + } +} diff --git a/dashboard/cmd/gomote/list.go b/dashboard/cmd/gomote/list.go new file mode 100644 index 0000000..cd3d1f8 --- /dev/null +++ b/dashboard/cmd/gomote/list.go @@ -0,0 +1,57 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build extdep + +package main + +import ( + "flag" + "fmt" + "os" + "strings" + + "golang.org/x/tools/dashboard/buildlet" +) + +func list(args []string) error { + fs := flag.NewFlagSet("list", flag.ContinueOnError) + fs.Usage = func() { + fmt.Fprintln(os.Stderr, "list usage: gomote list\n\n") + fs.PrintDefaults() + os.Exit(1) + } + fs.Parse(args) + if fs.NArg() != 0 { + fs.Usage() + } + + prefix := fmt.Sprintf("mote-%s-", username()) + vms, err := buildlet.ListVMs(projTokenSource(), *proj, *zone) + if err != nil { + return fmt.Errorf("failed to list VMs: %v", err) + } + for _, vm := range vms { + if !strings.HasPrefix(vm.Name, prefix) { + continue + } + fmt.Printf("%s\thttps://%s\n", vm.Type, strings.TrimSuffix(vm.IPPort, ":443")) + } + return nil +} + +func namedClient(name string) (*buildlet.Client, error) { + // TODO(bradfitz): cache the list on disk and avoid the API call? + vms, err := buildlet.ListVMs(projTokenSource(), *proj, *zone) + if err != nil { + return nil, fmt.Errorf("error listing VMs while looking up %q: %v", name, err) + } + wantName := fmt.Sprintf("mote-%s-%s", username(), name) + for _, vm := range vms { + if vm.Name == wantName { + return buildlet.NewClient(vm.IPPort, vm.TLS), nil + } + } + return nil, fmt.Errorf("buildlet %q not running", name) +} diff --git a/dashboard/cmd/gomote/put.go b/dashboard/cmd/gomote/put.go new file mode 100644 index 0000000..31595c2 --- /dev/null +++ b/dashboard/cmd/gomote/put.go @@ -0,0 +1,83 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build extdep + +package main + +import ( + "flag" + "fmt" + "io" + "net/http" + "os" +) + +// put a .tar.gz +func putTar(args []string) error { + fs := flag.NewFlagSet("put", flag.ContinueOnError) + fs.Usage = func() { + fmt.Fprintln(os.Stderr, "create usage: gomote puttar [put-opts] <buildlet-name> [tar.gz file or '-' for stdin]\n") + fs.PrintDefaults() + os.Exit(1) + } + var rev string + fs.StringVar(&rev, "gorev", "", "If non-empty, git hash to download from gerrit and put to the buildlet. e.g. 886b02d705ff for Go 1.4.1") + + fs.Parse(args) + if fs.NArg() < 1 || fs.NArg() > 2 { + fs.Usage() + } + + name := fs.Arg(0) + bc, err := namedClient(name) + if err != nil { + return err + } + + var tgz io.Reader = os.Stdin + if rev != "" { + if fs.NArg() != 1 { + fs.Usage() + } + // TODO(bradfitz): tell the buildlet to do this + // itself, to avoid network to & from home networks. + // Staying Google<->Google will be much faster. + res, err := http.Get("https://go.googlesource.com/go/+archive/" + rev + ".tar.gz") + if err != nil { + return fmt.Errorf("Error fetching rev %s from Gerrit: %v", rev, err) + } + defer res.Body.Close() + if res.StatusCode != 200 { + return fmt.Errorf("Error fetching rev %s from Gerrit: %v", rev, res.Status) + } + tgz = res.Body + } else if fs.NArg() == 2 && fs.Arg(1) != "-" { + f, err := os.Open(fs.Arg(1)) + if err != nil { + return err + } + defer f.Close() + tgz = f + } + return bc.PutTarball(tgz) +} + +// put single files +func put(args []string) error { + fs := flag.NewFlagSet("put", flag.ContinueOnError) + fs.Usage = func() { + fmt.Fprintln(os.Stderr, "create usage: gomote put [put-opts] <type>\n\n") + fs.PrintDefaults() + os.Exit(1) + } + fs.Parse(args) + if fs.NArg() != 1 { + fs.Usage() + } + return fmt.Errorf("TODO") + builderType := fs.Arg(0) + _ = builderType + return nil +} diff --git a/dashboard/cmd/gomote/run.go b/dashboard/cmd/gomote/run.go new file mode 100644 index 0000000..6be9346 --- /dev/null +++ b/dashboard/cmd/gomote/run.go @@ -0,0 +1,42 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build extdep + +package main + +import ( + "flag" + "fmt" + "os" + + "golang.org/x/tools/dashboard/buildlet" +) + +func run(args []string) error { + fs := flag.NewFlagSet("run", flag.ContinueOnError) + fs.Usage = func() { + fmt.Fprintln(os.Stderr, "create usage: gomote run [run-opts] <buildlet-name> <cmd> [args...]") + fs.PrintDefaults() + os.Exit(1) + } + + fs.Parse(args) + if fs.NArg() < 2 { + fs.Usage() + } + name, cmd := fs.Arg(0), fs.Arg(1) + bc, err := namedClient(name) + if err != nil { + return err + } + + remoteErr, execErr := bc.Exec(cmd, buildlet.ExecOpts{ + Output: os.Stdout, + }) + if execErr != nil { + return fmt.Errorf("Error trying to execute %s: %v", cmd, execErr) + } + return remoteErr +} diff --git a/dashboard/cmd/upload/upload.go b/dashboard/cmd/upload/upload.go index 880b879..087be49 100644 --- a/dashboard/cmd/upload/upload.go +++ b/dashboard/cmd/upload/upload.go @@ -15,15 +15,13 @@ import ( "flag" "fmt" "io" - "io/ioutil" "log" "net/http" "os" - "path/filepath" "strings" "golang.org/x/oauth2" - "golang.org/x/oauth2/google" + "golang.org/x/tools/dashboard/auth" "google.golang.org/cloud" "google.golang.org/cloud/storage" ) @@ -111,18 +109,9 @@ var bucketProject = map[string]string{ } func tokenSource(bucket string) (oauth2.TokenSource, error) { - proj := bucketProject[bucket] - fileName := filepath.Join(os.Getenv("HOME"), "keys", proj+".key.json") - jsonConf, err := ioutil.ReadFile(fileName) - if err != nil { - if os.IsNotExist(err) { - return nil, fmt.Errorf("Missing JSON key configuration. Download the Service Account JSON key from https://console.developers.google.com/project/%s/apiui/credential and place it at %s", proj, fileName) - } - return nil, err - } - conf, err := google.JWTConfigFromJSON(jsonConf, storage.ScopeReadWrite) - if err != nil { - return nil, fmt.Errorf("reading JSON config from %s: %v", fileName, err) + proj, ok := bucketProject[bucket] + if !ok { + return nil, fmt.Errorf("unknown project for bucket %q", bucket) } - return conf.TokenSource(oauth2.NoContext), nil + return auth.ProjectTokenSource(proj, storage.ScopeReadWrite) } |