forked from docker/buildx
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request docker#2112 from cpuguy83/dialstdio
Add dial-stdio command
- Loading branch information
Showing
12 changed files
with
460 additions
and
26 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
package build | ||
|
||
import ( | ||
"context" | ||
stderrors "errors" | ||
"net" | ||
|
||
"github.com/containerd/containerd/platforms" | ||
"github.com/docker/buildx/builder" | ||
"github.com/docker/buildx/util/progress" | ||
v1 "github.com/opencontainers/image-spec/specs-go/v1" | ||
"github.com/pkg/errors" | ||
) | ||
|
||
func Dial(ctx context.Context, nodes []builder.Node, pw progress.Writer, platform *v1.Platform) (net.Conn, error) { | ||
nodes, err := filterAvailableNodes(nodes) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
if len(nodes) == 0 { | ||
return nil, errors.New("no nodes available") | ||
} | ||
|
||
var pls []v1.Platform | ||
if platform != nil { | ||
pls = []v1.Platform{*platform} | ||
} | ||
|
||
opts := map[string]Options{"default": {Platforms: pls}} | ||
resolved, err := resolveDrivers(ctx, nodes, opts, pw) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
var dialError error | ||
for _, ls := range resolved { | ||
for _, rn := range ls { | ||
if platform != nil { | ||
p := *platform | ||
var found bool | ||
for _, pp := range rn.platforms { | ||
if platforms.Only(p).Match(pp) { | ||
found = true | ||
break | ||
} | ||
} | ||
if !found { | ||
continue | ||
} | ||
} | ||
|
||
conn, err := nodes[rn.driverIndex].Driver.Dial(ctx) | ||
if err == nil { | ||
return conn, nil | ||
} | ||
dialError = stderrors.Join(err) | ||
} | ||
} | ||
|
||
return nil, errors.Wrap(dialError, "no nodes available") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
package commands | ||
|
||
import ( | ||
"io" | ||
"net" | ||
"os" | ||
|
||
"github.com/containerd/containerd/platforms" | ||
"github.com/docker/buildx/build" | ||
"github.com/docker/buildx/builder" | ||
"github.com/docker/buildx/util/progress" | ||
"github.com/docker/cli/cli/command" | ||
"github.com/moby/buildkit/util/appcontext" | ||
"github.com/moby/buildkit/util/progress/progressui" | ||
v1 "github.com/opencontainers/image-spec/specs-go/v1" | ||
"github.com/pkg/errors" | ||
"github.com/spf13/cobra" | ||
"golang.org/x/sync/errgroup" | ||
) | ||
|
||
type stdioOptions struct { | ||
builder string | ||
platform string | ||
progress string | ||
} | ||
|
||
func runDialStdio(dockerCli command.Cli, opts stdioOptions) error { | ||
ctx := appcontext.Context() | ||
|
||
contextPathHash, _ := os.Getwd() | ||
b, err := builder.New(dockerCli, | ||
builder.WithName(opts.builder), | ||
builder.WithContextPathHash(contextPathHash), | ||
) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
if err = updateLastActivity(dockerCli, b.NodeGroup); err != nil { | ||
return errors.Wrapf(err, "failed to update builder last activity time") | ||
} | ||
nodes, err := b.LoadNodes(ctx) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
printer, err := progress.NewPrinter(ctx, os.Stderr, progressui.DisplayMode(opts.progress), progress.WithPhase("dial-stdio"), progress.WithDesc("builder: "+b.Name, "builder:"+b.Name)) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
var p *v1.Platform | ||
if opts.platform != "" { | ||
pp, err := platforms.Parse(opts.platform) | ||
if err != nil { | ||
return errors.Wrapf(err, "invalid platform %q", opts.platform) | ||
} | ||
p = &pp | ||
} | ||
|
||
defer printer.Wait() | ||
|
||
return progress.Wrap("Proxying to builder", printer.Write, func(sub progress.SubLogger) error { | ||
var conn net.Conn | ||
|
||
err := sub.Wrap("Dialing builder", func() error { | ||
conn, err = build.Dial(ctx, nodes, printer, p) | ||
if err != nil { | ||
return err | ||
} | ||
return nil | ||
}) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
defer conn.Close() | ||
|
||
go func() { | ||
<-ctx.Done() | ||
closeWrite(conn) | ||
}() | ||
|
||
var eg errgroup.Group | ||
|
||
eg.Go(func() error { | ||
_, err := io.Copy(conn, os.Stdin) | ||
closeWrite(conn) | ||
return err | ||
}) | ||
eg.Go(func() error { | ||
_, err := io.Copy(os.Stdout, conn) | ||
closeRead(conn) | ||
return err | ||
}) | ||
return eg.Wait() | ||
}) | ||
} | ||
|
||
func closeRead(conn net.Conn) error { | ||
if c, ok := conn.(interface{ CloseRead() error }); ok { | ||
return c.CloseRead() | ||
} | ||
return conn.Close() | ||
} | ||
|
||
func closeWrite(conn net.Conn) error { | ||
if c, ok := conn.(interface{ CloseWrite() error }); ok { | ||
return c.CloseWrite() | ||
} | ||
return conn.Close() | ||
} | ||
|
||
func dialStdioCmd(dockerCli command.Cli, rootOpts *rootOptions) *cobra.Command { | ||
opts := stdioOptions{} | ||
|
||
cmd := &cobra.Command{ | ||
Use: "dial-stdio", | ||
Short: "Proxy current stdio streams to builder instance", | ||
Args: cobra.NoArgs, | ||
RunE: func(cmd *cobra.Command, args []string) error { | ||
opts.builder = rootOpts.builder | ||
return runDialStdio(dockerCli, opts) | ||
}, | ||
} | ||
|
||
flags := cmd.Flags() | ||
cmd.Flags() | ||
flags.StringVar(&opts.platform, "platform", os.Getenv("DOCKER_DEFAULT_PLATFORM"), "Target platform: this is used for node selection") | ||
flags.StringVar(&opts.progress, "progress", "quiet", "Set type of progress output (auto, plain, tty).") | ||
return cmd | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
# docker buildx dial-stdio | ||
|
||
<!---MARKER_GEN_START--> | ||
Proxy current stdio streams to builder instance | ||
|
||
### Options | ||
|
||
| Name | Type | Default | Description | | ||
|:-------------|:---------|:--------|:-------------------------------------------------| | ||
| `--builder` | `string` | | Override the configured builder instance | | ||
| `--platform` | `string` | | Target platform: this is used for node selection | | ||
| `--progress` | `string` | `quiet` | Set type of progress output (auto, plain, tty). | | ||
|
||
|
||
<!---MARKER_GEN_END--> | ||
|
||
## Description | ||
|
||
dial-stdio uses the stdin and stdout streams of the command to proxy to the configured builder instance. | ||
It is not intended to be used by humans, but rather by other tools that want to interact with the builder instance via BuildKit API. | ||
|
||
## Examples | ||
|
||
Example go program that uses the dial-stdio command wire up a buildkit client. | ||
This is for example use only and may not be suitable for production use. | ||
|
||
```go | ||
client.New(ctx, "", client.WithContextDialer(func(context.Context, string) (net.Conn, error) { | ||
c1, c2 := net.Pipe() | ||
cmd := exec.Command("docker", "buildx", "dial-stdio") | ||
cmd.Stdin = c1 | ||
cmd.Stdout = c1 | ||
|
||
if err := cmd.Start(); err != nil { | ||
c1.Close() | ||
c2.Close() | ||
return nil, err | ||
} | ||
|
||
go func() { | ||
cmd.Wait() | ||
c2.Close() | ||
}() | ||
|
||
return c2 | ||
})) | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.