1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586 |
- package container
- import (
- "bytes"
- "context"
- "github.com/docker/docker/api/types"
- "github.com/docker/docker/client"
- "github.com/docker/docker/pkg/stdcopy"
- )
- // ExecResult represents a result returned from Exec()
- type ExecResult struct {
- ExitCode int
- outBuffer *bytes.Buffer
- errBuffer *bytes.Buffer
- }
- // Stdout returns stdout output of a command run by Exec()
- func (res *ExecResult) Stdout() string {
- return res.outBuffer.String()
- }
- // Stderr returns stderr output of a command run by Exec()
- func (res *ExecResult) Stderr() string {
- return res.errBuffer.String()
- }
- // Combined returns combined stdout and stderr output of a command run by Exec()
- func (res *ExecResult) Combined() string {
- return res.outBuffer.String() + res.errBuffer.String()
- }
- // Exec executes a command inside a container, returning the result
- // containing stdout, stderr, and exit code. Note:
- // - this is a synchronous operation;
- // - cmd stdin is closed.
- func Exec(ctx context.Context, cli client.APIClient, id string, cmd []string) (ExecResult, error) {
- // prepare exec
- execConfig := types.ExecConfig{
- AttachStdout: true,
- AttachStderr: true,
- Cmd: cmd,
- }
- cresp, err := cli.ContainerExecCreate(ctx, id, execConfig)
- if err != nil {
- return ExecResult{}, err
- }
- execID := cresp.ID
- // run it, with stdout/stderr attached
- aresp, err := cli.ContainerExecAttach(ctx, execID, types.ExecStartCheck{})
- if err != nil {
- return ExecResult{}, err
- }
- defer aresp.Close()
- // read the output
- var outBuf, errBuf bytes.Buffer
- outputDone := make(chan error, 1)
- go func() {
- // StdCopy demultiplexes the stream into two buffers
- _, err = stdcopy.StdCopy(&outBuf, &errBuf, aresp.Reader)
- outputDone <- err
- }()
- select {
- case err := <-outputDone:
- if err != nil {
- return ExecResult{}, err
- }
- break
- case <-ctx.Done():
- return ExecResult{}, ctx.Err()
- }
- // get the exit code
- iresp, err := cli.ContainerExecInspect(ctx, execID)
- if err != nil {
- return ExecResult{}, err
- }
- return ExecResult{ExitCode: iresp.ExitCode, outBuffer: &outBuf, errBuffer: &errBuf}, nil
- }
|