cmd/gomote: consistently support a direct-to-buildlet mode, bypassing coordinator
For testing new builder images, this adds support to gomote to connect
to a buildlet directly, without going via the coordinator. If the
builder name contains a '@' character, the name is expected to be of
the form <build-config-name>@ip[:port].
Also update the gomote run -path docs while I'm here, since I always
forget the magic expansions (which at least are documentd in the
buildlet godoc). Copy them to the flags doc.
Change-Id: I50227855897106e1cc60c1881700866d5fddf2a5
Reviewed-on: https://go-review.googlesource.com/38775
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
diff --git a/cmd/gomote/destroy.go b/cmd/gomote/destroy.go
index 9fbc016..77d7110 100644
--- a/cmd/gomote/destroy.go
+++ b/cmd/gomote/destroy.go
@@ -23,7 +23,7 @@
fs.Usage()
}
name := fs.Arg(0)
- bc, err := namedClient(name)
+ bc, _, err := clientAndConf(name)
if err != nil {
return err
}
diff --git a/cmd/gomote/get.go b/cmd/gomote/get.go
index b514fda..576b618 100644
--- a/cmd/gomote/get.go
+++ b/cmd/gomote/get.go
@@ -29,7 +29,7 @@
}
name := fs.Arg(0)
- bc, err := namedClient(name)
+ bc, _, err := clientAndConf(name)
if err != nil {
return err
}
diff --git a/cmd/gomote/gomote.go b/cmd/gomote/gomote.go
index 567abc3..c7996a6 100644
--- a/cmd/gomote/gomote.go
+++ b/cmd/gomote/gomote.go
@@ -6,6 +6,8 @@
The gomote command is a client for the Go builder infrastructure.
It's a remote control for remote Go builder machines.
+See https://golang.org/wiki/Gomote
+
Usage:
gomote [global-flags] cmd [cmd-flags]
@@ -15,8 +17,68 @@
user-username-openbsd-amd64-60-0
$ gomote push user-username-openbsd-amd64-60-0
$ gomote run user-username-openbsd-amd64-60-0 go/src/make.bash
+ $ gomote run user-username-openbsd-amd64-60-0 go/bin/go test -v -short os
-TODO: document more, and figure out the CLI interface more.
+To list the subcommands, run "gomote" without arguments:
+
+ Commands:
+
+ create create a buildlet
+ destroy destroy a buildlet
+ gettar extract a tar.gz from a buildlet
+ list list buildlets
+ ls list the contents of a directory on a buildlet
+ ping test whether a buildlet is alive and reachable
+ push sync the repo of your pwd to the buildlet
+ put put files on a buildlet
+ put14 put Go 1.4 in place
+ puttar extract a tar.gz to a buildlet
+ rm delete files or directories
+ run run a command on a buildlet
+
+To list all the builder types available, run "create" with no arguments:
+
+ $ gomote create
+ (tons of builder types)
+
+The "gomote run" command has many of its own flags:
+
+ $ gomote run -h
+ create usage: gomote run [run-opts] <instance> <cmd> [args...]
+ -builderenv string
+ Optional alternate builder to act like. Must share the same
+ underlying buildlet host type, or it's an error. For
+ instance, linux-amd64-race or linux-386-387 are compatible
+ with linux-amd64, but openbsd-amd64 and openbsd-386 are
+ different hosts.
+ -debug
+ write debug info about the command's execution before it begins
+ -dir string
+ Directory to run from. Defaults to the directory of the
+ command, or the work directory if -system is true.
+ -e value
+ Environment variable KEY=value. The -e flag may be repeated
+ multiple times to add multiple things to the environment.
+ -path string
+ Comma-separated list of ExecOpts.Path elements. The special
+ string 'EMPTY' means to run without any $PATH. The empty
+ string (default) does not modify the $PATH. Otherwise, the
+ following expansions apply: the string '$PATH' expands to
+ the current PATH element(s), the substring '$WORKDIR'
+ expands to the buildlet's temp workdir.
+ -system
+ run inside the system, and not inside the workdir; this is implicit if cmd starts with '/'
+
+Debugging buildlets directly
+
+Using "gomote create" contacts the build coordinator
+(farmer.golang.org) and requests that it create the buildlet on your
+behalf. All subsequent commands (such as "gomote run" or "gomote ls")
+then proxy your request via the coordinator. To access a buildlet
+directly (for example, when working on the buildlet code), you can
+skip the "gomote create" step and use the special builder name
+"<build-config-name>@ip[:port>", such as "windows-amd64-gce@10.1.5.3".
+
*/
package main
diff --git a/cmd/gomote/list.go b/cmd/gomote/list.go
index 83b1cd1..3b00aec 100644
--- a/cmd/gomote/list.go
+++ b/cmd/gomote/list.go
@@ -43,7 +43,36 @@
return nil
}
+// clientAndConfig returns a buildlet.Client and its build config for
+// a named remote buildlet (a buildlet connection owned by the build
+// coordinator).
+//
+// As a special case, if name contains '@', the name is expected to be
+// of the form <build-config-name>@ip[:port]. For example,
+// "windows-amd64-race@10.0.0.1".
func clientAndConf(name string) (bc *buildlet.Client, conf dashboard.BuildConfig, err error) {
+ var ok bool
+
+ if strings.Contains(name, "@") {
+ f := strings.SplitN(name, "@", 2)
+ if len(f) != 2 {
+ err = fmt.Errorf("unsupported name %q; for @ form expect <build-config-name>@host[:port]")
+ return
+ }
+ builderType := f[0]
+ conf, ok = dashboard.Builders[builderType]
+ if !ok {
+ err = fmt.Errorf("unknown builder type %q", name, builderType)
+ return
+ }
+ ipPort := f[1]
+ if !strings.Contains(ipPort, ":") {
+ ipPort += ":80"
+ }
+ bc = buildlet.NewClient(ipPort, buildlet.NoKeyPair)
+ return
+ }
+
cc, err := buildlet.NewCoordinatorClientFromFlags()
if err != nil {
return
@@ -53,7 +82,6 @@
if err != nil {
return
}
- var ok bool
for _, rb := range rbs {
if rb.Name == name {
conf, ok = dashboard.Builders[rb.BuilderType]
@@ -69,17 +97,9 @@
return
}
- bc, err = namedClient(name)
- return
-}
-
-func namedClient(name string) (*buildlet.Client, error) {
- if strings.Contains(name, ":") {
- return buildlet.NewClient(name, buildlet.NoKeyPair), nil
- }
- cc, err := buildlet.NewCoordinatorClientFromFlags()
+ bc, err = cc.NamedBuildlet(name)
if err != nil {
- return nil, err
+ return
}
- return cc.NamedBuildlet(name)
+ return bc, conf, nil
}
diff --git a/cmd/gomote/ls.go b/cmd/gomote/ls.go
index ca237be..8386d62 100644
--- a/cmd/gomote/ls.go
+++ b/cmd/gomote/ls.go
@@ -35,7 +35,7 @@
dir = fs.Arg(1)
}
name := fs.Arg(0)
- bc, err := namedClient(name)
+ bc, _, err := clientAndConf(name)
if err != nil {
return err
}
diff --git a/cmd/gomote/ping.go b/cmd/gomote/ping.go
index 4de73a8..4c9e0cc 100644
--- a/cmd/gomote/ping.go
+++ b/cmd/gomote/ping.go
@@ -23,7 +23,7 @@
fs.Usage()
}
name := fs.Arg(0)
- bc, err := namedClient(name)
+ bc, _, err := clientAndConf(name)
if err != nil {
return err
}
diff --git a/cmd/gomote/put.go b/cmd/gomote/put.go
index b4461d3..fcaacb8 100644
--- a/cmd/gomote/put.go
+++ b/cmd/gomote/put.go
@@ -46,7 +46,7 @@
}
name := fs.Arg(0)
- bc, err := namedClient(name)
+ bc, _, err := clientAndConf(name)
if err != nil {
return err
}
@@ -125,7 +125,7 @@
fs.Usage()
}
- bc, err := namedClient(fs.Arg(0))
+ bc, _, err := clientAndConf(fs.Arg(0))
if err != nil {
return err
}
diff --git a/cmd/gomote/rm.go b/cmd/gomote/rm.go
index c8a206c..93e4d0d 100644
--- a/cmd/gomote/rm.go
+++ b/cmd/gomote/rm.go
@@ -25,7 +25,7 @@
}
name := fs.Arg(0)
args = fs.Args()[1:]
- bc, err := namedClient(name)
+ bc, _, err := clientAndConf(name)
if err != nil {
return err
}
diff --git a/cmd/gomote/run.go b/cmd/gomote/run.go
index 197d877..d110dc1 100644
--- a/cmd/gomote/run.go
+++ b/cmd/gomote/run.go
@@ -29,7 +29,8 @@
var env stringSlice
fs.Var(&env, "e", "Environment variable KEY=value. The -e flag may be repeated multiple times to add multiple things to the environment.")
var path string
- fs.StringVar(&path, "path", "", "Comma-separated list of ExecOpts.Path elements. The special string 'EMPTY' means to run without any $PATH. The empty string (default) does not modify the $PATH.")
+ fs.StringVar(&path, "path", "", "Comma-separated list of ExecOpts.Path elements. The special string 'EMPTY' means to run without any $PATH. The empty string (default) does not modify the $PATH. Otherwise, the following expansions apply: the string '$PATH' expands to the current PATH element(s), the substring '$WORKDIR' expands to the buildlet's temp workdir.")
+
var dir string
fs.StringVar(&dir, "dir", "", "Directory to run from. Defaults to the directory of the command, or the work directory if -system is true.")
var builderEnv string